Câu trả lời:
Câu trả lời của Ber - lưu trữ nó trong threadlocals - là một ý kiến rất tồi. Hoàn toàn không có lý do gì để làm theo cách này.
Một cách tốt hơn nhiều là ghi đè phương thức của biểu mẫu __init__
để lấy một đối số từ khóa bổ sung request
,. Điều này lưu trữ yêu cầu trong biểu mẫu , nơi yêu cầu và từ đó bạn có thể truy cập yêu cầu đó trong phương pháp sạch của mình.
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self.request ...
và theo quan điểm của bạn:
myform = MyForm(request.POST, request=request)
CẬP NHẬT 25/10/2011 : Tôi hiện đang sử dụng điều này với một lớp được tạo động thay vì phương thức, vì Django 1.3 hiển thị một số điều kỳ lạ.
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
class ModelFormWithRequest(ModelForm):
def __new__(cls, *args, **kwargs):
kwargs['request'] = request
return ModelForm(*args, **kwargs)
return ModelFormWithRequest
Sau đó ghi đè MyCustomForm.__init__
như sau:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Sau đó, bạn có thể truy cập đối tượng yêu cầu từ bất kỳ phương thức nào của ModelForm
with self.request
.
__new__
kwargs của nó, sau này sẽ được chuyển đến __init__
phương thức của lớp . Đặt tên cho lớp ModelFormWithRequest
tôi nghĩ rõ ràng hơn nhiều về ý nghĩa của nó hơn ModelFormMetaClass
.
Đối với những gì nó đáng giá, nếu bạn đang sử dụng Chế độ xem dựa trên lớp , thay vì chế độ xem dựa trên chức năng, hãy ghi đè get_form_kwargs
trong chế độ xem chỉnh sửa của bạn. Mã mẫu cho một CreateView tùy chỉnh :
from braces.views import LoginRequiredMixin
class MyModelCreateView(LoginRequiredMixin, CreateView):
template_name = 'example/create.html'
model = MyModel
form_class = MyModelForm
success_message = "%(my_object)s added to your site."
def get_form_kwargs(self):
kw = super(MyModelCreateView, self).get_form_kwargs()
kw['request'] = self.request # the trick!
return kw
def form_valid(self):
# do something
Mã chế độ xem ở trên sẽ request
sẵn dùng làm một trong các đối số từ khóa cho hàm khởi tạo của biểu mẫu __init__
. Do đó trong việc của bạn ModelForm
:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
# important to "pop" added kwarg before call to parent's constructor
self.request = kwargs.pop('request')
super(MyModelForm, self).__init__(*args, **kwargs)
request
đối tượng trong get_form_kwargs
tự động hay không.
self.get_object
không? Các CreateView
mở rộng SingleObjectMixin
. Nhưng điều này có hiệu quả hay tăng một ngoại lệ hay không phụ thuộc vào việc bạn đang tạo một đối tượng mới hay cập nhật một đối tượng hiện có; tức là kiểm tra cả hai trường hợp (và xóa tất nhiên).
Aproach thông thường là lưu trữ đối tượng yêu cầu trong một tham chiếu cục bộ luồng sử dụng phần mềm trung gian. Sau đó, bạn có thể truy cập điều này từ bất kỳ đâu trong ứng dụng của mình, bao gồm cả phương thức Form.clean ().
Thay đổi chữ ký của phương thức Form.clean () có nghĩa là bạn có phiên bản Django đã sửa đổi, sở hữu của bạn, phiên bản này có thể không phải là những gì bạn muốn.
Cảm ơn số lượng phần mềm trung gian trông giống như sau:
import threading
_thread_locals = threading.local()
def get_current_request():
return getattr(_thread_locals, 'request', None)
class ThreadLocals(object):
"""
Middleware that gets various objects from the
request object and saves them in thread local storage.
"""
def process_request(self, request):
_thread_locals.request = request
Đăng ký phần mềm trung gian này như được mô tả trong tài liệu Django
**kwargs
, có nghĩa là bạn sẽ phải chuyển đối tượng yêu cầu là MyForm(request.POST, request=request)
.
Đối với quản trị viên Django, trong Django 1.8
class MyModelAdmin(admin.ModelAdmin):
...
form = RedirectForm
def get_form(self, request, obj=None, **kwargs):
form = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
form.request = request
return form
Tôi đã gặp phải vấn đề cụ thể này khi tùy chỉnh quản trị viên. Tôi muốn một trường nhất định được xác thực dựa trên thông tin đăng nhập của quản trị viên cụ thể.
Vì tôi không muốn sửa đổi dạng xem để chuyển yêu cầu làm đối số cho biểu mẫu, nên sau đây là những gì tôi đã làm:
class MyCustomForm(forms.ModelForm):
class Meta:
model = MyModel
def clean(self):
# make use of self.request here
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
def form_wrapper(*args, **kwargs):
a = ModelForm(*args, **kwargs)
a.request = request
return a
return form_wrapper
obj=obj
không obj=None
trên dòng 11.
'function' object has no attribute 'base_fields'
. Tuy nhiên, câu trả lời @ François đơn giản hơn (không đóng) hoạt động trơn tru.
Bạn không phải lúc nào cũng sử dụng phương pháp này (và có thể là phương pháp không tốt của nó), nhưng nếu bạn chỉ sử dụng biểu mẫu trong một dạng xem, bạn có thể đưa nó vào bên trong chính phương thức xem.
def my_view(request):
class ResetForm(forms.Form):
password = forms.CharField(required=True, widget=forms.PasswordInput())
def clean_password(self):
data = self.cleaned_data['password']
if not request.user.check_password(data):
raise forms.ValidationError("The password entered does not match your account password.")
return data
if request.method == 'POST':
form = ResetForm(request.POST, request.FILES)
if form.is_valid():
return HttpResponseRedirect("/")
else:
form = ResetForm()
return render_to_response(request, "reset.html")
get_form_class
phương pháp CBV , nếu tôi biết mình cần phải làm nhiều thứ với yêu cầu. Có thể có một số chi phí trong việc liên tục tạo lớp, nhưng điều đó chỉ chuyển nó từ thời gian nhập sang thời gian chạy.
Câu trả lời của Daniel Roseman vẫn là tốt nhất. Tuy nhiên, tôi sẽ sử dụng đối số vị trí đầu tiên cho yêu cầu thay vì đối số từ khóa vì một vài lý do:
Cuối cùng, tôi sẽ sử dụng một tên độc đáo hơn để tránh ghi đè một biến hiện có. Do đó, câu trả lời đã sửa đổi của tôi trông giống như:
class MyForm(forms.Form):
def __init__(self, request, *args, **kwargs):
self._my_request = request
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self._my_request ...
pho mát tươi từ cheesebaker @ pypi: django-requestprovider
Tôi có một câu trả lời khác cho câu hỏi này theo yêu cầu của bạn, bạn muốn truy cập người dùng vào phương thức sạch của biểu mẫu. Bạn có thể thử điều này. View.py
person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)
form.py
def __init__(self,*arg,**kwargs):
self.instance=kwargs.get('instance',None)
if kwargs['instance'] is not None:
del kwargs['instance']
super(Myform, self).__init__(*args, **kwargs)
Bây giờ bạn có thể truy cập self.instance bằng bất kỳ phương pháp rõ ràng nào trong form.py
Khi bạn muốn truy cập nó thông qua các khung nhìn lớp Django "đã chuẩn bị" giống như CreateView
có một mẹo nhỏ cần biết (= giải pháp chính thức không hoạt động ngoài hộp). Riêng bạn, CreateView
bạn sẽ phải thêm mã như sau:
class MyCreateView(LoginRequiredMixin, CreateView):
form_class = MyOwnForm
template_name = 'my_sample_create.html'
def get_form_kwargs(self):
result = super().get_form_kwargs()
result['request'] = self.request
return result
= trong ngắn hạn, đây là giải pháp để chuyển request
đến biểu mẫu của bạn với các chế độ xem Tạo / Cập nhật của Django.