【问题标题】:Edit django 'through' model inline in wagtail admin?在 wagtail 管理员中内联编辑 django 'through' 模型?
【发布时间】:2018-11-27 17:59:22
【问题描述】:

[用更好的代码示例编辑]

根据标题,我试图允许在 Wagtail 中对一个非常简单的商店页面进行内联编辑(可能会将其变成一个简单的包):

具有以下型号:

class Product(ClusterableModel):
    page = ParentalKey(MiniShopPage, on_delete=models.CASCADE, related_name='shop_products')
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=2500)
    downloadable = models.BooleanField()
    price = models.FloatField()
    image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

    # define the content_panels
    panels = [
        FieldPanel('name'),
        FieldPanel('description'),
        FieldPanel('downloadable'), 
        FieldPanel('price'), 
        ImageChooserPanel('image'),
    ]

class Order(TimeStampedModel, ClusterableModel):
    '''
    Example of use outside of the admin:
    p = Product.objects.first()
    order = Order.objects.create(client_email='someone@hotmail.com', gift_amount=0)
    quantities = ProductInOrderCount(product=p, order=order, quantity=2)
    quantities.save()

    for itm in order.productinordercount_set.all():                          
        print(itm.quantity)
    '''
    is_fulfilled = models.BooleanField(default=False)
    is_paid_for = models.BooleanField(default=False)
    client_email = models.EmailField(blank=False)
    gift_amount = models.PositiveIntegerField()
    # products = M2MTHROUGH
    # the through model stores the quantity
    products = models.ManyToManyField(Product, through='ProductInOrderCount')

    content_panels = [
        FieldPanel('is_fulfilled'),
        FieldPanel('is_paid_for'),
        FieldPanel('client_email'),
        FieldPanel('gift_amount'),
        InlinePanel('products'),
    ]

    class OrderModelAdmin(ModelAdmin):
        model = Order
        menu_label = 'Orders'
        ...

    modeladmin_register(OrderModelAdmin)

class ProductInOrderCount(Orderable):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

棘手的是我得到了错误Cannot set values on a ManyToManyField which specifies an intermediary model. 或者我根本没有得到一个内联面板,而是一个选择。

我假设是这种情况,因为 create 和 add 方法不能通过模型​​起作用,是这样吗?

如果可以,您能否建议一种我可以重写应用程序的方法,以便我可以在管理员和代码中创建带有产品的订单?

【问题讨论】:

  • 我认为您需要分享更多代码才能使这个问题有意义 - 您提供的代码中没有任何 ManyToManyFields。
  • 你是对的。我调整了 M2Mfields 以匹配您在此处给出的建议:*.com/questions/50209851/… 但也许这并不适用于这里?
  • 好吧,我现在更困惑了。您是说上面的代码 sn-p 是根据*.com/questions/50209851/… 更改模型定义以避免ManyToManyField 的结果,但您仍然收到ManyToManyField 错误?请发帖Minimal, Complete, and Verifiable example
  • 我认为您的评论和我的编辑相互交叉@gasman 道歉。你是对的,我尝试了两种方法,我重写了问题以反映一个问题而不是两个问题。

标签: django wagtail


【解决方案1】:

InlinePanel 仅适用于一对多 ParentalKey 关系,不适用于 ManyToManyField。这应该不是问题,因为ParentalKey 非常适合这种情况:

  • ManyToManyFieldthrough 模型实际上只是两个背靠背的一对多关系;
  • ParentalKey 专为与父模型密切相关的关系而设计,因为它们始终被编辑、验证并保存为一个单元。 ProductInOrderCountOrder 之间的关系是这样的(ProductInOrderCount 记录在概念上是 Order 的一部分),但ProductInOrderCountProduct 之间的关系却不是(ProductInOrderCount 不是一部分Product)。

这会给你一个模型定义,如:

class ProductInOrderCount(Orderable):
    order = ParentalKey(Order, on_delete=models.CASCADE, related_name='ordered_products')
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

然后您的Order 模型可以有一个InlinePanel('ordered_products'),并且可以省略products 字段。

【讨论】:

  • 谢谢!我花了一段时间才发现我现在必须使用panels。很好的答案。快速跟进:例如,modeladmin 为何在使用 list_display 时将 ordered_products 显示为 core.ProductInOrderCount.None