从数据库中填充输入的 Django 表单

Django form with inputs populated from database

我有一个包含产品和订单的简单 Django 模型结构,由一个中介链接 table,它确定给定订单中每个产品的数量:

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 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'}
   ])

希望对您有所帮助!

您可以使用 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()

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

详细说明 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>