Sieht aus wie ich eine Lösung gefunden habe, die auf einer Klassenmethode der abstrakten Klasse basiert, die das richtige Feld über die Methode contribute_to_class
erstellt und durch das Signal class_prepared
initiiert wird.
Es wurde durch den folgenden Artikel inspiriert: Django Model Field Injection, und in einigen Fällen kann der Artikel Django application import and missed class_prepared signals nützlich sein, aber in meinen besonderen Fällen war es nicht relevant.
So ist die Lösung, die eine Methode in der abstrakten Klasse zu definieren, die das richtige Feld schaffen wird:
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
Die Unterklasse unberührt gelassen werden kann:
class LikeForPost(Like):
TARGET_MODEL = 'blog.Post'
Um es funktioniert Die on_class_prepared()
-Funktion muss aufgerufen werden, nachdem die LikeForPost
-Klasse erstellt wurde, die erreicht werden kann, indem sie an das class_prepared
-Signal von Django angeschlossen wird. Der beste Platz, um es zu setzen, nach der documentation, ist in der AppConfig.__init__()
Methode. Also haben wir eine Anwendung auswählen, die für diese Einrichtung zuständig sein sollte, in meinem Fall ist es blog
, und fügen Sie den folgenden Code zu 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)
Und diese Konfiguration standardmäßig zu aktivieren, konfigurieren Sie es in blog/__init__.py
:
default_app_config = 'blog.apps.BlogConfig'
Diese Lösung in Django getestet 1,10, und verhält sich in ein normalerweise definierten fest codierten Feld identisch, wenn ein Server, Tests des Modells ausgeführt wird, und wenn die Vorbereitung Migrationen mit manage.py makemigrations
.