使用 1 个按钮 Django 提交 2 个自定义 Crispy 表单

发布于 2025-01-15 10:53:03 字数 4761 浏览 2 评论 0原文

我有 2 个表格,第二个表格引用第一个表格。我可以使用脆表单正确执行表单,但是,当我使用 helper = FormHelper() 自定义每个表单时,它们将不再一起提交。本质上,一个表单已提交,而另一个表单则认为它丢失了所有输入数据。

Forms.py

    from django.forms import ModelForm, forms
from .models import Item, Item_dimensions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column


# Create the form class.
class List_Item_Form(ModelForm):
    class Meta:
        model = Item
        exclude = ('id','creator','created_on','updated_on' )

    helper = FormHelper()
    helper.layout = Layout(
        Row(
            Column('item_name', css_class='form-group col-md-6 mb-0'),
            Column('price', css_class='form-group col-md-6 mb-0'),
            css_class='form-row'
        ),
        'short_description',
        'description',
        Row(
            Column('main_image', css_class='form-group col-md-2.5 mb-0'),
            Column('image_2', css_class='form-group col-md-2.5 mb-0'),
            Column('image_3', css_class='form-group col-md-2.5 mb-0'),
            Column('image_4', css_class='form-group col-md-2.5 mb-0'),
            Column('image_5', css_class='form-group col-md-2.5 mb-0'),
            css_class='form-row'
        ),
        'quantity'
    )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_method = 'POST'

class List_Item_Dimensions(ModelForm):
    class Meta:
        model = Item_dimensions
        exclude = ('id','item_id')
    helper = FormHelper()
    helper.layout = Layout(
            Row(
                Column('x_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('y_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('z_dim_mm', css_class='form-group col-md-4 mb-0'),
                css_class='form-row'
            ),
            'weight_grams',
            Submit('submit', 'add_listing')
        )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_method = 'POST'

我尝试删除

helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))

并仅使用一个提交按钮,但它不起作用

Views.py

@login_required
def AddListing(request):
    if request.method == 'POST':
        form = List_Item_Form(request.POST,request.FILES)
        dim_form = List_Item_Dimensions(request.POST)
        if form.is_valid() and dim_form.is_valid():
            itemName = form.cleaned_data['item_name']
            price = form.cleaned_data['price']
            s_desc = form.cleaned_data['short_description']
            desc = form.cleaned_data['description']
            quantity = form.cleaned_data['quantity']
            main_img = form.cleaned_data['main_image']
            image_2 = form.cleaned_data['image_2']
            image_3 = form.cleaned_data['image_3']
            image_4 = form.cleaned_data['image_4']
            image_5 = form.cleaned_data['image_5']
            x_dim = dim_form.cleaned_data['x_dim_mm']
            y_dim = dim_form.cleaned_data['y_dim_mm']
            z_dim = dim_form.cleaned_data['z_dim_mm']
            weight = dim_form.cleaned_data['weight_grams']
            current_user =  request.user
            

            model_instance = Item(creator=current_user, item_name=itemName, 
                                price=price,short_description=s_desc,
                                description=desc, quantity=quantity,
                                main_image=main_img, image_2=image_2, 
                                image_3=image_3, image_4 = image_4, 
                                image_5=image_5)
            dim_instance = Item_dimensions(x_dim_mm = x_dim,
                                            y_dim_mm =y_dim,
                                            z_dim_mm =z_dim, 
                                            weight_grams = weight)
            model_instance.save()
            # dim_instance.save(commit=False)
            dim_instance.item_id = model_instance
            dim_instance.save()
            return HttpResponseRedirect('/user_profile/items/')
    else:
        form = List_Item_Form()
        dim_form = List_Item_Dimensions()
    return render(request, 'store/add_listing.html', {'form': form,'dim_form':dim_form})

template.html

{% block content %}
<div>
    <h1> list a new item </h1>
{% load crispy_forms_tags %} 
{% csrf_token %}
<form method="post", enctype="multipart/form-data">{% csrf_token %}
    {% crispy form  %}
    {% crispy dim_form %}
    {% comment %} {{ form|crispy }}
    {{ dim_form|crispy }} {% endcomment %}
    <input name="submit" type="post" value="template button">
