【问题标题】:Django form with inputs populated from database从数据库填充输入的 Django 表单
【发布时间】:2018-04-24 07:12:17
【问题描述】:

我有一个简单的 Django 模型结构,其中包含 Products 和 Orders,由一个中间表链接,该表确定给定订单中每个产品的数量:

models.py:

class Product(models.Model):
    name = models.CharField()

class Order(models.Model):
    id = models.IntegerField()
    products = models.ManyToManyField(Product, through='OrderProduct')

class OrderProduct(models.Model):
    order=models.ForeignKey(Order, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveSmallIntegerField()

我想在我的 forms.py 文件中设计一个表单,它 1) 提取数据库中每个产品的列表; 2) 为用户提供调整每个订购产品数量的选项(例如,在 CharField 输入中),以及 3) 创建新的 Order 和 OrderProduct 对象,用于存储用户订购的每个产品的数量记录。

但是,我想不出一个好方法来创建一个表单,该表单将自动从数据库中提取所有产品并添加字段来表示给定产品的订购数量。理想情况下,结果看起来像这样,但会自动编码:

forms.py:

class OrderForm(forms.Form):
    product_1_quantity = forms.IntegerField()
    product_2_quantity = forms.IntegerField()
    product_3_quantity = forms.IntegerField()

....等,对于每个产品。最好的方法是什么?它是否涉及为数据库中找到的每个产品创建一个新字段的“for”循环?

【问题讨论】:

    标签: django forms for-loop input formfield


    【解决方案1】:

    详细说明 user3140312 的以下答案 — Django 的 formsets 提供了解决方案!

    models.py:

    class Product(models.Model):
        name = models.CharField()
    
    class Order(models.Model):
        id = models.IntegerField()
        products = models.ManyToManyField(Product, through='OrderProduct')
    
    class OrderProduct(models.Model):
        order=models.ForeignKey(Order, on_delete=models.CASCADE)
        product = models.ForeignKey(Product, on_delete=models.CASCADE)
        quantity = models.PositiveSmallIntegerField()
    

    forms.py

    class ProductForm(forms.Form):
        product_id = forms.IntegerField(widget=forms.HiddenInput)
        quantity = forms.IntegerField()
    

    views.py

    from .forms import ProductForm
    from django.forms import formset_factory
    from .models import Product
    
    # Show a form asking for the user's product quantities
    def product_form(request):
    
        # If this form is being processed...
        if request.method == 'POST':
    
            ProductFormSet = formset_factory(ProductForm)
    
            # Grab the form from the POST variable
            formset = ProductFormSet(request.POST)
    
            # If the form is valid...
            if formset.is_valid():
    
                # Do whatever you want with the results
    
        # If the form is not being processed, create a new ProductFormSet and render it
        else:
    
            product_list = []
    
            for product in Product.objects.all():
                product_list.append({'product_id': product.id, 'quantity': 0})
    
            ProductFormSet = formset_factory(ProductForm, extra=0)
            formset = ProductFormSet(initial=product_list)
            return render(request, 'template.html', {'formset': formset})
    

    template.html:

    <form action="{% url '' %}" method="post">
        {% csrf_token %}
        {{ formset.as_table }}
        {{ formset.management_form }}
        <input type="submit" value="Submit" />
    </form>
    

    【讨论】:

    • 别忘了接受@user3140312的回答
    • 完成。谢谢!
    【解决方案2】:

    您可以使用ModelChoiceField 显示所有产品而无需执行 for 循环:

    class OrderForm(forms.Form):
        product = forms.ModelChoiceField(queryset=Product.objects.all()) # with queryset you can show a checkbox with the query
        quantify = forms.IntegerField()
    

    现在您的视图应该负责保存数据。例如,如果您需要一个“添加新”按钮,则可以使用 ajax,否则 you can use formset

    【讨论】:

    • 感谢您的回复!我试过这个,但这会产生一个“选择”下拉菜单,而我希望我的数据库中的每个产品都有一个单独的行,旁边有一个数量字段。 Formsets 在这里完成了目标 - 请参阅上面的答案!
    【解决方案3】:

    我认为 Django Formsets 可能对你有用。您可以根据您决定的数量反复创建相同形式的集合,从而创建您的产品。看看here。您可以执行以下示例中的操作。

    class ArticleForm(forms.Form):
       title = forms.CharField()
    
    from django.forms import formset_factory
    ArticleFormSet = formset_factory(ArticleForm, extra=2)
    

    您还可以使用以下数据预填充它,

    formset = ArticleFormSet(initial=[
          {'title': 'Django is now open source'}
       ])
    

    希望这会有所帮助!

    【讨论】:

    • 这很好用——非常感谢您的帮助!我将在另一篇文章中更详细地回答这个问题,以便人们可以看到整个代码。
    • 很高兴我能帮上忙 :)
    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 2015-04-26
    • 2018-03-08
    • 2021-08-03
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 2018-09-02
    相关资源
    最近更新 更多