使用unique_for_date

时间:2017-07-09 20:49:54

标签: python django django-models

我正在尝试使用unique_for_date选项来阻止在同一日期创建具有相同slug的多个帖子。但它似乎根本不起作用:我仍然可以从shell和管理仪表板创建具有相同slug的帖子。 ModelForm也是如此。 我的models.py:

class Post(models.Model):

    STATUS_CHOICES = (
        ('draft', 'Draft'),
        ('published', 'Published'),
        ('suspended', 'Suspended'),
    )

    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique_for_date='created')
    status = models.CharField(max_length=15,
                              choices=STATUS_CHOICES,
                              default='draft')
    content = models.TextField(max_length=200000, blank=True)
    # dates
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    publish = models.DateTimeField(default=timezone.now)

我通过将auto_now_add=True更改为default=timezone.now找到了某种解决问题的方法,但它只在通过django admin创建对象时显示错误 - 从shell或表单创建对象时仍然没有错误。

更新:我知道使用auto_now_add设置editable = False会导致django跳过字段验证,但它无法解释为什么即使使用default=timezone.now

它也会跳过验证

更新2 :由于某种原因,unique_for_date仅适用于django-admin仪表板表单(至少在我的情况下)。为了获得与其他表单相同的效果,我已经覆盖了模型的clean_fields方法(强制django验证唯一字段):

def clean_fields(self, exclude=None):
    super().clean_fields(exclude=exclude)
    self.validate_unique()

4 个答案:

答案 0 :(得分:2)

我认为您createdDateTimeField,所以它也在考虑时间。尝试将其更改为DateField

答案 1 :(得分:1)

unique_for_date约束在Django管理员表单级别强制执行,但不在数据库级别强制执行。如果你看一下文档,

  

这是在模型验证期间由Model.validate_unique()强制实施的,但不是在数据库级别强制执行。如果任何unique_for_date约束涉及不属于ModelForm的字段(例如,如果其中一个字段在exclude中列出或具有editable = False),Model.validate_unique()将跳过该特定约束的验证。

如果您需要强制执行数据库级别唯一约束,那么我可能会建议您在unique_together类中添加Meta约束。此外,如果您愿意,可能需要将created字段更改为DateField()

答案 2 :(得分:1)

感谢您发布该问题,我遇到了完全相同的问题(奇怪的是,代码大致相同——我们是否遵循 same book?:))。已经三年了,这个问题已经有了一些变化,但你是否有机会使用 WSL 进行开发?

我也将 unique_for_date 设置为 slug 的参数,并且本地版本的管理界面按预期运行,即。 e.它不允许在同一日期出现两个相同的 slug。有趣的是,在 WSL 版本中,可以为任何给定日期创建多个相同的 slug,即使代码与 Windows 版本相同。

我在 WSL 版本的相同代码中遇到了另一个莫名其妙的错误(tl;dr: 本地版本再次按预期工作):我正在显示博客列表使用 django 的面包和黄油 HTML templates 以节略形式发布。单击列表条目的标题(使用 canonical url 中描述的 urlpattern path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail)the Django documentation)应该打开其未删节的详细视图,但是,尽管列表显示正确,详细视图的条目不能显示是因为系统找不到条目并抛出 404 错误。我正在传递 'published' 日期来构建规范网址;虽然可以使用 'published__year' 检索包含 slug 的帖子,但 'published__month''published__day' 都不会返回任何内容(当我保存测试条目时,日期格式正确)。同样,完全相同的代码在本地版本(即 WSL 之外)中完美运行。如果细节太紧凑,请随意纠缠我。

我的观察指向 WSL 本身(存在一些内存问题)或我在其中运行的数据库。很难说,但是你的问题有没有可能是类似的原因造成的?

我的代码有两个不同版本,一个在我的本地文件系统 (Windows) 中,另一个在 WSL 2(Linux 的 Windows 子系统,显然;Debian)中,因此能够比较两个系统的行为:我在本地和 WSL 中使用相同的代码(通过 github 传输)和要求。 G。 Django 3.1.6,以及相同的 DBMS(MySQL;在我的 WSL/Debian 中,无论是 MySQL 还是 MariaDB 都不是 100% 清楚,但后者旨在替代前者,所以我会如果这会导致我在这里描述的错误,我会感到惊讶)。我也在这两种环境中使用 Visual Studio 代码。

答案 3 :(得分:0)

摘自官方文档:https://docs.djangoproject.com/en/2.2/ref/models/fields/#unique-for-date

如果任何unique_for_date约束涉及不属于ModelForm的字段(例如,如果其中一个字段列在exclude中或具有editable = False),则Model.validate_unique()将跳过对该特定字段的验证约束。

问题可能出在“ 不是ModelForm一部分的字段将跳过对该特定约束的验证”。