在Django的get_queryset方法中调用super().get_queryset()的原因及作用解析
嘿,我来给你把这行代码的来龙去脉讲得明明白白,保证你听完就通透!
先看你给出的代码:
def get_queryset(self): queryset = super(OrderListView, self).get_queryset() return queryset.filter(initiator=self.request.user)
咱们逐个解答你的疑问:
1. 这行代码的核心目的是什么?
简单说就是**「站在父类的肩膀上干活」**。你重写了get_queryset方法,但不想完全抛弃父类已经写好的成熟逻辑,所以先调用父类的get_queryset拿到它生成的基础查询集,再在这个基础上叠加自己的过滤规则。
2. 它具体做了什么?
super(OrderListView, self).get_queryset()这行代码,本质是调用你OrderListView继承的父类(比如Django自带的ListView)的get_queryset方法。
父类的get_queryset本来就有自己的内置逻辑:比如默认会返回你在视图里指定的model对应的所有对象(比如Order.objects.all()),如果父类还做了其他预处理(比如根据URL参数过滤、排序规则、分页相关的前置处理),这行代码也会把这些处理后的完整查询集拿过来。
3. 为什么必须调用super()?
因为当你在子类里重写一个方法时,Python默认不会自动执行父类的同名方法。如果你直接写return Order.objects.filter(...),虽然看起来能实现需求,但会丢失父类get_queryset里的所有隐性功能:
- 比如如果父类已经配置了
paginate_by分页逻辑,你跳过父类方法的话,分页可能直接失效; - 再比如如果项目里自定义了一个基础ListView,加了全局的软删除过滤(只返回
is_deleted=False的对象),你不调用super的话,你的查询集就会不小心包含已删除的订单。
用super()调用父类方法,就是为了把这些父类的「隐形功能」保留下来,只在它的基础上扩展自己的业务逻辑。
4. 为什么在自己的方法里调用同名方法?
这可不是「自己调用自己」哦,你调用的是父类的get_queryset方法,和你现在重写的子类方法是两个完全不同的东西。你只是借父类的方法生成一个靠谱的基础查询集,然后在这个基础上做进一步筛选——相当于「先拿到所有符合父类规则的订单,再从中挑出当前用户发起的」,而不是「直接从零开始找当前用户的订单」。后者看起来简单,但灵活性和可维护性差很多:比如以后父类get_queryset新增了「只返回最近30天订单」的规则,你不用改自己的代码,自动就能得到「最近30天里当前用户发起的订单」,这就是继承的优势!
备注:内容来源于stack exchange,提问作者Arlan Kaliyev

