我一直在尝试修改AuditTrail代码,以便它不复制ForeignKey
字段,而是复制相关字段(即我不想在我的数据库表上使用外键对于审计模型)。
我写了一个copy_field
函数,看起来像这样:
def copy_field(field):
while(isinstance(field, models.OneToOneField, models.ForeignKey)):
field = field.rel.get_related_field()
if isinstance(field, models.AutoField):
f = models.IntegerField()
else:
f = copy(field)
#...snip some adjusting of fs attributes...
return f
当准备具有AuditTrail
属性的模型时(通过class_prepared
信号)运行此代码。
但是,当ForeignKey
与尚未准备的模型上的字段相关时,这会遇到问题 - get_related_field()
调用将失败,因为field.rel.to
是一个字符串包含相关模型的名称,而不是模型实例。
我无法解决这个问题。在开始复制字段之前,我是否必须确定模型具有哪些依赖关系,并等到它们都准备好了?关于最佳方式的任何想法?
答案 0 :(得分:0)
我最终做的是列出模型具有的所有依赖项(通过确定一个标准的应用程序/名称对;从django.db.models.fields.related
复制一些代码来确定这一点)并修改我的class_prepared
信号处理程序听取所有模型,而不仅仅是我的目标模型。
当处理程序在我的依赖项列表中识别出一个模型时,它会从列表中删除它并检查列表是否为空;如果是,则可以创建审计模型。重要的注意事项是在创建模型之前断开class_prepared
处理程序,否则我遇到了无限递归(或者我可以更具体地控制处理程序)。
dependencies = []
for field in cls._meta.local_fields:
while isinstance(field, (models.OneToOneField, models.ForeignKey)):
if isinstance(field.rel.to,basestring):
dependencies.append(get_canonical(cls,field.rel.to))
break
else:
field = field.rel.get_related_field()
def _contribute(sender, **kwargs):
key = (sender._meta.app_label, sender.__name__)
if key in dependencies:
dependencies.remove(key)
if not dependencies:
models.signals.class_prepared.disconnect(_contribute)
model = create_audit_model(cls)
models.signals.class_prepared.connect(_contribute, weak=False)