Django:有没有办法实现“日期范围唯一”?

7 投票
2 回答
4176 浏览
提问于 2025-04-15 23:28

如果我的物品模型是:

class Item(models.Model):
    name = models.CharField(max_length=500)
    startDate = models.DateField("Start Date", unique="true")
    endDate = models.DateField("End Date")      

每个物品都需要有一个独特的日期范围。比如说,如果我创建了一个日期范围是从6月1日到6月8日的物品,那么我该如何防止创建一个日期范围是从6月3日到6月5日的物品(或者用模板逻辑显示一个错误)呢?

告诉我,如果我可以更清楚地解释这个问题!

2 个回答

7

如果你使用postgresql作为数据库,并且使用的django版本是3.0或更高,那么你可能想要在数据库层面上强制执行一些逻辑(这个方法在之前的答案给出时是不可用的)。

from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateRangeField, RangeOperators
from django.db import models


class Item(models.Model):
    name = models.CharField(max_length=500)
    date_range = DateRangeField()

    class Meta:
        constraints = [
            ExclusionConstraint(
                name='exclude_overlap',
                expressions=[
                    ('date_range', RangeOperators.OVERLAPS),
                ],
            )

来源: https://docs.djangoproject.com/en/3.2/ref/contrib/postgres/constraints/

9

你不能在模型层面强制执行这个规则,不过你可以重写保存方法,像这样:

class Item(models.Model):
    name = models.CharField(max_length=500)
    startDate = models.DateField("Start Date", unique="true")
    endDate = models.DateField("End Date")     

    def save(self, *args, **kwargs):
        try:
            Item.objects.get(Q(startDate__range=(self.startDate,self.endDate))|Q(endDate__range=(self.sartDate,self.endDate))|Q(startDate__lt=self.startDate,endDate__gt=self.endDate))
            #raise some save error
        except Item.DoesNotExist:
            super(Item,self).save(*args,**kwargs)

补充一下:也许日期范围的检查可以简单一点,距离我上次做这个已经很久了,但这个例子展示了大致的概念 :).

撰写回答