You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 1.8:如何实现Char字段区分大小写的联合唯一约束

解决Django 1.8联合唯一约束允许大小写不同条目保存的问题

问题根源

你用unique_together设置了联合唯一约束,但很多数据库(比如MySQL)默认的字符集排序规则是大小写不敏感的(比如utf8_general_ci),所以数据库会把central和Central当成同一个值,导致保存时触发重复报错。

两种解决方案

方案1:修改字段的数据库排序规则(最靠谱)

直接给room_name字段指定大小写敏感的排序规则,让数据库层面区分不同大小写的字符串,同时保留联合唯一约束。

修改models.py里的room_name字段:

room_name = models.CharField(
    verbose_name=_('room_name'),
    max_length=100,
    null=False,
    blank=False,
    default="",
    db_collation='utf8_bin'  # MySQL用这个,PostgreSQL换成C或POSIX
)
  • MySQL选utf8_bin:按字节严格比较,大小写完全区分。
  • PostgreSQL选C或POSIX:这两个排序规则是大小写敏感的。

改完后执行迁移:

python manage.py makemigrations
python manage.py migrate

方案2:模型层加自定义验证(辅助用)

如果暂时动不了数据库排序规则,可以在模型的clean方法里加自定义检查,但这种方法防不了并发写入的冲突,只能作为补充。

修改Tags模型(注意补全继承和元组格式):

from django.core.exceptions import ValidationError

class Tags(models.Model):  # 原代码漏了继承models.Model,必须加上
    Rooms = models.ForeignKey(Rooms, related_name='rooms')
    room_name = models.CharField(
        verbose_name=_('room_name'),
        max_length=100,
        null=False,
        blank=False,
        default="",
    )

    def clean(self):
        # 检查同Rooms下是否已有完全匹配(区分大小写)的room_name
        exists = Tags.objects.filter(
            Rooms=self.Rooms,
            room_name__exact=self.room_name
        ).exclude(pk=self.pk).exists()
        if exists:
            raise ValidationError("Tags with this Rooms and Aws room_name already exists.")
        super(Tags, self).clean()

    class Meta:
        unique_together = (('Rooms', 'room_name'),)  # 原代码少了逗号,得补成正确的元组格式

注意点

  1. 优先用方案1,从数据库层面解决问题最彻底,方案2只能做辅助验证。
  2. 执行迁移前记得备份数据库,避免数据出问题。
  3. 如果用SQLite,默认也是大小写不敏感的,需要调整连接参数或者用COLLATE BINARY来实现区分大小写。

内容的提问来源于stack exchange,提问作者Vaibhav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:52:39