2017-02-16 120 views
1

定义的ForeignKey的参考模型我有一个抽象的模型是这样的:覆盖在抽象的Django模型

class Like(models.Model): 
    TARGET_MODEL = 'TargetModel' 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 
    target = models.ForeignKey(TARGET_MODEL) 

    class Meta: 
     abstract = True 

,我想使TARGET_MODEL在每个子类中不同。例如,该Post模型从blog应用程序引用的模型LikeForPost

class LikeForPost(Like): 
    TARGET_MODEL = 'blog.Post' 

它似乎并不奏效,因为TARGET_MODEL不从子类实例化。什么才是实现这一目标的正确方法?

我知道我可以重新定义LikeForPost类中的整个target字段,但我希望有一个更优雅的解决方案,它只允许覆盖模型名称。

回答

0

看起来我已经找到了基于抽象类的类方法的解决方案,它通过contribute_to_class方法创建适当的字段,并由class_prepared信号启动。

它的灵感来自于以下文章:Django Model Field Injection,在某些情况下,Django application import and missed class_prepared signals文章可能有用,但在我的特殊情况下,它并不相关。

因此,解决方案是定义在抽象类中的方法,将创建正确的领域:

class Like(models.Model): 
    TARGET_MODEL = None # will be overridden in subclass 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 

    @classmethod 
    def on_class_prepared(cls): 
     target_field = models.ForeignKey(cls.TARGET_MODEL) 
     target_field.contribute_to_class(cls, 'target') 

    class Meta: 
     abstract = True 

子类可以保持不变:

class LikeForPost(Like): 
    TARGET_MODEL = 'blog.Post' 

要使它发挥作用,必须在LikeForPost类创建后调用on_class_prepared()函数,这可以通过将其挂接到Django的class_prepared信号来实现。根据documentation,放置它的最佳位置在AppConfig.__init__()方法中。所以我们挑选应该为此事负责安装的应用程序,在我的情况下,它是blog,和下面的代码添加到blog/apps.py

from django.apps import AppConfig 
from django.db.models import signals 

def call_on_class_prepared(sender, **kwargs): 
    """Calls the function only if it is defined in the class being prepared""" 
    try: 
     sender.on_class_prepared() 
    except AttributeError: 
     pass 


class BlogConfig(AppConfig): 
    name = 'blog' 

    def __init__(self, app_name, app_module): 
     super(BlogConfig, self).__init__(app_name, app_module) 
     # Connect programmatic class adjustment function to the signal 
     signals.class_prepared.connect(call_on_class_prepared) 

而为了让这个配置活跃在默认情况下,将其配置在blog/__init__.py

default_app_config = 'blog.apps.BlogConfig' 

将该溶液在Django 1.10测试,并且在运行时的服务器,该模型的测试,并与制备迁移时的行为等同于通常定义的硬编码的场3210。