ฉันพยายาม request.user สำหรับเมธอด clean ของฟอร์ม แต่ฉันจะเข้าถึงอ็อบเจ็กต์การร้องขอได้อย่างไร ฉันสามารถแก้ไขเมธอด clean เพื่ออนุญาตให้ใส่ตัวแปรได้หรือไม่
ฉันพยายาม request.user สำหรับเมธอด clean ของฟอร์ม แต่ฉันจะเข้าถึงอ็อบเจ็กต์การร้องขอได้อย่างไร ฉันสามารถแก้ไขเมธอด clean เพื่ออนุญาตให้ใส่ตัวแปรได้หรือไม่
คำตอบ:
คำตอบโดย Ber - เก็บไว้ใน threadlocals - เป็นความคิดที่แย่มาก ไม่มีเหตุผลที่จะทำเช่นนี้
วิธีที่ดีมากคือการแทนที่รูปแบบของวิธีการที่จะใช้ข้อโต้แย้งคำหลักพิเศษ__init__
request
ซึ่งจะจัดเก็บคำขอในรูปแบบที่จำเป็นและจากที่ที่คุณสามารถเข้าถึงได้ด้วยวิธีการที่สะอาด
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 ...
และในมุมมองของคุณ:
myform = MyForm(request.POST, request=request)
อัปเดต 10/25/2011 : ตอนนี้ฉันใช้สิ่งนี้กับคลาสที่สร้างขึ้นแบบไดนามิกแทนวิธีการเนื่องจาก Django 1.3 แสดงความแปลกประหลาดบางอย่างเป็นอย่างอื่น
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
จากนั้นลบล้างMyCustomForm.__init__
ดังนี้:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
จากนั้นคุณสามารถเข้าถึงวัตถุคำขอจากวิธีการใด ๆกับModelForm
self.request
__new__
kwargs ซึ่งหลังจากนั้นจะถูกส่งไปยัง__init__
เมธอดของคลาส การตั้งชื่อชั้นเรียนผมคิดว่าชัดเจนมากขึ้นในความหมายของมันมากกว่าModelFormWithRequest
ModelFormMetaClass
สิ่งที่คุ้มค่าหากคุณใช้มุมมองตามคลาสแทนที่จะเป็นมุมมองตามฟังก์ชันจะแทนที่get_form_kwargs
ในมุมมองการแก้ไขของคุณ ตัวอย่างโค้ดสำหรับCreateViewแบบกำหนดเอง:
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
โค้ดมุมมองด้านบนจะทำให้request
พร้อมใช้งานเป็นหนึ่งในอาร์กิวเมนต์คำสำคัญของ__init__
ฟังก์ชันตัวสร้างแบบฟอร์ม ดังนั้นในการ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
วัตถุภายในget_form_kwargs
โดยอัตโนมัติหรือไม่
self.get_object
? ขยายCreateView
SingleObjectMixin
แต่จะได้ผลหรือเกิดข้อยกเว้นขึ้นอยู่กับว่าคุณกำลังสร้างวัตถุใหม่หรืออัปเดตวัตถุที่มีอยู่ คือทดสอบทั้งสองกรณี (และการลบแน่นอน)
aproach ตามปกติคือการจัดเก็บอ็อบเจ็กต์คำร้องขอในการอ้างอิงเธรดโลคัลโดยใช้มิดเดิลแวร์ จากนั้นคุณสามารถเข้าถึงสิ่งนี้ได้จากทุกที่ในแอพของคุณรวมถึงเมธอด Form.clean ()
การเปลี่ยนลายเซ็นของเมธอด Form.clean () หมายความว่าคุณมี Django เวอร์ชันแก้ไขซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ
จำนวนมิดเดิลแวร์มีลักษณะดังนี้:
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
ลงทะเบียนมิดเดิลแวร์นี้ตามที่อธิบายไว้ในเอกสาร Django
**kwargs
MyForm(request.POST, request=request)
สำหรับผู้ดูแลระบบ Django ใน 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
ฉันพบปัญหานี้โดยเฉพาะเมื่อปรับแต่งผู้ดูแลระบบ ฉันต้องการให้ช่องบางช่องได้รับการตรวจสอบตามข้อมูลรับรองของผู้ดูแลระบบรายนั้น ๆ
เนื่องจากฉันไม่ต้องการแก้ไขมุมมองเพื่อส่งคำขอเป็นอาร์กิวเมนต์ไปยังแบบฟอร์มสิ่งต่อไปนี้คือสิ่งที่ฉันทำ:
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
ไม่ใช่obj=None
บรรทัดที่ 11
'function' object has no attribute 'base_fields'
. อย่างไรก็ตามคำตอบที่ง่ายกว่า (โดยไม่ต้องปิด) @ Françoisทำงานได้อย่างราบรื่น
คุณไม่สามารถใช้วิธีนี้ได้เสมอไป (และอาจเป็นวิธีปฏิบัติที่ไม่ดี) แต่ถ้าคุณใช้แบบฟอร์มในมุมมองเดียวคุณสามารถกำหนดขอบเขตภายในเมธอดมุมมองได้
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
วิธีCBV ถ้าฉันรู้ว่าฉันต้องทำหลายอย่างกับคำขอ อาจมีค่าใช้จ่ายบางส่วนในการสร้างคลาสซ้ำ ๆ แต่เพียงแค่ย้ายจากเวลานำเข้าเป็นรันไทม์
คำตอบของDaniel Rosemanยังคงดีที่สุด อย่างไรก็ตามฉันจะใช้อาร์กิวเมนต์ตำแหน่งแรกสำหรับคำขอแทนอาร์กิวเมนต์คำหลักด้วยเหตุผลบางประการ:
สุดท้ายนี้ฉันจะใช้ชื่อที่ไม่ซ้ำกันมากขึ้นเพื่อหลีกเลี่ยงการแทนที่ตัวแปรที่มีอยู่ ดังนั้นคำตอบที่แก้ไขของฉันดูเหมือนว่า:
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 ...
ชีสสดจากชีสเบเกอร์ @ pypi: django-requestprovider
ฉันมีคำตอบอื่นสำหรับคำถามนี้ตามความต้องการของคุณที่คุณต้องการเข้าถึงผู้ใช้ด้วยวิธีการที่สะอาดของแบบฟอร์ม คุณสามารถลองสิ่งนี้ 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)
ตอนนี้คุณสามารถเข้าถึง self.instance ด้วยวิธีการที่สะอาดใน form.py
เมื่อคุณต้องการเข้าถึงผ่านมุมมองคลาส Django ที่ "เตรียมไว้" เหมือนCreateView
มีเคล็ดลับเล็ก ๆ ที่ควรรู้ (= วิธีแก้ปัญหาอย่างเป็นทางการไม่ได้ผลนอกกรอบ) ด้วยตัวCreateView
คุณเองคุณจะต้องเพิ่มโค้ดดังนี้:
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
= ในระยะสั้นนี่คือวิธีการส่งผ่านrequest
ไปยังแบบฟอร์มของคุณด้วยมุมมองสร้าง / อัปเดตของ Django