Django unique_together与可为空的ForeignKey [英] Django unique_together with nullable ForeignKey

查看:168
本文介绍了Django unique_together与可为空的ForeignKey的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Sqlite的开发机中使用Django 1.8.4,并且具有以下模型:

I'm using Django 1.8.4 in my dev machine using Sqlite and I have these models:

class ModelA(Model):
    field_a = CharField(verbose_name='a', max_length=20)
    field_b = CharField(verbose_name='b', max_length=20)

    class Meta:
        unique_together = ('field_a', 'field_b',)


class ModelB(Model):
    field_c = CharField(verbose_name='c', max_length=20)
    field_d = ForeignKey(ModelA, verbose_name='d', null=True, blank=True)

    class Meta:
        unique_together = ('field_c', 'field_d',)

我已经进行了适当的迁移,并在Django Admin中注册了它们.因此,使用管理员我已经完成了以下测试:

I've run proper migration and registered them in the Django Admin. So, using the Admin I've done this tests:

  • 我能够创建ModelA记录,而Django禁止我创建重复的记录-符合预期!
  • 当field_b不为空时,我无法创建相同的ModelB记录
  • 但是,当使用field_d为空时,我能够创建相同的ModelB记录

我的问题是:如何为可为空的ForeignKey应用unique_together?

My question is: How do I apply unique_together for nullable ForeignKey?

我找到的关于该问题的最新答案有5年了...我确实认为Django已经发展并且问题可能并不相同.

The most recent answer I found for this problem has 5 year... I do think Django have evolved and the issue may not be the same.

推荐答案

更新:我的答案的上一版功能正常,但设计不好,该版本考虑了一些评论和其他答案

UPDATE: previous version of my answer was functional but had bad design, this one takes in account some of the comments and other answers.

在SQL中,NULL不等于NULL.这意味着,如果您有两个field_d == None and field_c == "somestring"不相等的对象,则可以创建两个对象.

In SQL NULL does not equal NULL. This means if you have two objects where field_d == None and field_c == "somestring" they are not equal, so you can create both.

您可以覆盖Model.clean来添加支票:

You can override Model.clean to add your check:

class ModelB(Model):
    #...
    def validate_unique(self, exclude=None):
        if ModelB.objects.exclude(id=self.id).filter(field_c=self.field_c, \
                                 field_d__isnull=True).exists():
            raise ValidationError("Duplicate ModelB")
        super(ModelB, self).validate_unique(exclude)

如果在表格之外使用,则必须调用full_cleanvalidate_unique.

If used outside of forms you have to call full_clean or validate_unique.

尽管如此,还是要小心处理比赛状况.

Take care to handle the race condition though.

这篇关于Django unique_together与可为空的ForeignKey的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