您好,
在管理员面板中,我创建了添加产品的表单。表单包括2个内联表单集,因为有一些与产品相关的模型。用户可以创建产品,然后定义该产品的不同属性的变体。我将举例说明这一点。用户有一个3种不同颜色的T恤,并希望以不同的价格添加它们。 T恤是作为具有3种变化的产品而创建的。
class Detail(models.Model):
product = models.ForeignKey('Product')
attribute = models.ForeignKey('Attribute')
value = models.CharField(max_length=500)
class Attribute(models.Model):
name = models.CharField(max_length=300)
class Variant(models.Model):
product = models.ForeignKey(Product)
details = models.ManyToManyField(Detail)
quantity = models.IntegerField()
price = models.DecimalField(max_digits=6, decimal_places=2)
我省略了产品,因为它无关紧要。
class DetailInline(admin.TabularInline):
model = Detail
class VariantInline(admin.StackedInline):
model = Variant
class ProductAdmin(admin.ModelAdmin):
class Meta:
model = Product
inlines = [DetailInline, VariantInline]
这很好用,模型保存得很好,我确实有Variants内联的问题。变量内联显示详细信息对象,但仅显示已保存在数据库中的对象。为了使用户的生活更加轻松,可以在创建Detail对象时将Detail对象添加到Variant内联,因此必须在保存Product之前进行。
我试图通过使用js将条目注入内联,但这是hackish,并且Django没有使用假值来验证formset抛出错误选择了错误的值。
在我写这个问题时,我想到了最后的想法。如果更改了对象的内联形式,则可以创建js,将数据传递给自定义视图,该视图将创建对象并返回结果。我看到的一个问题(旁边感觉不对)是如何通知django创建了新对象,因此它不会引发有关非现有值的错误。
无论如何,我希望有人能理解这个长期的问题。
答案 0 :(得分:2)
我想到的一件事是Knockout.js。
非常善于同时更新DOM中的大量元素,并且您可以使用来自客户端事件的Ajax调用轻松地将新值推回到自定义视图。
有几个框架可以做到这一点,但我认为Knockout是最容易阅读和实现最受欢迎的框架之一,如Backbone,Angular,Ember等。
Django通常会抱怨动态添加的选项,但只要在表单验证时它们存在于服务器端,你理论上 就可以了。
答案 1 :(得分:0)
我决定放弃这个想法,因为它花了很多时间,可能需要更多。我想出的也是相当讨厌的黑客而不是编码。但是不要把这个挂在这里,我会发布任何其他人的提示。
我有两个不同模型的模型作为内联formset,它们都有主模型的外键,其中一个有其他的外键。想法是根据用户输入的值在其中一个内联中创建虚假条目。正如它所代表的那样,使用jQuery与jango一起发布它很容易。所以我做了,但当然Django知道这个模型不存在。解决方法是创建我自己的表单和字段,并像我here一样覆盖clean()方法。
这导致了许多问题,其中一部分原因是我的模型依赖于彼此,而且必须切割一个clean()方法,以便不检查db对象是否存在。除此之外,在现场验证阶段缺乏有关POST数据的信息,因此必须覆盖表单的clean()方法,因为已发布数据。然而,它是不洁净的,因此必须从POST dict中提取并验证。此时我决定停止,因为它越来越复杂,可能导致数据不一致。我猜测下一步将是覆盖ModelAdmin的保存方法,因为创建的对象不在与formset绑定的查询集中,除非在可以完成的路上某个地方。
总结一下,我不得不说,在这一点上,我永远不会这样做,并使用我自己的change_form视图来更好地控制数据流。
TL;博士
创建自定义视图change_form。