</form>
</div>

{% endblock content %}

I have 2 forms with the second form referencing the first form. I can get the forms to execute correctly using crispy forms, however, when I customize each form using helper = FormHelper() they will no longer submit together. Essentially one form is submitted and the other form thinks it is missing all of its input data.

Forms.py

    from django.forms import ModelForm, forms
from .models import Item, Item_dimensions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column


# Create the form class.
class List_Item_Form(ModelForm):
    class Meta:
        model = Item
        exclude = ('id','creator','created_on','updated_on' )

    helper = FormHelper()
    helper.layout = Layout(
        Row(
            Column('item_name', css_class='form-group col-md-6 mb-0'),
            Column('price', css_class='form-group col-md-6 mb-0'),
            css_class='form-row'
        ),
        'short_description',
        'description',
        Row(
            Column('main_image', css_class='form-group col-md-2.5 mb-0'),
            Column('image_2', css_class='form-group col-md-2.5 mb-0'),
            Column('image_3', css_class='form-group col-md-2.5 mb-0'),
            Column('image_4', css_class='form-group col-md-2.5 mb-0'),
            Column('image_5', css_class='form-group col-md-2.5 mb-0'),
            css_class='form-row'
        ),
        'quantity'
    )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_method = 'POST'

class List_Item_Dimensions(ModelForm):
    class Meta:
        model = Item_dimensions
        exclude = ('id','item_id')
    helper = FormHelper()
    helper.layout = Layout(
            Row(
                Column('x_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('y_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('z_dim_mm', css_class='form-group col-md-4 mb-0'),
                css_class='form-row'
            ),
            'weight_grams',
            Submit('submit', 'add_listing')
        )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_method = 'POST'

I have tried removing

helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))

and using just one submit button but it didn't work

Views.py

@login_required
def AddListing(request):
    if request.method == 'POST':
        form = List_Item_Form(request.POST,request.FILES)
        dim_form = List_Item_Dimensions(request.POST)
        if form.is_valid() and dim_form.is_valid():
            itemName = form.cleaned_data['item_name']
            price = form.cleaned_data['price']
            s_desc = form.cleaned_data['short_description']
            desc = form.cleaned_data['description']
            quantity = form.cleaned_data['quantity']
            main_img = form.cleaned_data['main_image']
            image_2 = form.cleaned_data['image_2']
            image_3 = form.cleaned_data['image_3']
            image_4 = form.cleaned_data['image_4']
            image_5 = form.cleaned_data['image_5']
            x_dim = dim_form.cleaned_data['x_dim_mm']
            y_dim = dim_form.cleaned_data['y_dim_mm']
            z_dim = dim_form.cleaned_data['z_dim_mm']
            weight = dim_form.cleaned_data['weight_grams']
            current_user =  request.user
            

            model_instance = Item(creator=current_user, item_name=itemName, 
                                price=price,short_description=s_desc,
                                description=desc, quantity=quantity,
                                main_image=main_img, image_2=image_2, 
                                image_3=image_3, image_4 = image_4, 
                                image_5=image_5)
            dim_instance = Item_dimensions(x_dim_mm = x_dim,
                                            y_dim_mm =y_dim,
                                            z_dim_mm =z_dim, 
                                            weight_grams = weight)
            model_instance.save()
            # dim_instance.save(commit=False)
            dim_instance.item_id = model_instance
            dim_instance.save()
            return HttpResponseRedirect('/user_profile/items/')
    else:
        form = List_Item_Form()
        dim_form = List_Item_Dimensions()
    return render(request, 'store/add_listing.html', {'form': form,'dim_form':dim_form})

template.html

{% block content %}
<div>
    <h1> list a new item </h1>
{% load crispy_forms_tags %} 
{% csrf_token %}
<form method="post", enctype="multipart/form-data">{% csrf_token %}
    {% crispy form  %}
    {% crispy dim_form %}
    {% comment %} {{ form|crispy }}
    {{ dim_form|crispy }} {% endcomment %}
    <input name="submit" type="post" value="template button">
