我已经创建了一个'address'模型,用于我的应用程序的许多不同部分。每个用户可以有多个只属于自己的地址。我已经创建了另一个类"PersonalDetails",它属于一个用户。我希望这个类至少有一个,但最多有六个属于用户的地址。
我目前的设置(包括脆表单)允许这样做,但地址字段是一个"选择"字段,包含当前属于该用户的地址列表。我希望用户能够使用现有的地址或创建新的地址,因为他们去。我该怎么做呢?我试过让'PersonalDetails'表单使用'AddressForm',但没有任何乐趣。
作为额外的奖励,我只希望最初呈现一个地址表单,但用户可以选择单击"添加更多地址"以获取更多地址字段。这听起来像是formsets的工作,但我不知道这将如何与crispy一起工作-任何帮助将是伟大的!
Address_models.py
class Address(models.Model):
# Relations
profile = models.ForeignKey(
Profile,
verbose_name = "user"
)
# Attributes - Mandatory
address_line1 = models.CharField(
max_length = 45,
verbose_name = "Address line 1"
)
city = models.CharField(
max_length = 50,
)
postcode = models.CharField(
max_length = 8,
verbose_name = "Postcode",
help_text = "Enter your postcode",
blank = False,
validators = [RegexValidator(
"[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][A-Z]{2}")]
)
# Attributes - Optional
start_date = models.DateField(
verbose_name = "Start Date",
blank = True,
null = True,
help_text = "Move in date"
)
end_date = models.DateField(
verbose_name = "End Date",
blank = True,
null = True,
help_text = "Move out date"
)
address_line2 = models.CharField(
verbose_name = "Address line 2",
max_length = 45,
blank = True,
null = True
)
county = models.CharField(
verbose_name = "County",
max_length = 40,
blank = True,
null = True
)
PersonalDetails_models.py
class PersonalDetails(models.Model):
# Relations
profile = models.ForeignKey(
Profile,
verbose_name = "user"
)
# Attributes - Mandatory
ni_number = models.CharField(
max_length = 9,
verbose_name = "National Insurance Number",
help_text = "Enter your National Insurance number",
validators = [RegexValidator(
"^[a-zA-Z]{2}[0-9]{6}[A-Z]$")]
)
last_address = models.ForeignKey(
Address
)
# Attributes - Optional
prior_1_address = models.ForeignKey(
Address,
blank = True,
null = True,
related_name = "prior_1_address"
)
prior_2_address = models.ForeignKey(
Address,
blank = True,
null = True,
related_name = "prior_2_address"
)
prior_3_address = models.ForeignKey(
Address,
blank = True,
null = True,
related_name = "prior_3_address"
)
prior_4_address = models.ForeignKey(
Address,
blank = True,
null = True,
related_name = "prior_4_address"
)
prior_5_address = models.ForeignKey(
Address,
blank = True,
null = True,
related_name = "prior_5_address"
)
prior_6_address = models.ForeignKey(
Address,
blank = True,
null = True,
related_name = "prior_6_address"
)
Address_forms.py
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
PersonalDetails_forms.py
class PersonalDetailsForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PersonalDetailsForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_tag = False
class Meta:
model = PersonalDetailsForm
fields = ['ni_number', 'last_address', 'prior_1_address', 'prior_2_address', 'prior_3_address', 'prior_4_address', 'prior_5_address', 'prior_6_address']
我成功地使用了下面的小部件。
class Formset(LayoutObject):
"""
Layout object. It renders an entire formset, as though it were a Field.
Example::
Formset("attached_files_formset")
"""
template = "%s/formset.html" % TEMPLATE_PACK
def __init__(self, formset_name_in_context, template=None,**kwargs):
self.formset_name_in_context = formset_name_in_context
# crispy_forms/layout.py:302 requires us to have a fields property
self.fields = []
# Overrides class variable with an instance level variable
if template:
self.template = template
def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
formset = context[self.formset_name_in_context]
html = ''
return render_to_string(self.template, Context({'wrapper': self,
'formset': formset}))
将这个小部件添加到应用程序的某个地方,并像使用其他字段一样使用它。假设你的模块是crispy_layouts
helper_content.append(
crispy_layouts.Formset('address_form')
)
helper = FormHelper()
helper.layout = Layout(
helper_content,
)
address_form在您的上下文中是一个有效的表单集。它使用"%s/formset.html"模板是默认的,你可以根据自己的需要自定义。
我使用下面的模板和bootstrap3
<div class="formset">
<div class="table-scrollable">
{{ formset.non_form_errors.as_ul }}
<table class="table table-hover">
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr>
{% for field in form.visible_fields %}
<td> {# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field | as_crispy_field}}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<div class="row">
<div class="col-md-12">
<input type="submit" class="btn btn-primary pull-right" value="Add Row" name="addrow">
</div>
</div>
</div>
</div>
正如你在我的模板中看到的,我允许人们在视图中添加更多行。如果你的要求。POST包含addrow,然后复制您的请求。POST到post_data,所以它是可变的。
post_data['addressform-TOTAL_FORMS'] = int(post_data['addressform-TOTAL_FORMS'])+ 1
就是增加TOTAL_FORMS变量并将表单原样返回给用户。