Уникальный сдерживающий фактор Django?

Использование Django 1.5.1. Python 2.7.3.

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

  • PicklingError: не может pickle <class 'decimal.Decimal'>: это не тот же объект, что и decimal.Decimal
  • Django admin, пользовательское сообщение об ошибке?
  • Невозможно кодировать / декодировать вывод pprint
  • Ошибка конфигурации Django DB «Неправильная настройка»
  • Почему Django создает миграцию для изменений help_text и verbose_name?
  • Не удалось войти на сайт ASP.NET с модулем запросов Python
  • foreign_key = models.ForeignKey("self", null=True, default=None) slug = models.SlugField(max_length=40, unique=False) class Meta: unique_together = ("foreign_key", "slug") 

    Я даже проверил описание таблицы в Postgres (9.1), и ограничение было помещено в таблицу базы данных.

     -- something like "table_name_foreign_key_id_slug_key" UNIQUE CONSTRAINT, btree (foreign_key_id, slug) 

    Тем не менее, я все еще мог сохранить в таблице базы данных foreign_key из None / null и дублировать строки.

    Например,

    Я мог бы вводить и сохранять

     # model objects with slug="python" three times; all three foreign_key(s) # are None/null because that is their default value MO(slug="python").save() MO(slug="python").save() MO(slug="python").save() 

    Итак, после использования unique_together, почему я могу по-прежнему вводить три одинаково ценные строки?

    Я просто догадываюсь прямо сейчас, что это может иметь отношение к значению по умолчанию None для поля foreign_key, потому что перед unique_together, когда у меня только что было уникальное значение = True на slug, все работало нормально. Итак, если это так, то какое значение по умолчанию должно иметь значение, указывающее нулевое значение, но также поддерживающее уникальное ограничение?

  • Django: изменение моделей без очистки всех данных?
  • Как получить текущий экземпляр модели из inlineadmin в Django
  • PLE-кодировщик jpeg недоступен
  • Django Rest Framework и JSONField
  • PIL Image.resize () не изменяет размер изображения
  • Использование scipy.stats.stats в django после развертывания
  • 4 Solutions collect form web for “Уникальный сдерживающий фактор Django?”

    В Postgresql NULL не равно никакому другому NULL . Поэтому созданные вами строки не совпадают (с точки зрения Postgres).

    Обновить

    У вас есть несколько способов справиться с этим:

    • Запретить значение Null для внешнего ключа и использовать значение по умолчанию
    • Переопределите метод save вашей модели, чтобы проверить, нет ли такой строки
    • Изменить стандарт SQL 🙂

    Добавьте в свою модель clean метод, чтобы вы могли редактировать существующую строку.

     def clean(self): queryset = MO.objects.exclude(id=self.id).filter(slug=self.slug) if self.foreign_key is None: if queryset.exists(): raise ValidationError("A row already exists with this slug and no key") else: if queryset.filter(foreign_key=self.foreign_key).exists(): raise ValidationError("This row already exists") 

    Остерегайтесь, clean (или full_clean ) не вызывается методом save по умолчанию.

    NB: если вы поместите этот код в метод save , формы обновления (например, в админе) не будут работать: у вас будет ошибка трассировки из-за исключения ValidationError .

    Просто вручную создайте вторичный индекс в поле slug , но только для значений NULL в foreign_key_id :

     CREATE INDEX table_name_unique_null_foreign_key ON table_name (slug) WHERE foreign_key_id is NULL 

    Обратите внимание, что Django не поддерживает это, поэтому без пользовательской проверки формы / модели вы получите чистый IntegrityError / 500.

    Возможный дубликат создания уникального ограничения с нулевыми столбцами

    Как сказал hobbyte: «В Postgresql NULL не равно никому другому NULL. Поэтому создаваемые вами строки не совпадают (с точки зрения Postgres)».

    Другим возможным способом решения этой проблемы является добавление пользовательской проверки на уровне представления в методе form_valid.

    В views.py:

     def form_valid(self, form): --OTHER VALIDATION AND FIELD VALUE ASSIGNMENT LOGIC-- if ModelForm.objects.filter(slug=slug,foreign_key=foreign_key: form.add_error('field', forms.ValidationError( _("Validation error message that shows up in your form. "), code='duplicate_row', )) return self.form_invalid(form) 
    Python - лучший язык программирования в мире.