</form>
</div>

{% endblock content %}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千仐 2025-01-22 10:53:03

{% Crispy form %} 会自动添加

标签,除非您另外指定 form_tag = False。请参阅 https://django-crispy-forms.readthedocs.io/en /latest/form_helper.html

这里您已经给出了一个外部标签,因此其中的 crispy 标签将创建嵌套表单。这会使您的 HTML 无效。检查 https://django-crispy-forms .readthedocs.io/en/latest/crispy_tag_forms.html#crispy-tag-forms

PS:(还没用过最近的 django) - 您不需要在构造函数中包含帮助程序和其他自定义吗?

{% crispy form %} automatically adds <form></form> tags unless otherwise you specify form_tag = False. See https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html

Here you've already given an outer tag and hence the crispy tags inside it will create nested forms. This makes your HTML invalid. Check https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html#crispy-tag-forms

PS: (Haven't used django recently) - don't you need to include the helper and other customisations inside the constructor?

奶茶白久 2025-01-22 10:53:03

扩展@art的答案,这就是您可能想要的:

from django.forms import ModelForm
from .models import Item, Item_dimensions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column


# Create the form class.
class List_Item_Form(ModelForm):
    class Meta:
        model = Item
        exclude = ('id', 'creator', 'created_on', 'updated_on')

    helper = FormHelper()
    helper.layout = Layout(
        Row(
            Column('item_name', css_class='form-group col-md-6 mb-0'),
            Column('price', css_class='form-group col-md-6 mb-0'),
            css_class='form-row'
        ),
        'short_description',
        'description',
        Row(
            Column('main_image', css_class='form-group col-md-2.5 mb-0'),
            Column('image_2', css_class='form-group col-md-2.5 mb-0'),
            Column('image_3', css_class='form-group col-md-2.5 mb-0'),
            Column('image_4', css_class='form-group col-md-2.5 mb-0'),
            Column('image_5', css_class='form-group col-md-2.5 mb-0'),
            css_class='form-row'
        ),
        'quantity'
    )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_tag = False  # add this
    helper.disable_csrf = True  # otherwise the crispy form will add an additional csrf token (optional)


class List_Item_Dimensions(ModelForm):
    class Meta:
        model = Item_dimensions
        exclude = ('id', 'item_id')
    helper = FormHelper()
    helper.layout = Layout(
            Row(
                Column('x_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('y_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('z_dim_mm', css_class='form-group col-md-4 mb-0'),
                css_class='form-row'
            ),
            'weight_grams',
            Submit('submit', 'add_listing')
    )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_tag = False  # add this
    helper.disable_csrf = True  # otherwise the crispy form will add an additional csrf token (optional)

并且您可以以相同的方式将它们渲染在模板内:

{% block content %}
<div>
    <h1> list a new item </h1>
    {% load crispy_forms_tags %}
    <form method="post", enctype="multipart/form-data">{% csrf_token %}
        {% crispy form  %}
        {% crispy dim_form %}
        <input name="submit" type="post" value="template button">
    </form>
</div>

{% endblock content %}

另请注意,添加 {% csrf_token %} 只是添加一个额外的隐藏表单字段,类似于以下内容

<input type="hidden" name="csrfmiddlewaretoken" value="uo5TUfy6PxVbDDKuEhRlJEri3wGOkOZuuZbHKoDWGOhA1O5zjk9RLSwfFcEuxQec">

: csrf 令牌没有坏处,但也没有必要。

虽然与原来的问题并不严格相关,但我也想提出一些建议。在处理 ModelForms 时,Django 在幕后做了很多魔法。这意味着您可以省去手动获取视图中所有模型字段以创建新模型实例的麻烦。我还没有对此进行测试,但您的视图很可能会大大简化为类似的内容:

@login_required
def AddListing(request):
    if request.method == 'POST':
        form = List_Item_Form(request.POST,request.FILES)
        dim_form = List_Item_Dimensions(request.POST)
        if form.is_valid() and dim_form.is_valid():
            current_user = request.user

            model_instance = form.save(commit=False)
            model_instance.creator = current_user
            model_instance.save()

            dim_instance = dim_form.save(commit=False)
            dim_instance.item_id = model_instance
            dim_instance.save()
            return HttpResponseRedirect('/user_profile/items/')
    else:
        form = List_Item_Form()
        dim_form = List_Item_Dimensions()
    return render(request, 'store/add_listing.html', {'form': form, 'dim_form': dim_form})

Expanding on @art's answer, here's what you probably want:

from django.forms import ModelForm
from .models import Item, Item_dimensions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column


# Create the form class.
class List_Item_Form(ModelForm):
    class Meta:
        model = Item
        exclude = ('id', 'creator', 'created_on', 'updated_on')

    helper = FormHelper()
    helper.layout = Layout(
        Row(
            Column('item_name', css_class='form-group col-md-6 mb-0'),
            Column('price', css_class='form-group col-md-6 mb-0'),
            css_class='form-row'
        ),
        'short_description',
        'description',
        Row(
            Column('main_image', css_class='form-group col-md-2.5 mb-0'),
            Column('image_2', css_class='form-group col-md-2.5 mb-0'),
            Column('image_3', css_class='form-group col-md-2.5 mb-0'),
            Column('image_4', css_class='form-group col-md-2.5 mb-0'),
            Column('image_5', css_class='form-group col-md-2.5 mb-0'),
            css_class='form-row'
        ),
        'quantity'
    )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_tag = False  # add this
    helper.disable_csrf = True  # otherwise the crispy form will add an additional csrf token (optional)


class List_Item_Dimensions(ModelForm):
    class Meta:
        model = Item_dimensions
        exclude = ('id', 'item_id')
    helper = FormHelper()
    helper.layout = Layout(
            Row(
                Column('x_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('y_dim_mm', css_class='form-group col-md-4 mb-0'),
                Column('z_dim_mm', css_class='form-group col-md-4 mb-0'),
                css_class='form-row'
            ),
            'weight_grams',
            Submit('submit', 'add_listing')
    )
    helper.add_input(Submit('submit', 'Submit', css_class='btn-primary'))
    helper.form_tag = False  # add this
    helper.disable_csrf = True  # otherwise the crispy form will add an additional csrf token (optional)

And you'd render them inside of your template in the same way:

{% block content %}
<div>
    <h1> list a new item </h1>
    {% load crispy_forms_tags %}
    <form method="post", enctype="multipart/form-data">{% csrf_token %}
        {% crispy form  %}
        {% crispy dim_form %}
        <input name="submit" type="post" value="template button">
    </form>
</div>

{% endblock content %}

Also note that adding {% csrf_token %} simply adds an additional hidden form field similar to the following:

<input type="hidden" name="csrfmiddlewaretoken" value="uo5TUfy6PxVbDDKuEhRlJEri3wGOkOZuuZbHKoDWGOhA1O5zjk9RLSwfFcEuxQec">

Adding additional csrf tokens doesn't hurt, but also isn't necessary.

While not strictly related to the original question, I'd also like to give a word of advice. When dealing with ModelForms, Django does lots of magic behind the scenes. What this means is that you can save yourself the headache of manually grabbing all of your model's fields in your view to create a new model instance. I haven't tested this, but your view could most likely be greatly simplified to something similar this :

@login_required
def AddListing(request):
    if request.method == 'POST':
        form = List_Item_Form(request.POST,request.FILES)
        dim_form = List_Item_Dimensions(request.POST)
        if form.is_valid() and dim_form.is_valid():
            current_user = request.user

            model_instance = form.save(commit=False)
            model_instance.creator = current_user
            model_instance.save()

            dim_instance = dim_form.save(commit=False)
            dim_instance.item_id = model_instance
            dim_instance.save()
            return HttpResponseRedirect('/user_profile/items/')
    else:
        form = List_Item_Form()
        dim_form = List_Item_Dimensions()
    return render(request, 'store/add_listing.html', {'form': form, 'dim_form': dim_form})
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文