Python 使ArrayField的base_字段对于Django中的表是唯一的 球门
以下内容应引发ValidationError 简而言之,如果模型的ArrayField中的元素与数据库表中的元素匹配,则应引发ValidationError 失败的解决方案 不要提到unique关键字,所以我尝试了几种方法,这些都是最少的代码示例 在运行makemigrations和migrate之后,将unique=True添加到base_字段似乎根本不起任何作用 我尝试只向ArrayField添加unique=True。如果数组完全相同,Django将引发错误Python 使ArrayField的base_字段对于Django中的表是唯一的 球门,python,django,Python,Django,以下内容应引发ValidationError 简而言之,如果模型的ArrayField中的元素与数据库表中的元素匹配,则应引发ValidationError 失败的解决方案 不要提到unique关键字,所以我尝试了几种方法,这些都是最少的代码示例 在运行makemigrations和migrate之后,将unique=True添加到base_字段似乎根本不起任何作用 我尝试只向ArrayField添加unique=True。如果数组完全相同,Django将引发错误 # models.py ...
# models.py
...
class MyModel(models.Model)
title = ArrayField(
models.CharField(max_length=255),
unique=True,
)
当我想到这一点时,上面的话是有道理的。然后我尝试将unique=True添加到base_字段和ArrayField,但行为没有改变。我运行makemigrations和migrate
TL;博士
我是否可以使用unique=True使以下内容引发错误,或者我是否需要编写自己的验证器
>>> m1 = MyModel(names=['name1'])
>>> m2 = MyModel(names=['name1', 'name2'])
>>> m1.save()
>>> m2.save()
django.core.exceptions.ValidationError: ...
这是我最后所做工作的一个最简单的例子
# models.py
...
UNIQUE_ARRAY_FIELDS = ('name',)
class MyManager(models.Manager):
def prevent_duplicates_in_array_fields(self, model, array_field):
def duplicate_check(_lookup_params):
fields = self.model._meta.get_fields()
for unique_field in UNIQUE_ARRAY_FIELDS:
unique_field_index = [getattr(field, 'name', '') for field in fields]
try:
# if model doesn't have the unique field, then proceed to the next loop iteration
unique_field_index = unique_field_index.index(unique_field)
except ValueError:
continue
all_items_in_db = [item for sublist in self.values_list(fields[unique_field_index].name).exclude(**_lookup_params) for item in sublist]
all_items_in_db = [item for sublist in all_items_in_db for item in sublist]
if not set(array_field).isdisjoint(all_items_in_db):
raise ValidationError('{} contains items already in the database'.format(array_field))
if model.id:
lookup_params = {'id': model.id}
else:
lookup_params = {}
duplicate_check(lookup_params)
...
class MyModel(models.Model):
name = ArrayField(
models.CharField(max_length=255),
default=list
)
objects = MyManager()
...
def save(self, *args, **kwargs):
self.full_clean()
MyModel.objects.prevent_duplicates_in_array_fields(self, self.name)
super().save(*args, **kwargs)
...
# models.py
...
class MyModel(models.Model)
title = ArrayField(
models.CharField(max_length=255),
unique=True,
)
# shell_plus from Django-extensions
>>> m1 = MyModel(names=['name1'])
>>> m2 = MyModel(names=['name1'])
>>> m1.save()
>>> m2.save()
django.core.exceptions.ValidationError: ...
>>> m3 = MyModel(names=['name1', 'name2'])
>>> m3.save()
# no error raised
class MyModel(models.Model)
title = ArrayField(
models.CharField(max_length=255, unique=True),
unique=True,
)
# shell_plus from Django-extensions
>>> m1 = MyModel(names=['name1'])
>>> m2 = MyModel(names=['name1'])
>>> m1.save()
>>> m2.save()
django.core.exceptions.ValidationError: ...
>>> m3 = MyModel(names=['name1', 'name2'])
>>> m3.save()
# no error raised
>>> m1 = MyModel(names=['name1'])
>>> m2 = MyModel(names=['name1', 'name2'])
>>> m1.save()
>>> m2.save()
django.core.exceptions.ValidationError: ...
# models.py
...
UNIQUE_ARRAY_FIELDS = ('name',)
class MyManager(models.Manager):
def prevent_duplicates_in_array_fields(self, model, array_field):
def duplicate_check(_lookup_params):
fields = self.model._meta.get_fields()
for unique_field in UNIQUE_ARRAY_FIELDS:
unique_field_index = [getattr(field, 'name', '') for field in fields]
try:
# if model doesn't have the unique field, then proceed to the next loop iteration
unique_field_index = unique_field_index.index(unique_field)
except ValueError:
continue
all_items_in_db = [item for sublist in self.values_list(fields[unique_field_index].name).exclude(**_lookup_params) for item in sublist]
all_items_in_db = [item for sublist in all_items_in_db for item in sublist]
if not set(array_field).isdisjoint(all_items_in_db):
raise ValidationError('{} contains items already in the database'.format(array_field))
if model.id:
lookup_params = {'id': model.id}
else:
lookup_params = {}
duplicate_check(lookup_params)
...
class MyModel(models.Model):
name = ArrayField(
models.CharField(max_length=255),
default=list
)
objects = MyManager()
...
def save(self, *args, **kwargs):
self.full_clean()
MyModel.objects.prevent_duplicates_in_array_fields(self, self.name)
super().save(*args, **kwargs)
...