Django模型继承时如何让父类FileField调用子类重写的generate_filename?
问题根源
Django 模型字段是类属性,在类定义阶段就会完成初始化。你在SeamlessFile中定义actual_file字段时,直接将当时类作用域下的generate_filename函数对象绑定给了upload_to参数,这个绑定关系在类定义完成后就固定了。后续子类FrontEndAuditFile重写的是自身类作用域下的同名方法,不会修改父类字段已经绑定的函数引用,所以新方法不会触发。
解决方案
方案1:通用动态转发(推荐)
写一个全局的转发函数,运行时动态调用当前实例的generate_filename方法,不需要每个子类重复定义字段:
import os from django.db import models from abc import ABCMeta # 通用upload_to转发函数 def dynamic_upload_to(instance, filename): return instance.generate_filename(filename) class BaseFile(UidMixin, BaseModel): __metaclass__ = ABCMeta upload_directory = "" def generate_filename(self, filename): return "uploads/" class SeamlessFile(BaseFile): def generate_filename(self, filename): return os.path.join("seam/", os.path.basename(filename)) # 改用通用转发函数 actual_file = models.FileField( default=None, null=True, blank=True, upload_to=dynamic_upload_to, ) class FrontEndAuditFile(SeamlessFile): def generate_filename(self, filename): print("FrontEndAuditFile -> generate_filename") return os.path.join("fro/", os.path.basename(filename))
这个方案的优势是后续新增任何SeamlessFile的子类,只需要重写generate_filename方法即可,不需要额外修改其他代码,完全符合继承的多态特性。
方案2:子类重写字段
如果不想修改父类的现有实现,也可以在子类中重新声明一次actual_file字段,绑定当前子类的generate_filename方法:
class FrontEndAuditFile(SeamlessFile): def generate_filename(self, filename): print("FrontEndAuditFile -> generate_filename") return os.path.join("fro/", os.path.basename(filename)) # 重新声明字段,绑定当前类的方法 actual_file = models.FileField( default=None, null=True, blank=True, upload_to=generate_filename, )
这个方案的缺点是每个子类都要重复定义字段,代码冗余,容易遗漏。
内容的提问来源于stack exchange,提问作者Olivier Pons
相关产品推荐
相关产品推荐

