我想使用此代码:
constraints = [ models.UniqueConstraint(fields=['name', 'app'], name='unique_booking'), ]
但名称和应用程序(两者)不应检查区分大小写,因此“FOo”和“fOO”应标记为同一应用程序。怎么办?
有 2 个选项:
如果您使用的 postgresql 和 Django 版本高于 2.0 - 您可以使用 CICharField 或 CITextField 字段。
class DemoModelCI(models.Model):
class Meta(object):
constraints = [
UniqueConstraint(fields=['app', 'name'], name='unique_booking_ci')
]
name = CICharField(null=False, default=None, max_length=550, blank=False)
app = CICharField(null=False, default=None, max_length=550, blank=False)
如果您使用多种语言,则使用 CI 字段会存在一些限制。使用前请阅读文档。
要使用 CIText,您需要在数据库上创建扩展。您可以在 Django 迁移中完成此操作:
from django.db import migrations
from django.contrib.postgres.operations import CITextExtension
class Migration(migrations.Migration):
dependencies = [
('storage', '0037_previous_migration'),
]
operations = [
CITextExtension(),
]
为每个不区分大小写的字段创建 2 个字段。 第一个用于显示并保持文本的原始大小写。第二个将以小写形式保存,用于检查唯一性。
class DemoModel(models.Model):
class Meta(object):
constraints = [
UniqueConstraint(fields=['name_compare', 'app_compare'], name='unique_booking')
]
name_display = models.TextField(null=False, default=None, blank=False, max_length=550)
name_compare = models.TextField(null=False, default=None, blank=False, max_length=550)
app_display = models.TextField(null=False, default=None, blank=False, max_length=550)
app_compare = models.TextField(null=False, default=None, blank=False, max_length=550)
def save(self, *args, **kwargs):
# If explicitly received "compare" name - make sure it is casefolded
if self.name_compare:
self.name_compare = self.name_compare.casefold()
# If didn't get "compare" name - use the display name and casefold it
elif self.name_display:
self.name_compare = self.name_display.casefold()
# If explicitly received "compare" name - make sure it is casefolded
if self.app_compare:
self.app_compare = self.app_compare.casefold()
# If didn't get "compare" name - use the display name and casefold it
elif self.app_display:
self.app_compare = self.app_display.casefold()
return super(DemoModel, self).save(*args, **kwargs)
根据此票,实现不区分大小写的唯一约束所需的这些更改已在 Django 代码库中实现(在 GitHub 中找到代码),并且代码当前为(截至 2021 年 4 月 29 日)在主分支中。但最新的 Django 版本3.2中没有这些变化。也许您应该能够在
Django >= 3.3
中使用它们。那么代码应该是这样的:
# not implemented in Django <= 3.2
models.UniqueConstraint(fields=[Lower('name'), Lower('app')], name='unique_booking', expression='')
同时,您可以尝试通过在保存时小写值来存储它们:
class YourModel():
def save(self, *args, **kwargs):
self.name = self.name.lower()
self.app = self.app.lower()
super().save(*args, **kwargs)
CIText
字段。
对于使用 Django 4.0 及更高版本的任何人,在 UniqueConstraint 表达式 的帮助下,您可以像这样向模型添加 Meta 类:
class Meta:
constraints = [
models.UniqueConstraint(
'book',
Lower('app'),
name='unique_booking'
),
]
对于 Django 版本 >= 4.0,这将起作用 https://docs.djangoproject.com/en/4.0/releases/4.0/#function-unique-constraints.
from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import Lower
class MyModel(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Meta:
constraints = [
UniqueConstraint(
Lower('first_name'),
Lower('last_name').desc(),
name='first_last_name_unique',
),
]
我尝试过,它对我有用。