Django: Modell aus String holen?

133

In Django können Sie Beziehungen angeben wie:

author = ForeignKey('Person')

Und dann muss es intern die Zeichenfolge "Person" in das Modell konvertieren Person.

Wo ist die Funktion, die das macht? Ich möchte es benutzen, aber ich kann es nicht finden.

mpen
quelle

Antworten:

167

Ab Django 3.0 ist es AppConfig.get_model(model_name, require_ready=True)

Ab Django 1.9 ist die Methode django.apps.AppConfig.get_model(model_name).
- danihp

Ab Django 1.7 django.db.models.loadingist das veraltet (in 1.9 zu entfernen) zugunsten des neuen Anwendungsladesystems.
- Scott Woodall


Fand es. Es ist hier definiert:

from django.db.models.loading import get_model

Definiert als:

def get_model(self, app_label, model_name, seed_cache=True):
mpen
quelle
11
Diese Lösung ist in Django 1.7 veraltet, siehe diese andere Antwort für die Lösung: stackoverflow.com/a/26126935/155987
Tim Saylor
4
Hallo @mpen, ich schlage Ihnen vor, Ihre Antwort zu aktualisieren. Auf django 1.9 ist get_model auf AppConfig definiert :from django.apps import AppConfig
dani herrera
1
django.apps.AppConfig ist ein Generatortyp, der nicht wie ein Modellobjekt funktionieren kann.
Neeraj Kumar
2
In Django 1.7+ ist es besser, get_model () in der Django-App-Registrierung zu verwenden, die über verfügbar ist django.apps.apps.get_model(model_name). AppConfig-Objekte sind für einen anderen Zweck vorgesehen und erfordern, dass Sie eine AppConfig-Instanz erstellen, um aufrufen zu können get_model().
Zlovelady
2
Django 1.11 braucht die Antwort von @luke_aus
Georg Zimmer
132

django.db.models.loadingwurde in Django 1.7 veraltet ( in 1.9 entfernt ) zugunsten des neuen Anwendungsladesystems .

Django 1.7-Dokumente geben uns stattdessen Folgendes:

>>> from django.apps import apps
>>> User = apps.get_model(app_label='auth', model_name='User')
>>> print(User)
<class 'django.contrib.auth.models.User'>
Scott Woodall
quelle
Ich habe früher die "Lokalisierungs" -Funktion von pydoc verwendet ... ich bin mir des Unterschieds hier nicht sicher, aber um in Django zu bleiben, habe ich zu dieser Methode gewechselt. Vielen Dank.
Warath-Codierer
61

Nur für alle, die stecken bleiben (wie ich):

from django.apps import apps

model = apps.get_model('app_name', 'model_name')

app_namesollte wie angegeben in Anführungszeichen gesetzt werden model_name(dh nicht versuchen, es zu importieren)

get_model akzeptiert Klein- oder Großbuchstaben 'Modellname'

lukeaus
quelle
32

Die meisten Modellzeichenfolgen werden als "appname.modelname" angezeigt, daher möchten Sie diese Variante möglicherweise für get_model verwenden

from django.db.models.loading import get_model

your_model = get_model ( *your_string.split('.',1) )

Der Teil des django - Code, der in der Regel solche Zeichenfolgen in ein Modell dreht , ist ein wenig komplexer Dieses aus django/db/models/fields/related.py:

    try:
        app_label, model_name = relation.split(".")
    except ValueError:
        # If we can't split, assume a model in current app
        app_label = cls._meta.app_label
        model_name = relation
    except AttributeError:
        # If it doesn't have a split it's actually a model class
        app_label = relation._meta.app_label
        model_name = relation._meta.object_name

# Try to look up the related model, and if it's already loaded resolve the
# string right away. If get_model returns None, it means that the related
# model isn't loaded yet, so we need to pend the relation until the class
# is prepared.
model = get_model(app_label, model_name,
                  seed_cache=False, only_installed=False)

Für mich scheint dies ein guter Fall zu sein, um dies im Kerncode in eine einzige Funktion aufzuteilen. Wenn Sie jedoch wissen, dass Ihre Zeichenfolgen im Format "App.Model" vorliegen, funktionieren die beiden oben genannten Zeilen.

Ch'marr
quelle
3
Ich denke die 2. Zeile sollte sein : your_model = get_model(*your_string.rsplit('.', 1)). Das App-Label hat manchmal ein gepunktetes Format, der Modellname ist jedoch immer eine gültige Kennung.
Rockallite
1
Sieht so aus, als wäre dies im neuen nicht notwendig apps.get_model. "Als Verknüpfung akzeptiert diese Methode auch ein einzelnes Argument im Formular app_label.model_name."
Ryne Everett
16

Der gesegnete Weg, dies in Django 1.7+ zu tun, ist:

import django
model_cls = django.apps.apps.get_model('app_name', 'model_name')

Im kanonischen Beispiel aller Framework-Tutorials:

import django
entry_cls = django.apps.apps.get_model('blog', 'entry')  # Case insensitive
Craig Labenz
quelle
9

Falls Sie nicht wissen, in welcher App Ihr ​​Modell vorhanden ist, können Sie es folgendermaßen suchen:

from django.contrib.contenttypes.models import ContentType 
ct = ContentType.objects.get(model='your_model_name') 
model = ct.model_class()

Denken Sie daran, dass Ihr_Modellname in Kleinbuchstaben geschrieben sein muss.

Ola Nguyen Van
quelle
4

Ich bin nicht sicher, wo es in Django gemacht wird, aber Sie könnten dies tun.

Zuordnen des Klassennamens zur Zeichenfolge über Reflektion.

classes = [Person,Child,Parent]
def find_class(name):
 for clls in classes:
  if clls.__class__.__name__ == name:
   return clls
jbcurtin
quelle
1
Ist es clls .__ class __.__ name__ oder nur clls .__ name__?
Vinayak Kaniyarakkal
4

Eine weitere Wiedergabe mit weniger Code für die Faulen. Getestet in Django 2+

from django.apps import apps
model = apps.get_model("appname.ModelName") # e.g "accounts.User"
Glyzerin
quelle
1

Hier ist ein weniger django-spezifischer Ansatz, um eine Klasse aus einem String zu erhalten:

mymodels = ['ModelA', 'ModelB']
model_list = __import__('<appname>.models', fromlist=mymodels)
model_a = getattr(model_list, 'ModelA')

oder Sie können importlib wie hier gezeigt verwenden :

import importlib
myapp_models = importlib.import_module('<appname>.models')
model_a = getattr(myapp_models, 'ModelA')
Schubisu
quelle