Django: ottieni il modello dalla stringa?


133

In Django, puoi specificare relazioni come:

author = ForeignKey('Person')

E poi internamente deve convertire la stringa "Person" nel modello Person.

Dov'è la funzione che fa questo? Voglio usarlo, ma non riesco a trovarlo.

Risposte:


167

A partire da Django 3.0, lo è AppConfig.get_model(model_name, require_ready=True)

A partire da Django 1.9 il metodo è django.apps.AppConfig.get_model(model_name).
- danihp

A partire da Django 1.7 django.db.models.loadingè deprecato (da rimuovere in 1.9) a favore del nuovo sistema di caricamento delle applicazioni.
- Scott Woodall


Trovato. È definito qui:

from django.db.models.loading import get_model

Definito come:

def get_model(self, app_label, model_name, seed_cache=True):

11
Questa soluzione è obsoleta in Django 1.7, vedi questa altra risposta per la soluzione: stackoverflow.com/a/26126935/155987
Tim Saylor,

4
Ciao @mpen, ti consiglio di aggiornare la tua risposta. Su django 1.9 get_model è definito su AppConfig :from django.apps import AppConfig
dani herrera

1
django.apps.AppConfig è un tipo di generatore che non può funzionare come un oggetto modello.
Neeraj Kumar,

2
In Django 1.7+ è meglio usare get_model () nel registro dell'app Django, che è disponibile tramite django.apps.apps.get_model(model_name). Gli oggetti AppConfig sono destinati a uno scopo diverso e per poter chiamare è necessario creare un'istanza AppConfig get_model().
zlovelady,

2
Django 1.11 necessita della risposta fornita da @luke_aus
Georg Zimmer l'

132

django.db.models.loadingè stato deprecato in Django 1.7 ( rimosso in 1.9 ) a favore del nuovo sistema di caricamento dell'applicazione .

I documenti di Django 1.7 ci forniscono invece quanto segue:

>>> from django.apps import apps
>>> User = apps.get_model(app_label='auth', model_name='User')
>>> print(User)
<class 'django.contrib.auth.models.User'>

Usavo la funzione "individuare" di pydoc ... non sono sicuro della differenza qui, ma per rimanere all'interno di Django ho passato a questo metodo. Grazie.
codificatore di guerra

61

solo per chiunque rimanga bloccato (come ho fatto io):

from django.apps import apps

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

app_namedovrebbe essere elencato usando le virgolette, come dovrebbe model_name(cioè non provare a importarlo)

get_model accetta lettere minuscole o maiuscole 'nome_modello'


32

La maggior parte delle "stringhe" del modello viene visualizzata come modulo "nomedominio.modelname", quindi potresti voler utilizzare questa variante su get_model

from django.db.models.loading import get_model

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

La parte del codice django che di solito trasforma tali stringhe in un modello è un po 'più complessa Questo da 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)

Per me, questo sembra essere un buon caso per dividere questo in una singola funzione nel codice principale. Tuttavia, se sai che le tue stringhe sono nel formato "App.Model", le due linee sopra funzioneranno.


3
Penso che la linea 2 ° dovrebbe essere: your_model = get_model(*your_string.rsplit('.', 1)). L'etichetta dell'app a volte ha un formato punteggiato, tuttavia il nome del modello è sempre un identificatore valido.
Rockallite,

1
Sembra che questo non sia necessario nel nuovo apps.get_model. "Come scorciatoia, questo metodo accetta anche un singolo argomento nel modulo app_label.model_name."
Ryne Everett,

16

Il modo benedetto per farlo in Django 1.7+ è:

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

Quindi, nell'esempio canonico di tutti i tutorial del framework:

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

9

Se non sai in quale app esiste il tuo modello, puoi cercarlo in questo modo:

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

Ricorda che your_model_name deve essere in minuscolo.


4

Non sono sicuro di dove sia stato fatto in Django, ma potresti farlo.

Mappatura del nome della classe sulla stringa tramite reflection.

classes = [Person,Child,Parent]
def find_class(name):
 for clls in classes:
  if clls.__class__.__name__ == name:
   return clls

1
È clls .__ classe __.__ name__ o solo clls .__ name__?
Vinayak Kaniyarakkal,

4

Un'altra interpretazione con meno codice per i pigri. Testato in Django 2+

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

1

Ecco un approccio meno specifico di django per ottenere una classe dalla stringa:

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

oppure puoi usare importlib come mostrato qui :

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.