要实现Django多态行为(自定义外键),可以不使用GenericForeignKey,而是使用自定义外键。下面是一个示例代码:
from django.db import models
class ContentType(models.Model):
app_label = models.CharField(max_length=50)
model = models.CharField(max_length=50)
class Meta:
unique_together = ('app_label', 'model')
class MyForeignKey(models.ForeignKey):
def __init__(self, **kwargs):
self.content_type_field = kwargs.pop('content_type_field')
self.object_id_field = kwargs.pop('object_id_field')
super().__init__(**kwargs)
def contribute_to_class(self, cls, name, private_only=False, virtual_only=models.NOT_PROVIDED):
super().contribute_to_class(cls, name, private_only=private_only, virtual_only=virtual_only)
setattr(cls, self.content_type_field, models.ForeignKey(ContentType, on_delete=models.CASCADE))
setattr(cls, self.object_id_field, models.PositiveIntegerField())
class MyModel(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
my_fk = MyForeignKey(to='myapp.MyModel', content_type_field='content_type', object_id_field='object_id')
def __str__(self):
return str(self.my_fk)
在上面的代码中,我们创建了一个名为MyForeignKey
的自定义外键类,它继承自models.ForeignKey
。在MyForeignKey
的构造函数中,我们传入了content_type_field
和object_id_field
参数,用于指定ContentType和Object ID的字段名称。
在contribute_to_class
方法中,我们通过setattr
函数将ContentType和Object ID的字段添加到模型类中。
然后,我们创建了一个名为MyModel
的模型类,它包含了一个content_type
字段和一个object_id
字段,以及一个使用MyForeignKey
的自定义外键字段my_fk
。
通过这种方式,我们可以实现多态行为,可以将my_fk
字段关联到MyModel
类本身的实例,也可以关联到其他模型类的实例。