多对多模型的 Django 表单。如何从视图/模板填写表格?

Posted

技术标签:

【中文标题】多对多模型的 Django 表单。如何从视图/模板填写表格?【英文标题】:Django form for many-to-many model. How do I fill a form from views/template? 【发布时间】:2014-03-03 05:43:07 【问题描述】:

所以我有 2 个通过 Many-to-many 关系关联的模型。因为我需要一个额外的文件,所以我使用了额外的模型CategoryByDay

基本上我想要在我的应用程序中创建一个习惯或日常清单,记录我今天必须做的各种事情。所以我想将每个新的一天与每个类别联系起来并记录它的状态(如果它完成了1,如果不是0)。我正在使用CharField,因为稍后我想记录阅读书籍等其他内容,这里不相关

models.py

from django.db import models

class Day(models.Model):
    name = models.CharField(max_length=8)
    date = models.DateField()

    def __unicode__(self):
        return self.name

class Category(models.Model):
    name = models.CharField(max_length=100)
    categoryBD = models.ManyToManyField(Day, through='CategoryByDay')

    def __unicode__(self):
        return self.name

class CategoryByDay(models.Model):
    day = models.ForeignKey(Day)
    category = models.ForeignKey(Category)
    status = models.CharField(max_length=64)

在我的html 中,我想显示一个类别列表和它附近的一个表格,其中只会发布状态和日期以及类别将自动填写。现在我不知道该怎么做。这是我到目前为止得到的,在一些论坛上阅读,您可以从视图中传递额外的数据(这不起作用,并且表单要求我填写日期和类别表单)

views.py

def today(request):
    if request.method == 'POST':
#... POST validation here, not relevant
    else:
        day = datetime.date.today().strftime("%d/%m/%y")
        categories_list = Category.objects.all()
        category_form_list = []
# I am doing this strange list, because later in template I had problem
# accessing list through iteration like forloop.counter. 
# I will access it via for x,y in pair
        for category in categories_list:
            data = 'day': day,
            'category': category.name,
            form = CategoryByDayForm(data)
            #So I tried adding data to form, it didn't work and can be ignored
            part = [category, form]
            category_form_list.append(part)
        context =  't': t,
        'category_form_list': category_form_list,
        return render(request, 'today/today.html', context)

这是我的表格,我猜应该早点添加的。

表格py

class CategoryByDayForm(forms.ModelForm):
    status = forms.CharField(max_length=64, initial="0")
    day = forms.ModelMultipleChoiceField(queryset=Day.objects.all())
    category = forms.ModelMultipleChoiceField(queryset=Category.objects.all())
    class Meta:
        model = CategoryByDay

现在,在表单中,我不确定应该为日期和类别使用哪种表单类型。也许我应该以某种方式省略它?

最终模板:

今天的html

#...
    <ul>
        % for category, form in category_form_list %
            <li>                   
                 category.name 
                <form action="" method="post">
                    % csrf_token %
                     form.non_field_errors
                    <div class="status">
                         form.status.errors
                         form.status 
                        <input type="submit" value="Submit" />
                    </div>
                </form>
            </li>
        % endfor %
    </ul>
#...

这很有效,只显示一个表单status,但是当我点击提交并以我的方式调试它时,我遇到了我没有填写日期和类别表单的错误。

有人可以告诉我如何进行吗?

【问题讨论】:

一个简单的方法是为特定的日期和类别创建一个视图(在 URL 中提到)。然后表单必须省略日期和类别字段。它应该在保存表单时填充它们。 @arocks 所以我听从了你的建议,从字段中删除了日期和类别,并设法在我的视图中设置了日期。日子很简单,因为它总是保存今天的日期。现在,有没有办法从模板发送类别名称?如果我知道如何发送它,我现在可以使用 request.category 检索它。 为什么不从 example.com/category/23 这样的 url 中获取它,其中 23 是类别 ID? 我终于通过在 POST 请求中添加隐藏输入发送类别名称来做到这一点。 &lt;input type="hidden" value=" category.name " name="category"&gt;感谢您的帮助,这是很好的指导。 很高兴听到您成功了 :) 【参考方案1】:

我设法让它工作。

对于将来偶然在谷歌上搜索并进入此页面的任何人,这就是我所做的。

1.更改CategoryByDayForm的形式,只接受状态,不接受日期和类别

forms.py

from django import forms
from today.models import CategoryByDay, Category, Day

class CategoryByDayForm(forms.ModelForm):
    status = forms.CharField(max_length=64, initial="0")
    class Meta:
        model = CategoryByDay
        exclude = ['day', 'category']
    在模板中,添加隐藏表单输入发送当前类别迭代:

today.html

#...
% for category, form in category_form_list %
                <li>                   
                     category.name 
                    <form action="" method="post">
                        % csrf_token %
                         form.non_field_errors
                        <input type="hidden" value=" category.name " name="category">
                        <div class="status">
                             form.status 
                            <input type="submit" value="Submit" />
                        </div>
                    </form>
                </li>
            % endfor %
# ...

最后,在视图中,我操纵了我得到的表单,所以我添加了缺失的元素(从表单我有状态,我仍然需要设置日期和类别)

views.py

def today(request):
    t = datetime.date.today().strftime("%d/%m/%y")
    day = Day.objects.filter(name=t)
    if request.method == 'POST':
            form = CategoryByDayForm(request.POST)
        if form.is_valid():
            category_status = form.save(commit=False)
            category_status.day = day[0]
            category_name = request.POST['category']
            category_status.category = Category.objects.filter(name=category_name)[0]
            category_status.save()
            form.save_m2m()

...

希望以后能对大家有所帮助。

【讨论】:

【参考方案2】:

另一种解决方案 视图.py:

class ViewIndex(TemplateResponseMixin, View):
    template_name = 'frontend/view_index.html'

    def dispatch(self, request, *args, **kwargs):
       FS = modelformset_factory(CategoryByDay, extra=1)
       queryset = CategoryByDay.objects.filter(day__date=datetime.date.today())

       if request.method == 'POST':
           formset = FS(request.POST, request.FILES)

           if formset.is_valid():
               formset.save()
               formset = FS(queryset=queryset)

       else:
           formset = FS(queryset=queryset)


       return self.render_to_response('formset':formset)

前端/view_index.html:

% extends 'base.html' %
% block content_main %
<form method="post" enctype="multipart/form-data">
    % csrf_token %
     formset.management_form 
    % for form in formset %
        form 
       <hr/>
    % endfor %

    <input type="submit">
</form>
% endblock %

和 urls.py

urlpatterns = patterns('',
   url(r'^$', ViewIndex.as_view(), name='view_index'),
)

【讨论】:

以上是关于多对多模型的 Django 表单。如何从视图/模板填写表格?的主要内容,如果未能解决你的问题,请参考以下文章

具有多对多关系的Django表单不保存

如何在 django 中处理未保存的多对多关系?

通过 Django 中的模型表单保存多对多数据

Django 多对多模板问题

Django内联表单集通过另一个模型在多对多关系中过滤

模板中的多对多通过模型中的 Django 访问条目