在GenericForeignKey模型(CBV)的多个模板中包含表单

时间:2016-01-03 21:09:27

标签: python django forms generics class-based-views

要了解有关Django的更多信息并了解如何尽可能编程为DRY,我建立了一个具有以下功能的小型网站:

  • 发布博客
  • 发布图片
  • 发布书签

在这些APP中的每个对象上,用户都可以发表评论。所以我得到了 带有GenericForeignKey的模型的评论APP。 (正常工作)

我想在博客,图片和书签的详细信息视图中显示评论表单。为了保持干燥,我创建了一个包含标签

@register.inclusion_tag('comments/add_comment.html')
def show_comment_form(obj):
    pk = obj.pk
    content_type = ContentType.objects.get_for_model(obj)
    form = AddCommentForm()

    return {'pk': pk, 'content_type': content_type, 'form': form}

使用以下模板呈现表单:

<form action="{% url 'comments:add' pk content_type %}" method="post">
    <div class="create-blog-container">
        <div class="box-top">{% trans "Leave your comment behind" %}...</div>
        <div class="box-content">
            {% csrf_token %}
            {{ form.as_div }}
        </div>
        <div class="box-footer">
            <input type="submit" class="btn btn-green" value="{% trans 'Add comment' %}" />
        </div>
</form>

添加时

{% show_comment_form blog %} 

在博客的详细信息模板中,它使用正确的参数呈现表单。当我点击SUBMIT按钮时,表单将在以下添加视图中处理(当前只需获取表单,验证并通过服务将其添加到数据库中)。

class Add(LoginRequiredMixin, View):
    model = Comment

    def post(self, *args, **kwargs):
        content_type = self.kwargs.get('content_type')
        pk = self.kwargs.get('pk')
        form = AddCommentForm(self.request.POST)

        if form.is_valid():
            content = form.cleaned_data.get('content')
            comments.services.comment.add(content_type, pk, self.request.user, content)
            messages.add_message(self.request, messages.SUCCESS, _("Your comment has been posted"))
        else:
            print(form.errors)

        return HttpResponseRedirect(reverse('blogs:detail', kwargs={'pk': pk}))

但是这个解决方案不会渲染带有验证错误的表单。我回到基础,创建一个硬编码的&#39;在博客的详细视图中形成,但它不灵活,也不干。

有人可以向我推进正确的方向如何将此表单(通过包含标记或其他建议的方法)转换为干燥且灵活的表单以在通用content_type上发表评论吗?

2 个答案:

答案 0 :(得分:0)

为了完成DRY,我建议(正如你所提到的)实施Django contenttypes的评论并将其与AJAX混合。

根据您的情况,您可以将经过验证的表单传递给包含标记(show_comment_form

@register.inclusion_tag('comments/add_comment.html')
def show_comment_form(obj, form=None):
    pk = obj.pk
    content_type = ContentType.objects.get_for_model(obj)
    form = form or AddCommentForm()

    return {'pk': pk, 'content_type': content_type, 'form': form}

答案 1 :(得分:0)

更改您的包含标记,以便根据对象类型在不同的网址上发布评论。同时更改它,如果当前上下文中已有comment_form,则不会创建新表单。例如:

@register.inclusion_tag('comments/add_comment.html', takes_context=True)
def show_comment_form(context, obj):
    pk = obj.pk
    content_type = ContentType.objects.get_for_model(obj)
    form = context.get('comment_form', AddCommentForm())

    url_id = "%s:%s:comment:add" % (content_type.app_label, content_type.model)

    return {'pk': pk, 'content_type': content_type, 'form': form, url_id}

模板:

{# content_type may be obsolete now #}
<form action="{% url url_id pk content_type %}" method="post">
    <div class="create-blog-container">
        <div class="box-top">{% trans "Leave your comment behind" %}...</div>
        <div class="box-content">
            {% csrf_token %}
            {{ form.as_div }}
        </div>
        <div class="box-footer">
            <input type="submit" class="btn btn-green" value="{% trans 'Add comment' %}" />
        </div>
</form>

创建视图mixin,它将添加到视图处理注释创建(或表单验证),从正常视图为该内容和新mixin创建每个内容类型的新视图,并在单独的URL上注册该视图(名称您在模板标记中创建url_id的网址。

它干燥,灵活,不需要进行大量更改。