Django ตั้งค่าฟิลด์หลังจากฟอร์มเริ่มต้น


116

ฉันกำลังพยายามตั้งค่าฟิลด์เป็นค่าหนึ่งหลังจากเริ่มต้นฟอร์มแล้ว

ตัวอย่างเช่นฉันมีชั้นเรียนต่อไปนี้

class CustomForm(forms.Form):
    Email = forms.EmailField(min_length=1, max_length=200)

ในมุมมองฉันต้องการที่จะทำสิ่งนี้:

form = CustomForm()
form["Email"] = GetEmailString()

return HttpResponse(t.render(c))

คำตอบ:


135

เนื่องจากคุณไม่ได้ส่งผ่านข้อมูล POST ฉันจะถือว่าสิ่งที่คุณพยายามทำคือตั้งค่าเริ่มต้นที่จะแสดงในแบบฟอร์ม วิธีที่คุณทำคือใช้initialคีย์เวิร์ด

form = CustomForm(initial={'Email': GetEmailString()})

ดูเอกสาร Django Formสำหรับคำอธิบายเพิ่มเติม

หากคุณกำลังพยายามเปลี่ยนค่าหลังจากส่งแบบฟอร์มคุณสามารถใช้สิ่งต่อไปนี้

if form.is_valid():
    form.cleaned_data['Email'] = GetEmailString()

ตรวจสอบเอกสารอ้างอิงด้านบนสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้งาน cleaned_data


