如何在自定义管理器中访问模型属性?

1 投票
1 回答
1076 浏览
提问于 2025-04-17 05:25

我有一个Django模型,用来表示一个带有日期字段的对象。同时,我还创建了两个管理器,用来筛选这些对象在特定日期范围内的记录。

class SchoolYearManager(models.Manager):
    def get_query_set(self):
        now = datetime.datetime.now()
        current_year = now.year
        start_date = datetime.date(current_year, 7, 1)
        end_date = datetime.date((current_year + 1), 6, 30)
        return super(SchoolYearManager, self).get_query_set().filter(status=self.model.LIVE).filter(event_date__range=(start_date, end_date))

class PastSchoolYearManager(models.Manager):
    def get_query_set(self):
        current_year = self.model.event_date.year
        start_date = datetime.date(current_year, 7, 1)
        end_date = datetime.date((current_year + 1), 6, 30)
        return super(PastSchoolYearManager, self).get_query_set().filter(status=self.model.LIVE).filter(event_date__range=(start_date, end_date))

class Event(models.Model):
    LIVE = 3
    DRAFT = 4
    STATUS_CHOICES = (
        (LIVE, 'Live'),
        (DRAFT, 'Draft'),
    )
    status = models.IntegerField(choices=STATUS_CHOICES, default=4, help_text="Only entries with a status of 'live' will be displayed publically.")
    event_date = models.DateField()

    objects = Models.Manager()
    school_year_events = SchoolYearManager()
    past_school_year_events = PastSchoolYearManager()

我的第一个管理器(SchoolYearManager)工作得很好,可以正常返回在那个日期范围内的事件。但是当我尝试使用 Event.past_school_year_events.all() 时,却出现了一个属性错误: "类型对象 'Event' 没有属性 'event_date'"。

我创建第二个管理器(PastSchoolYearEvents)的目的是为了封装一个通用的年度归档视图,以便返回特定年份内的事件。

为什么我在管理器中不能调用 self.model.event_date 呢?

我这样做是对的吗?如果不对,那有什么更好的方法呢?

1 个回答

1

这怎么可能呢?它指的是什么事件日期呢?当你调用 Event.past_school_year_events.all() 的时候,其实并没有一个模型实例。self.model,顾名思义,是指模型类。那么它怎么知道你想要的日期是什么呢?

我其实搞不清楚你想做什么——你打算从哪里获取日期?你是想从一个事件开始,然后获取同一年里的其他所有事件吗?如果是这样的话,我觉得你可能只是想把 past_school_year_events 变成一个模型方法,而不是一个管理器。

编辑 如果你想从特定的年份开始,使用管理器当然是合适的,但你需要把年份作为参数传递给你的管理器方法。为此,我建议在管理器上使用一个单独的方法,而不是重写 get_query_set——实际上,可以在 SchoolYearManager 中添加另一个方法:

class SchoolYearManager(models.Manager):
    def live_events(self, start_date, end_date):
       return self.filter(status=self.model.LIVE).filter(event_date__range=(start_date, end_date))

    def this_year(self):
        now = datetime.datetime.now()
        current_year = now.year
        start_date = datetime.date(current_year, 7, 1)
        end_date = datetime.date((current_year + 1), 6, 30)
        return self.live_events(start_date, end_date)

    def from_year(self, year):
        start_date = datetime.date(year, 7, 1)
        end_date = datetime.date(year+1, 6, 30)
        return self.live_events(start_date, end_date)

现在你只有一个管理器,它没有重写 get_query_set,所以你甚至不需要保留默认的那个——你可以把这个管理器保留为 objects。这样你就可以这样做:

Event.objects.this_year()  # all this year's events
Event.objects.from_year(2010) # all events from 2010

撰写回答