Django Unique Together (с внешними ключами)
У меня есть ситуация, когда я хочу использовать Meta-опции unique_together
для принудительного применения определенного правила, здесь промежуточная модель:
class UserProfileExtension(models.Model):
extension = models.ForeignKey(Extension, unique=False)
userprofile = models.ForeignKey(UserProfile, unique=False)
user = models.ForeignKey(User, unique=False)
class Meta:
unique_together = (("userprofile", "extension"),
("user", "extension"),
# How can I enforce UserProfile Client
# and Extension to be unique? This obviously
# doesn't work, but is this idea possible without
# creating another FK in my intermediary model
("userprofile__client", "extension"))
и здесь UserProfile:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
client = models.ForeignKey(Client)
Спасибо.
Ответы
Ответ 1
Вы не можете.
Предложение unique_together
непосредственно переводится в уникальный индекс SQL
. И вы можете устанавливать их только в столбцах одной таблицы, а не в комбинации нескольких таблиц.
Вы можете добавить для него валидацию, но просто перезапишите метод validate_unique
и добавьте к нему эту проверку.
Документы: http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.validate_unique
Ответ 2
Моим решением было использовать Django get_or_create. Используя get_or_create, бесполезный get будет возникать, если строка уже существует в базе данных, а строка будет создана, если она не существует.
Пример:
extension = Extension.objects.get(pk=someExtensionPK)
userProfile = UserProfile.objects.get(pk=someUserProfilePK)
UserProfileExtension.objects.get_or_create(extension=extension, userprofile=userProfile)
Ответ 3
Мои 2 цента, дополняющие принятый ответ от @Wolph
Вы можете добавить валидацию для него самостоятельно, просто переписав метод validate_unique и добавив в него эту валидацию.
Это рабочий пример кода, который кто-то может найти полезным.
from django.core.exceptions import ValidationError
class MyModel(models.Model):
fk = models.ForeignKey(AnotherModel, on_delete=models.CASCADE)
my_field = models.CharField(...) # whatever
def validate_unique(self, *args, **kwargs):
super(MyModel, self).validate_unique(*args, **kwargs)
if self.__class__.objects.\
filter(fk=self.fk, my_field=self.my_field).\
exists():
raise ValidationError(
message='MyModel with this (fk, my_field) already exists.',
code='unique_together',
)
Ответ 4
В версиях django 2. 2+ предлагается использовать ограничение и индекс в качестве мета-опции класса модели:
https://docs.djangoproject.com/en/2.2/ref/models/options/#django.db.models.Options.unique_together
https://docs.djangoproject.com/en/2.2/ref/models/options/#django.db.models.Options.constraints