显示Django模型的查询集的一系列内联表单 [英] Displaying a series of inline forms for a queryset of Django models

查看:41
本文介绍了显示Django模型的查询集的一系列内联表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有这样的模型:

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=255)

class Book(models.Model):
    publisher = models.ForeignKey('Publisher')
    title = models.CharField(max_length=255)

class BookImage(models.Model):
    book = models.ForeignKey('Book')
    file = models.ImageField(max_length=255)
    title = models.CharField(max_length=255)

我要创建一个页面,该页面:

I want to make a page that:

  • 列出特定发行商的所有图书(例如 Book.objects.filter(publisher = 34)).
  • 对于每本书,显示任何现有的BookImage.
  • 每本书显示3种表单,用于上传和添加新的BookImage.
  • 一个提交按钮.

我不需要编辑图书"的详细信息-表单仅用于BookImages.

I don't need to edit the details of the Books - the forms are only for BookImages.

我与 modelformset_factory inlineformset_factory 纠缠在一起,但都不对...我觉得我在把事情弄得太复杂了.有什么想法吗?

I'm getting in a tangle with modelformset_factory and inlineformset_factory and none of it is right... I feel like I'm making things too complicated. Any ideas?

更新:

有些事情我已经尝试过朝正确的方向前进,但我不确定它们是否有帮助:

Here are some things I've tried that head in a sort-of-right direction, but I'm not sure they help:

# Forms for multiple Books for this Publisher
# But I don't think I need forms for the Books in my situation?
my_publisher = Publisher.objects.get(pk=37)
BookFormSet = modelformset_factory(Book, fields=(['title']))
formset = BookFormSet(queryset=Book.objects.filter(publisher=my_publisher))

# Multiple BookImages on one Book:
# Good, but how do I do this for all of a Publisher's Books, and display existing BookImages?
my_book = Book.objects.get(pk=42)
BookImageFormSet = inlineformset_factory(Book, BookImage, fields=('file', 'title'))
formset = BookImageFormSet(instance=my_book)

推荐答案

我找到了如何执行此操作的示例

I found an example of how to do this in this blog post. Below I've rewritten the example using my Publisher/Book/BookImage models, and generic class-based views, for future reference.

该表格还允许用户编辑图书的书名,这并不是我最初想要的,但这似乎比 not 容易.内联Book表格每个都至少需要一个字段,因此我们也可以包括Book的标题.

The form also allows the user to edit the titles of the Books, which wasn't what I originally wanted, but this seems easier than not doing it; the inline Book forms require at least one field each, so we may as well include the Book's title.

此外,要了解其工作原理,我使用此代码整理了一个小Django项目,并提供了更多详细信息,

Also, to see how this worked, I've put together a small Django project using this code, and a little more detail, available on GitHub.

models.py :

models.py:

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=255)

class Book(models.Model):
    title = models.CharField(max_length=255)
    publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE)

class BookImage(models.Model):
    book = models.ForeignKey('Book', on_delete=models.CASCADE)
    image = models.ImageField(max_length=255)
    alt_text = models.CharField(max_length=255)

forms.py :

forms.py:

from django.forms.models import BaseInlineFormSet, inlineformset_factory
from .models import Publisher, Book, BookImage

# The formset for editing the BookImages that belong to a Book.
BookImageFormset = inlineformset_factory(
                                        Book,
                                        BookImage,
                                        fields=('image', 'alt_text')),
                                        extra=1)

class BaseBooksWithImagesFormset(BaseInlineFormSet):
    """
    The base formset for editing Books belonging to a Publisher, and the
    BookImages belonging to those Books.
    """
    def add_fields(self, form, index):
        super().add_fields(form, index)

        # Save the formset for a Book's Images in a custom `nested` property.
        form.nested = BookImageFormset(
                                instance=form.instance,
                                data=form.data if form.is_bound else None,
                                files=form.files if form.is_bound else None,
                                prefix='bookimage-%s-%s' % (
                                    form.prefix,
                                    BookImageFormset.get_default_prefix()),
                            )

    def is_valid(self):
        "Also validate the `nested` formsets."
        result = super().is_valid()

        if self.is_bound:
            for form in self.forms:
                if hasattr(form, 'nested'):
                    result = result and form.nested.is_valid()

        return result

    def save(self, commit=True):
        "Also save the `nested` formsets."
        result = super().save(commit=commit)

        for form in self.forms:
            if hasattr(form, 'nested'):
                if not self._should_delete_form(form):
                    form.nested.save(commit=commit)

        return result

# This is the formset for the Books belonging to a Publisher and the
# BookImages belonging to those Books.
PublisherBooksWithImagesFormset = inlineformset_factory(
                                        Publisher,
                                        Book,
                                        formset=BaseBooksWithImagesFormset,
                                        fields=('title',),
                                        extra=1)

views.py :

views.py:

from django.http import HttpResponseRedirect
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin

from .forms import PublisherBooksWithImagesFormset
from .models import Publisher, Book, BookImage

class PublisherUpdateView(SingleObjectMixin, FormView):
    model = Publisher
    success_url = 'publishers/updated/'
    template_name = 'publisher_update.html'

    def get(self, request, *args, **kwargs):
        # The Publisher whose Books we're editing:
        self.object = self.get_object(queryset=Publisher.objects.all())
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        # The Publisher whose Books we're editing:
        self.object = self.get_object(queryset=Publisher.objects.all())
        return super().post(request, *args, **kwargs)

    def get_form(self, form_class=None):
        "Use our formset of formsets, and pass in the Publisher object."
        return PublisherBooksWithImagesFormset(
                            **self.get_form_kwargs(), instance=self.object)

    def form_valid(self, form):            
        form.save()
        return HttpResponseRedirect(self.get_success_url())

templates/publisher_update.html :

templates/publisher_update.html:

{% extends 'base.html' %}

{% block content %}

  <form action="" method="post" enctype="multipart/form-data">

    {% for hidden_field in form.hidden_fields %}
      {{ hidden_field.errors }}
      {{ hidden_field }}
    {% endfor %}

    {% csrf_token %}

    {{ form.management_form }}
    {{ form.non_form_errors }}

    {% for book_form in form.forms %}
      {# Output a Book form. #}

      {% for hidden_field in book_form.hidden_fields %}
        {{ hidden_field.errors }}
      {% endfor %}

      <table>
        {{ book_form.as_table }}
      </table>

      {# Check if our `nested` property exists, with BookImage forms in it. #}
      {% if book_form.nested %}
          {{ book_form.nested.management_form }}
          {{ book_form.nested.non_form_errors }}

            {% for bookimage_form in book_form.nested.forms %}
              {# Output the BookImage forms for this Book. #}

              {% for hidden_field in bookimage_form.hidden_fields %}
                {{ hidden_field.errors }}
              {% endfor %}

              <table>
                {{ bookimage_form.as_table }}
              </table>
            {% endfor %}
      {% endif %}

    {% endfor %}

    <input type="submit" value="Update books">
  </form>

{% endblock content %}

这篇关于显示Django模型的查询集的一系列内联表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