Дублируются поля Django ManytoMany, ошибка атрибута: «ManyRelatedManager» - PullRequest
1 голос
/ 25 февраля 2012

Существует три модели: House_Type, House_Option и Order

Модель House_Type имеет 2 поля: идентификатор и имя

House_Option имеет 3 поля: идентификатор, имя и тип, где тип - это внешний ключ, связанный с House_Type.

и, наконец, Order состоит из множества полей, одним из которых является поле ManytoMany, называемое "choice", которое ссылается на House_Option

Способ, которым это работает, состоит в том, что House_Type имеет разные «типы» домов: например, квартира, квартира, особняк, полуотдельный дом и т. Д.

House_Option имеет все возможные параметры для каждого типа: например, для типа «квартира» у вас есть вариант 1, расположенный на улице X, вариант 2, расположенный на улице Y и т. Д.

В модели заказа пользователь должен выбрать один «вариант» каждого «типа» дома. Поэтому они должны выбрать один вариант квартиры, один вариант дома и т. Д. Поскольку это поле ManytoMany, это возможно. Однако мой вопрос: как я могу запретить пользователю выбирать ДВА варианта «квартиры», например. Как мне ограничить их выбором только одного (или ни одного) из каждого?

Я пытался создать def (clean) в модели Order:

        def clean(self):
            if self.choice.house_option_type.count() > 1:
                    raise ValidationError('Custom Error Message')

Однако это возвращает ошибку атрибута: у объекта «ManyRelatedManager» нет атрибута «house_option_type»

Есть идеи?

Ответы [ 3 ]

1 голос
/ 25 февраля 2012

Управление отношениями 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 применяется как ограничение БД для таблицы и не будет работать между таблицами.Так что забудьте о вышеописанном подходе.

Тем не менее, я думаю, что должно работать следующее:

Если вы просто переопределите validate_unique для Order_options и самостоятельно реализуете логику уникальности, при этом будьте осторожныдля обработки существующего и несуществующего случая это должно работать.

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)]})
    ...
0 голосов
/ 25 февраля 2012

Я думаю, что Django не разрешает составные первичные ключи и (таким образом) ни составные ограничения внешнего ключа (ни первичному, ни уникальному ключу), которые могли бы решить проблему изначально.

Существует билет для этой функции, который выполняет следующие действия: Билет № 373: добавлена ​​поддержка первичных ключей из нескольких столбцов

0 голосов
/ 25 февраля 2012

Если вы хотите посчитать количество вариантов типа, вы можете сделать это:

if self.choice.filter(type__name = 'condo').count() > 1:
  raise ValidationError("Multiple condos selected!");
...