Похоже, я нашел решение на основе метода класса абстрактного класса, который создает правильное поле с помощью метода 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'
Чтобы заставить его работать, функция on_class_prepared()
должна быть вызвана после создания класса LikeForPost
, что может быть достигнуто путем подключения его к сигналу class_prepared
Django. Лучшее место для размещения, согласно 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, и ведет себя идентично нормально определенную область закодированной при запуске сервера, испытание модели, а при подготовке миграции с manage.py makemigrations
.