Django DateTimeField中唯一的月/年组合

时间:2014-10-13 13:50:01

标签: django

我有DateTimeField并希望按月/年限制,即每月只有一个条目。

目前我使用了两个额外的字段(month / year)和unique_together = ("month", "year"),但肯定有更好的解决方案。

class someModel(models.Model):
    datetime = models.DateTimeField(unique=True)
    ...

    class Meta:
        ordering = ['datetime']

2 个答案:

答案 0 :(得分:4)

除了你现在正在做的方式之外,你不能真正“原生”地做到这一点,因为在定义模型时你正在定义数据库级验证,并说MySQL不支持带有YEAR的DATETIME字段+ MONTH唯一约束。

但是,您可以在该字段上添加自己的验证器,但这将需要额外的开销来保存/更新模型的实例。我以前自己遇到了日期时间/时间戳值的麻烦,通常年+月独特约束解决方案是最有效/透明的,即使它导致额外的存储(但这是最便宜的元素,对吗?)

但是,如果您决定使用单字段唯一约束,请参阅https://docs.djangoproject.com/en/dev/ref/validators/ - 您需要在字段中添加验证器,以检查是否存在具有该年份+月份组合的其他对象。请注意,这在大型系统上效率非常低,因为MySQL不支持DATETIME字段上的年/月索引 - 该值将通过完整表扫描中的函数传递并在之后进行过滤:(

答案 1 :(得分:1)

Field.unique_for_date会使某个字段值的实例唯一。 这将按月限制:

from django.core.exceptions import ValidationError

class SomeModel(models.Model):
    # Set index to field
    datetime = models.DateTimeField(db_index=True)

    def save(self, *args, **kwargs):
        # If new instance created
        queryset = SomeModel.objects.filter(
                        datetime__startswith=self.datetime.strftime('%Y-%m-'))

        # If instance changed
        if self.id is not None:
            queryset = queryset.exclude(id=self.id)

        if queryset.exists():
            raise ValidationError('Choose another date')

        super(SomeModel, self).save(*args, **kwargs)