Используйте formset_factory в качестве подформы в хрустящей форме Django

Я создал модель «адреса», которая используется в различных частях моего приложения. Каждый пользователь может иметь несколько адресов, принадлежащих исключительно ему. Я создал еще один класс — PersonalDetails, принадлежащий пользователю. Я бы хотел, чтобы этот класс имел хотя бы один, но до шести адресов, принадлежащих пользователю.

Моя текущая настройка (включая хрустящие формы) позволяет это, но поле адреса представляет собой поле «выбрать», содержащее список адресов, принадлежащих в настоящее время этому пользователю. Я хотел бы, чтобы пользователь мог использовать существующие адреса или создавать новые адреса по мере их появления. Как мне это сделать? Я пытался заставить форму «Личные сведения» использовать «Адресную форму», но без особого удовольствия.

В качестве дополнительного бонуса я хотел бы сначала отобразить только одну адресную форму, но у пользователя есть возможность щелкнуть «добавить больше адресов» для дополнительных адресных полей. Это звучало как работа для наборов форм, но я не знаю, как это будет работать с хрустящими - любая помощь была бы здоровой!

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
class AddressForm(forms.ModelForm):

    class Meta:
        model = Address
        fields = '__all__'
address = models.ForeignKey( Address, blank = True, null = True, related_name = "prior
class AddressForm(forms.ModelForm):

    class Meta:
        model = Address
        fields = '__all__'
address" ) prior
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']
address = models.ForeignKey( Address, blank = True, null = True, related_name = "prior
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']
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']

person Kali_89    schedule 19.07.2015    source источник


Ответы (1)


Я успешно использую виджет ниже.

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>

Как вы можете видеть в моем шаблоне, я позволяю людям добавлять больше строк, чтобы сделать это, на ваш взгляд. Если ваш request.POST содержит addrow, скопируйте ваш request.POST в post_data, чтобы он был изменяемым.

post_data['addressform-TOTAL_FORMS'] = int(post_data['addressform-TOTAL_FORMS'])+ 1

Вы в основном увеличиваете переменную TOTAL_FORMS и снова возвращаете эту форму пользователю как есть.

Вот как вы добавляете больше строк в свой набор форм без javascript.

person durdenk    schedule 25.08.2015