首页 > 解决方案 > 基础模型的自定义管理器。用于过滤具有不同属性的子类的模型

问题描述

假设我有以下类,它为具有时间间隔的数据实现了一个基本模型(我不在这里写整个实现,我不能使用第三方库)。

class BaseHistorizationModel(models.Model):

    value = models.DecimalField(decimal_places=2, max_digits=5)
    date_begin = models.DateField(db_index=True, blank=True, null=True)
    date_end = models.DateField(db_index=True, blank=True, null=True)

    class Meta:
        abstract = True
        ordering = [F("date_begin").asc(nulls_last=True)]

   @classmethod
    def get_values_between(cls, date_begin, date_end):
        instances = cls.get_instances_between(date_begin, date_end)
        return [(i.date_begin, i.value) for i in instances}
        
   @classmethod
    def get_instances_between(cls, date_begin, date_end):
        begin_overlap = cls._get_begin_overlap(date_begin, date_end)
        end_overlap = cls._get_end_overlap(date_begin, date_end)
        insides = cls.object.filter(
            date_begin__gte=date_begin,
            date_end__lte=date_end,
        )
        over = cls._get_overlap(date_begin, date_end)
        return to_list(
            over if over else (begin_overlap, insides, end_overlap) 
        )

   @classmethod
    def _get_begin_overlap(cls, date_begin, date_end):
        try:
            overlap = cls.objects.get(
                Q(date_begin__lt=date_begin)
                & Q(date_end__gt=date_begin)
                & Q(date_end__lt=date_end)
            )
         except cls.ObjectDoesNotExist:
             overlap = None
        return overlap

    ...

然后我有其他类继承自BaseHistorizationModel,例如:

class NbOccupant(BaseHistorizationModel):
    value = models.IntegerField()
    building = models.ForeignKey(
        Building,
        on_delete=models.CASCADE,
        related_name="nb_occupants",
    )    

class Temperature(BaseHistorizationModel):
    value = models.IntegerField()
    city = models.ForeignKey(
        City,
        on_delete=models.CASCADE,
        related_name="temperatures",
    )    

我不清楚如何将我的方法get_values_between_date用于子类。对于这些类,我需要首先使用他们自己的外键过滤我的数据,我希望能够执行以下操作:

nb_occupants = NbOccupant.get_values_between_date(start, end, building__name="palais de l'elysee")
temperatures = Temperature.get_values_between(start, end, city__name="Grenoble")

我最终得到以下结果:


class BaseHistorization(models.Model):
   ...
   @classmethod
    def get_values_between(date_begin, date_end, **extra_query):
        instances = cls.get_instances_between(date_begin, date_end, extra_query)
        return {i.date_begin: i.value for i in instances}

   ... 

    @classmethod
    def _get_begin_overlap(date_begin, date_end, extra_query):
        query = (
           Q(date_begin__lt=date_begin)
           & Q(date_end__gt=date_begin)
           & Q(date_end__lt=date_end)
        )
        try:
            overlap = cls.objects.filter(query, **extra_query)
        except cls.ObjectDoesNotExist:
            overlap = None
        return overlap

这似乎有点复杂,我需要将 extra_query 通过我的所有功能传递到cls.objects.getor cls.objects.filter。我有很多这样的函数调用。我认为CustomManager可以帮助我,但我不完全明白如何。或者也许我可以做点别的。

标签: djangoinheritanceorm

解决方案


推荐阅读