Django đặt giá trị trường sau khi biểu mẫu được khởi tạo


116

Tôi đang cố gắng đặt trường thành một giá trị nhất định sau khi biểu mẫu được khởi tạo.

Ví dụ, tôi có lớp sau.

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

Theo quan điểm, tôi muốn có thể làm điều gì đó như sau:

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

return HttpResponse(t.render(c))

Câu trả lời:


135

Vì bạn không chuyển dữ liệu POST, tôi sẽ giả định rằng những gì bạn đang cố gắng làm là đặt một giá trị ban đầu sẽ được hiển thị trong biểu mẫu. Cách bạn làm điều này là với initialtừ khóa.

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

Xem tài liệu về Biểu mẫu Django để biết thêm giải thích.

Nếu bạn đang cố gắng thay đổi một giá trị sau khi biểu mẫu được gửi, bạn có thể sử dụng một số thứ như:

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

Kiểm tra các tài liệu tham khảo ở trên để biết thêm về cách sử dụng cleaned_data


2
Điều này xác nhận những gì tôi biết, nhưng tôi ModelChoiceFieldvẫn cho không hợp lệ_choice khi tôi cho nó một initialgiá trị :(
markwalker_

Vâng, đây cũng là vấn đề của tôi. Và việc thay đổi form.data ['Email'] là không thể.
GergelyPolonkai

2
tôi đã thay đổi của tôi thành form.data['Email'] = GetEmailString()và nó hoạt động
psychok7

1
Tôi cần đặt nó giữa CustomForm (request.POST) và .is_valid (), vì vậy tôi không thể sử dụng ký tự đầu trong phương thức khởi tạo cũng như dữ liệu clean_data. Tôi đã thử sử dụng form.data, nhưng nó không thay đổi được (Django 1.11).
Teekin

Các giải pháp đúng cho câu hỏi này phải nộp là: form.fields['Email'].initial = GetEmailString() Các form.fields['keyword'].initialphép bạn truy cập để khởi tạo giá trị của bạn ngay cả sau khi đã instanciated hình thức của bạn
vctrd

95

Nếu bạn đã khởi tạo biểu mẫu, bạn có thể sử dụng thuộc tính ban đầu của trường. Ví dụ,

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

Cũng hoạt động tuyệt vời trong vòng lặp for với bộ định dạng, chỉ cần sử dụng logic "cho biểu mẫu trong bộ định dạng" và bạn có thể đặt các lựa chọn và dữ liệu ban đầu như đã thấy ở trên.
radtek

5
Có cách nào khác để làm điều này là Django 1.7 / Python 3.4 không? Đây không phải là làm việc cho tôi
Jeremy

1
@JeremyCraigMartinez: Không ... Biểu mẫu bạn đang thử có phải là biểu mẫu liên kết (với dữ liệu GET / POST được chuyển vào) không? Tài liệu cho biết Đây là lý do tại sao các giá trị ban đầu chỉ được hiển thị cho các biểu mẫu không liên kết. Đối với các biểu mẫu liên kết, đầu ra HTML sẽ sử dụng dữ liệu liên kết. , xem ở đây
Markus

9
cách đúng là form.initial ["Email"] = GetEmailString ()
Elio Scordo

12

Nếu bạn muốn thực hiện việc đó trong phương thức của biểu mẫu __init__vì lý do nào đó, bạn có thể thao tác lệnh 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'

Cuối cùng cũng tìm ra giải pháp. Cảm ơn bạn. Nó làm việc cho tôi.
Almas Dusal

8

Một cái gì đó giống như của Nigel Cohen sẽ hoạt động nếu bạn thêm dữ liệu vào bản sao của tập hợp dữ liệu biểu mẫu đã thu thập:

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

1
Tôi không phải là người thích ghi đè dữ liệu thô. Nếu bạn nhất thiết phải làm điều này, bạn có thể nên làm data[form.add_prefix('Email')]để tính đến các trường hợp tiền tố được đặt.
Josh

2
Có cách nào khác để làm điều này là Django 1.7 / Python 3.4 không? Đây không phải là làm việc cho tôi
Jeremy

Dòng thứ 3 có thể ngắn hơn một chút nếu không cần giữ nguyên dạng ban đầu:form.data = form.data.copy()
ZZY

@Josh, đây là một tình huống cần thiết: sử dụng biểu mẫu để xác thực đầu vào -> xử lý với đầu vào -> xử lý xong -> xóa / sửa đổi một số trường của biểu mẫu và hiển thị thành HTML dưới dạng phản hồi. Ví dụ, có các trường 'tên', 'email', 'nội dung' trong một biểu mẫu, tôi muốn giữ lại 'tên' và 'email', nhưng xóa 'nội dung'. Vì vậy, người dùng không cần phải nhập lại tên / email nếu họ muốn gửi một BÀI ĐĂNG khác. Tất nhiên khởi tạo một hình thức mới có cùng tên / email như giá trị ban đầu là một cách, nhưng tôi nghĩ rằng xóa về hình thức cũ là đơn giản hơn trong một số trường hợp
ZZY

Tôi không chắc mình hoàn toàn hiểu. Tuy nhiên, nếu tôi làm vậy, tôi nghe có vẻ như bạn nên sử dụng modelform_factory. Bằng cách này, bạn có thể tạo một lớp Biểu mẫu không có các trường bạn không muốn. Rất nguy hiểm khi có một lớp Biểu mẫu có các trường không được hiển thị vì đối tượng biểu mẫu sẽ vẫn chấp nhận dữ liệu cho các trường không được hiển thị. Kẻ tấn công có thể sử dụng điều này để có lợi cho họ.
Josh

5

Nếu bạn đã khởi tạo biểu mẫu như thế này

form = CustomForm()

thì cách chính xác kể từ tháng 1 năm 2019 , là sử dụng .initialđể thay thế dữ liệu. Điều này sẽ thay thế dữ liệu trong intialdict đi cùng với biểu mẫu. Nó cũng hoạt động nếu bạn đã khởi tạo bằng một số ví dụ như form = CustomForm(instance=instance)

Để thay thế dữ liệu trong biểu mẫu, bạn cần

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

Tổng quát hóa điều này, nó sẽ là,

form.initial['field_name'] = new_value

3

Chỉ cần thay đổi trường Form.data của bạn:

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 ra một cách khác vào hỗn hợp: điều này cũng hoạt động, với ký hiệu hiện đại hơn một chút. Nó chỉ hoạt động xung quanh thực tế là a QueryDictlà bất biến.

>>> 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">'

0

trong widget sử dụng "giá trị" attr. Thí dụ:

username = forms.CharField(
    required=False,
    widget=forms.TextInput(attrs={'readonly': True, 'value': 'CONSTANT_VALUE'}),
)

-12

Một cách khác để làm điều này, nếu bạn đã khởi tạo một biểu mẫu (có hoặc không có dữ liệu) và bạn cần thêm dữ liệu khác trước khi hiển thị:

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

8
Điều này không thành công cho tôi. Tôi có một dòng như trên trong hình thức của tôi init phương pháp, và nó làm tăng "AttributeError: QueryDict này dụ là không thay đổi"
Jonathan Hartley

Mã này chỉ hoạt động khi biểu mẫu đã được khởi tạo mà không có bất kỳ dữ liệu biểu mẫu nào. Do đó, một đối tượng không thể thay đổi như request.GET hoặc request.POST sẽ không bị ràng buộc, vì vậy bạn sẽ nhận được một từ điển trống (form.data) có thể được thay đổi mà không có bất kỳ lỗi nào. FYI Tôi đang sử dụng Django 1.6.3
potar

Điều này sẽ hoạt động nếu tiêu đề "Loại-Nội dung" của bạn được đặt thành "nhiều phần / biểu mẫu-dữ liệu". Nó không thành công khi bạn sử dụng loại nội dung "application / x-www-form-urlencoded". Tôi không biết tại sao, nhưng nó là một ***** để gỡ lỗi.
teewuane
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.