Django ManytoMany字段重复,属性错误:'ManyRelatedManager'

时间:2012-02-25 17:56:59

标签: python django django-models django-orm

有三种模式: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'

有什么想法吗?

3 个答案:

答案 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