django orm filter datetime by integer of days(Django orm按天数整数筛选日期时间)
                            本文介绍了Django orm按天数整数筛选日期时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
                        
                        问题描述
我有一个名为AccessDuration的模型,它有两个重要的字段:duration(Int)和lab_start_date(DateTime)。基于这两个字段,我想检查访问持续时间是否已过期。这是通过使用模型函数完成的。
class AccessDuration(models.Model):
    ....
    duration = models.PositiveIntegerField(default=30, help_text=_('In days'))
    lab_start_date = models.DateTimeField(verbose_name=('Start Date'), null=True)
    @property
    def expiration_date(self) -> Union[timezone.datetime, None]:
        if self.lab_start_date:
            return self.lab_start_date + timezone.timedelta(days=self.duration)
        return None
    @property
    def is_expired(self) -> bool:
        """ to check whether duration already expired or yet """
        if self.expiration_date:
            return timezone.now() > self.expiration_date
        return False
但是,我需要这个过滤器可以在我的Django管理页面使用。我试过了,但似乎仍然不起作用:
from django.db import models
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from .models import AccessDuration
class AccessListFilter(admin.SimpleListFilter):
    title = _('Is Expired')
    parameter_name = 'is_expired'
    def lookups(self, request, model_admin):
        return [
            ('true', _('True')),
            ('false', _('False'))
        ]
    def queryset(self, request, queryset):
        value = self.value()
        expiration_date = models.ExpressionWrapper(
            models.F('lab_start_date') + (timezone.timedelta(days=1) * models.F('duration')),
            output_field=models.DateTimeField()
        )
        if value == 'true':
            return queryset.annotate(expiration_date=expiration_date)
                           .filter(expiration_date__lt=timezone.now())
        elif value == 'false':
            return queryset.annotate(expiration_date=expiration_date)
                           .filter(expiration_date__gte=timezone.now())
        return queryset
class AccessAdmin(admin.ModelAdmin):
    list_filter = (AccessListFilter, 'lab_start_date')
admin.site.register(AccessDuration, AccessAdmin)
我发现的错误;
@William解决后,我对Manager做了一些修改;
class AccessDurationQuerySet(models.QuerySet):
    def filter_expiration(self, is_expired: bool = False):
        """
        To filter whether AccessDuration already expired or yet.
        don't use the same `expiration_date` as expression key,
        because it will clash with `AccessDuration.expiration_date` property.
        Issue: https://stackoverflow.com/q/69012110/6396981
        """
        kwargs = {'_expiration_date__gte': Now()}
        if is_expired:
            del kwargs['_expiration_date__gte']
            kwargs['_expiration_date__lt'] = Now()
        return self.all().annotate(
            _expiration_date=models.ExpressionWrapper(
                models.F('lab_start_date') + (timezone.timedelta(days=1) * models.F('duration')),
                output_field=models.DateTimeField()
            )
        ).filter(**kwargs)
class AccessDurationManager(
    models.Manager.from_queryset(AccessDurationQuerySet),
    DefaultManager
):
    def published(self):
        return super().published().filter(
            status=AccessDurationStatusChoices.active
        )
class AccessDuration(models.Model):
    ....
    objects = AccessDurationManager()
然后在我们的ORM中;
AccessDuration.objects.filter_expiration(is_expired=True)
或在我们的admin.py;
class ExpirationListFilter(admin.SimpleListFilter):
    title = _('Is Expired')
    parameter_name = 'is_expired'
    def lookups(self, request, model_admin):
        return [
            (True, True),
            (False, False)
        ]
    def queryset(self, request, queryset):
        value = str(self.value()).lower()
        if value == 'true':
            return queryset.filter_expiration(is_expired=True)
        elif value == 'false':
            return queryset.filter_expiration(is_expired=False)
        return queryset
class AccessAdmin(admin.ModelAdmin):
    ...
    list_filter = (ExpirationListFilter, ...)
推荐答案
您应该使用expiration_date要批注的其他名称。例如:
from django.db.models.functions import Now
if value == 'true':
    return queryset.annotate(
        _expiration_date=expiration_date
    ).filter(_expiration_date__lt=Now())
elif value == 'false':
    return queryset.annotate(
        _expiration_date=expiration_date
    ).filter(_expiration_date__gte=Now())
                        这篇关于Django orm按天数整数筛选日期时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
				 沃梦达教程
				
			本文标题为:Django orm按天数整数筛选日期时间
				
        
 
            
        
             猜你喜欢
        
	     - 计算测试数量的Python单元测试 2022-01-01
 - 我如何透明地重定向一个Python导入? 2022-01-01
 - 如何使用PYSPARK从Spark获得批次行 2022-01-01
 - YouTube API v3 返回截断的观看记录 2022-01-01
 - 使用公司代理使Python3.x Slack(松弛客户端) 2022-01-01
 - 使用 Cython 将 Python 链接到共享库 2022-01-01
 - CTR 中的 AES 如何用于 Python 和 PyCrypto? 2022-01-01
 - ";find_element_by_name(';name';)";和&QOOT;FIND_ELEMENT(BY NAME,';NAME';)";之间有什么区别? 2022-01-01
 - 检查具有纬度和经度的地理点是否在 shapefile 中 2022-01-01
 - 我如何卸载 PyTorch? 2022-01-01
 
