如何使用综合列表使我的Django代码干燥和高效?

时间:2014-05-22 11:49:36

标签: django django-models

在下面的代码中,我可以看到2个区别问题:

  1. 这不是DRY,因为date__range中的整个逻辑对于两个列表(A和B)都是相同的。你怎么解决这个问题?我尝试使用方法作为参数但没有成功,不确定如何实现它。

  2. 在每个循环中调用get_x_events(),我想这样效率不高..

  3. class Event(models.Model):

        @classmethod
        def get_stats(cls, owner, nb_days, offset):
    
            # Building a list with comprehensive list calling the get_A_events() classmethod of the EventA class
            list_A = [EventA.get_A_events(owner).filter(
                date__range=(
                    now_day - timedelta(days=offset) - timedelta(days=d),
                    now_day - timedelta(days=offset) - timedelta(days=d-1))).count() \
                for d in range(nb_days)]
    
            # Doing the same with another method of another class
            # The logic is exactly the same thought...
            list_B = [EventB.get_B_events(owner).filter(
                date__range=(
                    now_day - timedelta(days=offset) - timedelta(days=d),
                    now_day - timedelta(days=offset) - timedelta(days=d-1))).count() \
                for d in range(nb_days)]
    
            return zip(list_A, list_B)
    

    我的模型以这种方式组织:

    • class Event(models.Model)
    • 类EventA(事件)
    • 类EventB(事件)

    感谢。

3 个答案:

答案 0 :(得分:1)

这将是一个良好的开端。

kwargs = {
    'date__range': (now_day - timedelta(days=offset) - timedelta(days=d),
                    now_day - timedelta(days=offset) - timedelta(days=d-1)),
}

list_A = [
    EventA.get_A_events(owner).filter(**kwargs).count()
    for d in range(nb_days)
]

list_B = [
    EventB.get_B_events(owner).filter(**kwargs).count()
    for d in range(nb_days)
]

除此之外,您应该重构您的模型。拥有EventAEventB而不是单个Event模型表明您进一步违反了DRY原则。这同样适用于get_A_eventsget_B_events方法,为什么不使用单个get_events方法?

答案 1 :(得分:1)

您的查询当然可以进行优化。现在,您为列表推导中的每个迭代执行一个sql查询。使用注释,您可以将其减少为2个查询:

from django.db.models import Count

list_A = [a['num_days'] for a in EventA.get_A_events(owner).filter(date__range=(
             now_day - timedelta(days=offset),
             now_day - timedelta(days=offset+nb_days))) \
             .values('date').annotate(num_days=Count('id'))]

您可以使用**kwargs进行过滤器调用,如Matt建议的那样,但是您可以遵循DRY原则的范围主要取决于模型的逻辑结构,主要是它们的继承链。如果您可以发布模型,我可以帮助您。

答案 2 :(得分:1)

def get_events_list(event_object_with_owner, offset, nb_days):
    event_list = [ 
                   event_object_with_owner.filter(
                   date__range=(
                   now_day - timedelta(days=offset) - timedelta(days=d),
                   now_day - timedelta(days=offset) - timedelta(days=d-1))).count() \
                   for d in range(nb_days)
                  ]
    return event_list


event_list_A = get_events_list(EventA.get_A_events(owner), offset, nb_days)

event_list_B = get_events_list(EventB.get_B_events(owner), offset, nb_days)