2
นี่เป็นการยืนยันสิ่งที่ฉันรู้ แต่ฉันModelChoiceFieldยังคงให้ invalid_choice เมื่อฉันให้initialค่า :(
markwalker_

ใช่นี่เป็นปัญหาของฉันด้วย และไม่สามารถเปลี่ยน form.data ['Email'] ได้
GergelyPolonkai

2
ฉันเปลี่ยนของฉันform.data['Email'] = GetEmailString()และมันได้ผล
psychok7

1
ฉันต้องการตั้งค่าระหว่าง CustomForm (request.POST) และ. is_valid () ดังนั้นฉันจึงไม่สามารถใช้ค่าเริ่มต้นในตัวสร้างหรือ clean_data ฉันลองใช้ form.data แล้ว แต่มันไม่เปลี่ยนรูป (Django 1.11)
Teekin

วิธีการแก้ปัญหาที่ถูกต้องเพื่อคำถามนี้ควรจะ: ช่วยให้คุณเข้าถึงในการเริ่มต้นค่าของคุณแม้หลังจาก instanciated แบบฟอร์มของคุณform.fields['Email'].initial = GetEmailString()form.fields['keyword'].initial
vctrd

95

หากคุณเริ่มต้นฟอร์มแล้วคุณสามารถใช้คุณสมบัติเริ่มต้นของฟิลด์ได้ ตัวอย่างเช่น,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()

นอกจากนี้ยังใช้งานได้ดีใน for loop กับชุดฟอร์มเพียงใช้ตรรกะ "for form in formet" และคุณสามารถตั้งค่าตัวเลือกและข้อมูลเริ่มต้นได้ดังที่เห็นด้านบน
radtek

5
มีวิธีอื่นในการทำเช่นนี้คือ Django 1.7 / Python 3.4 หรือไม่? สิ่งนี้ไม่ได้ผลสำหรับฉัน
Jeremy

1
@JeremyCraigMartinez: ไม่ ... แบบฟอร์มที่คุณกำลังลองใช้แบบผูกมัด (มีการส่งข้อมูล GET / POST) หรือไม่? เอกสารกล่าวว่านี่คือเหตุผลที่ค่าเริ่มต้นแสดงเฉพาะสำหรับฟอร์มที่ไม่ถูกผูกไว้ สำหรับรูปแบบที่ถูกผูกไว้เอาต์พุต HTML จะใช้ข้อมูลที่ถูกผูกไว้ ดูที่นี่
Markus

9
วิธีที่ถูกต้องคือ form.initial ["Email"] = GetEmailString ()
Elio Scordo

12

หากคุณต้องการทำภายใน__init__วิธีการของแบบฟอร์มด้วยเหตุผลบางประการคุณสามารถจัดการกับinitialdict:

class MyForm(forms.Form):
    my_field = forms.CharField(max_length=255)

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.initial['my_field'] = 'Initial value'

ในที่สุดก็พบทางออก. ขอบคุณ. มันได้ผลสำหรับฉัน
Almas Dusal

8

สิ่งที่คล้ายกับของ Nigel Cohen จะใช้งานได้หากคุณเพิ่มข้อมูลลงในสำเนาของชุดข้อมูลแบบฟอร์มที่รวบรวม:

form = FormType(request.POST)
if request.method == "POST":
    formcopy = form(request.POST.copy())
    formcopy.data['Email'] = GetEmailString()

1
ฉันไม่ใช่แฟนตัวยงของการลบล้างข้อมูลดิบ หากคุณต้องทำสิ่งนี้อย่างแน่นอนคุณควรdata[form.add_prefix('Email')]พิจารณากรณีที่มีการตั้งค่าคำนำหน้า
Josh

2
มีวิธีอื่นในการทำเช่นนี้คือ Django 1.7 / Python 3.4 หรือไม่? สิ่งนี้ไม่ได้ผลสำหรับฉัน
Jeremy

บรรทัดที่ 3 อาจสั้นลงเล็กน้อยหากไม่จำเป็นต้องคงรูปแบบเดิม:form.data = form.data.copy()
ZZY

@ Josh นี่คือสถานการณ์หนึ่งที่จำเป็น: ใช้แบบฟอร์มเพื่อตรวจสอบอินพุต -> การประมวลผลด้วยอินพุต -> การประมวลผลเสร็จสิ้น -> ลบ / แก้ไขหลายฟิลด์ของฟอร์มและแสดงผลเป็น HTML เป็นการตอบสนอง ตัวอย่างมีช่อง 'ชื่อ', 'อีเมล', 'เนื้อหา' ในแบบฟอร์มฉันต้องการเก็บ 'ชื่อ' และ 'อีเมล' แต่ลบ 'เนื้อหา' เพื่อให้ผู้ใช้ไม่จำเป็นต้องป้อนชื่อ / อีเมลอีกครั้งหากต้องการส่ง POST อื่น แน่นอนว่าการเริ่มต้นฟอร์มใหม่ด้วยชื่อ / อีเมลเดียวกันกับค่าเริ่มต้นเป็นวิธีหนึ่ง แต่ฉันคิดว่าการลบแบบฟอร์มเก่านั้นง่ายกว่าในบางกรณี
ZZY

ฉันไม่แน่ใจว่าฉันเข้าใจทั้งหมด modelform_factoryแต่ถ้าฉันทำมันเสียงที่ฉันชอบคุณควรแทนจะใช้ ด้วยวิธีนี้คุณสามารถสร้างคลาสฟอร์มที่ไม่มีฟิลด์ที่คุณไม่ต้องการ เป็นเรื่องอันตรายมากที่จะมีคลาสฟอร์มที่มีฟิลด์ที่ไม่แสดงผลเนื่องจากออบเจ็กต์ฟอร์มจะยังคงยอมรับข้อมูลสำหรับฟิลด์ที่ไม่แสดงผล ผู้โจมตีสามารถใช้สิ่งนี้ให้เป็นประโยชน์
Josh

5

หากคุณได้กำหนดค่าเริ่มต้นในรูปแบบนี้

form = CustomForm()

วิธีที่ถูกต้อง ณเดือนมกราคม 2019คือการใช้.initialเพื่อแทนที่ข้อมูล สิ่งนี้จะแทนที่ข้อมูลในintialdict ที่ไปพร้อมกับแบบฟอร์ม นอกจากนี้ยังใช้งานได้หากคุณเริ่มต้นโดยใช้อินสแตนซ์บางอย่างเช่น form = CustomForm(instance=instance)

ในการแทนที่ข้อมูลในแบบฟอร์มคุณต้อง

form.initial['Email'] = GetEmailString()

การสรุปสิ่งนี้จะเป็น

form.initial['field_name'] = new_value

3

เพียงแค่เปลี่ยนฟิลด์ Form.data ของคุณ:

class ChooseProjectForm(forms.Form):
    project = forms.ModelChoiceField(queryset=project_qs)
    my_projects = forms.BooleanField()

    def __init__(self, *args, **kwargs):
        super(ChooseProjectForm, self).__init__(*args, **kwargs)
        self.data = self.data.copy()  # IMPORTANT, self.data is immutable
        # any condition:
        if self.data.get('my_projects'):
            my_projects = self.fields['project'].queryset.filter(my=True)
            self.fields['project'].queryset = my_projects
            self.fields['project'].initial = my_projects.first().pk
            self.fields['project'].empty_label = None  # disable "-----"
            self.data.update(project=my_projects.first().pk)  # Update Form data
            self.fields['project'].widget = forms.HiddenInput()  # Hide if you want

0

หากต้องการเปลี่ยนวิธีอื่นในการผสมผสาน: สิ่งนี้ใช้ได้ผลด้วยสัญกรณ์ที่ทันสมัยกว่าเล็กน้อย มันใช้ได้กับข้อเท็จจริงที่ว่า a QueryDictไม่เปลี่ยนรูป

>>> the_form.data = {**f.data.dict(), 'some_field': 47}
>>> the_form['some_field'].as_widget()
'<input type="hidden" name="some_field" value="47"
        class="field-some_field" id="id_some_field">'


-12

อีกวิธีหนึ่งในการทำเช่นนี้หากคุณได้เริ่มต้นฟอร์มแล้ว (มีหรือไม่มีข้อมูล) และคุณต้องเพิ่มข้อมูลเพิ่มเติมก่อนที่จะแสดง:

form = Form(request.POST.form)
form.data['Email'] = GetEmailString()

8
สิ่งนี้ล้มเหลวสำหรับฉัน ฉันมีบรรทัดเหมือนข้างบนในวิธีการเริ่มต้นของแบบฟอร์มและทำให้เกิด "AttributeError: อินสแตนซ์ QueryDict นี้ไม่เปลี่ยนรูป"
Jonathan Hartley

รหัสนี้ใช้ได้เฉพาะเมื่อฟอร์มเริ่มต้นโดยไม่มีข้อมูลฟอร์มใด ๆ เป็นผลให้วัตถุไม่เปลี่ยนรูปเช่น request.GET หรือ request.POST จะไม่ถูกผูกมัดดังนั้นคุณจะได้รับพจนานุกรมว่างเปล่า (form.data) ที่สามารถเปลี่ยนแปลงได้โดยไม่มีข้อผิดพลาดใด ๆ ฉันใช้ Django 1.6.3
potar

วิธีนี้จะได้ผลหากส่วนหัว "ประเภทเนื้อหา" ของคุณตั้งค่าเป็น "หลายส่วน / ฟอร์มข้อมูล" จะล้มเหลวเมื่อคุณใช้ "application / x-www-form-urlencoded" ประเภทเนื้อหา ฉันไม่รู้ว่าทำไม แต่มันเป็นการดีบัก *****
teewuane
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.