有三种模式:House_Type,House_Option和Order
House_Type模型有2个字段:id和name
House_Option有3个字段:id,name和type其中type是链接到House_Type的外键。
最后,Order包含许多字段,其中一个字段是名为“choice”的ManytoMany字段,链接到House_Option
这样做的方式是House_Type有不同类型的房屋:例如,公寓,公寓,独立式住宅,半独立屋等。
House_Option为每种类型提供了所有可能的选项:例如,对于“公寓”类型,您有选项1位于街道X,选项2位于街道Y等。
在订单模型中,用户必须为每个房屋“类型”选择一个“选项”。所以他们必须选择一个公寓选项,一个房屋选项等。因为这是一个ManytoMany字段,这是可能的。但是我的问题是:例如,如何阻止用户选择两个“公寓”选项。如何将它们限制为仅选择一个(或不选择)?
我试图在Order模型中创建一个def(clean):
def clean(self):
if self.choice.house_option_type.count() > 1:
raise ValidationError('Custom Error Message')
然而,这会返回属性错误:'ManyRelatedManager'对象没有属性'house_option_type'
有什么想法吗?
答案 0 :(得分:1)
通过明确定义的模型管理ManyToMany关系,其中两个外键对于每个订单都是唯一的。您可以使用unique_together对相同类型的多对多关系强加唯一性约束。
class House_Type(models.Model):
name = models.CharField(...)
class House_Option(models.Model):
name = models.CharField(...)
type = models.ForeignKey(House_Type)
class Order(models.Model):
...
choices = models.ManyToManyField(House_Option, through='Order_options')
...
class Order_options(models.Model):
class Meta:
unique_together = ('order', 'option__type')
...
order = models.ForeignKey(Order)
option = models.ForeignKey(House_Option)
...
编辑,更新语法和更正。
是的,看起来unique_together被应用为表上的DB约束,并且不能跨表工作。所以忘掉上面的方法。
我仍然认为以下内容应该有效:
如果您只是简单地覆盖Order_options上的validate_unique并自己实现唯一性逻辑,那么在小心如何处理现有和不存在的情况时它应该有效。
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
class Order_options(models.Model):
...
def validate_unique(self, exclude = None):
super(Order_options, self).validate_unique(exclude)
options = { 'order__id' : self.order.id, 'option__type' : 'self.option.type' }
objs = Order_options.objects.exclude(id=self.id) if self.id else Order_options.objects
if objs.filter(**options).exists():
raise ValidationError({NON_FIELD_ERRORS: ['Error: {0} option type already exists'.format(self.option.type)]})
...
答案 1 :(得分:0)
如果要计算某种类型的选择数量,可以这样做:
if self.choice.filter(type__name = 'condo').count() > 1:
raise ValidationError("Multiple condos selected!");
答案 2 :(得分:0)
我认为Django不允许使用复合主键,因此(也不会)复合外键约束(对主键或唯一键)本身可以解决问题。
该功能的票证有活动:Ticket #373: Add support for multiple-column primary keys