2011-02-03 15 views
94

En Django, puede especificar relaciones como:Django: Obtener el modelo de la cadena?

author = ForeignKey('Person') 

Y entonces internamente tiene que convertir la cadena "Persona" en el modelo Person.

¿Dónde está la función que hace esto? Quiero usarlo, pero no puedo encontrarlo.

Respuesta

146

Como de Django 1.9 El método es django.apps.AppConfig.get_model(model_name).
- danihp


Como de Django 1.7 el django.db.models.loading es obsoleto (a retirar en 1,9) a favor de la del nuevo sistema de aplicación de carga.
- Scott Woodall


encontrado. Se define aquí:

from django.db.models.loading import get_model 

define como:

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

Esta solución está en desuso en Django 1.7, vea esta otra respuesta para la solución: http://stackoverflow.com/a/26126935/155987 –

+2

Hola @mpen, le sugiero que actualice su respuesta. [En django 1.9 get_model se define en AppConfig] (https://docs.djangoproject.com/es/1.9/ref/applications/#django.apps.AppConfig.get_model): 'desde django.apps import AppConfig' – danihp

+0

@danihp Gracias, agregué una nota. – mpen

3

No estoy seguro de dónde se hace en Django, pero podrías hacerlo.

Asignando el nombre de la clase a la cadena a través de la reflexión.

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

¿Es CLLS .__ clase __.__ name__ o simplemente clls .__ name__? –

30

mayoría de las "cadenas" modelo aparecerá como la forma "appname.modelname" por lo que es posible que desee utilizar esta variación en get_model

from django.db.models.loading import get_model 

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

La parte del código django que generalmente convierte tales cadenas en un modelo es un poco más compleja Esto de 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) 

Para mí, este parece ser un buen caso para dividir esto en una sola función en el código central. Sin embargo, si sabe que sus cadenas están en formato "Modelo de aplicación", las dos líneas anteriores funcionarán.

+2

Creo que la 2da línea debería ser: 'your_model = get_model (* your_string.rsplit ('.', 1))'. La etiqueta de la aplicación a veces tiene un formato de puntos, sin embargo, el nombre del modelo siempre es un identificador válido. – Rockallite

+0

Parece que esto no es necesario en la nueva 'apps.get_model'. "Como un acceso directo, este método también acepta un único argumento en la forma' app_label.model_name'. " –

13

simplemente para cualquier persona se atasque (como yo):

from django.apps import apps 

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

app_name deben mencionarse el uso de citas, al igual que model_name (es decir, no trate de importarlo)

get_model acepta minúsculas o mayúscula 'nombre_del_modelo'

+0

¿Qué hay en el mundo es una 'coma invertida' ... ??? –

+1

que debería leer 'citas', es decir. '' –

+0

Esta es la respuesta que funciona con django 1.11 –

97

A partir de Django 1.7 el django.db.models.loadingis deprecated (a eliminar en 1.9) a favor del nuevo sistema de carga de aplicaciones. El 1.7 docs give us el siguiente lugar:

$ python manage.py shell 
Python 2.7.6 (default, Mar 5 2014, 10:59:47) 
>>> from django.apps import apps 
>>> User = apps.get_model(app_label='auth', model_name='User') 
>>> print User 
<class 'django.contrib.auth.models.User'> 
>>> 

Editado por tttthomasssss comentario.

+0

Solía ​​usar la función "localizar" de pydoc ... no estoy seguro de la diferencia aquí, pero para permanecer dentro de Django, he cambiado a este método. Gracias. –

15

La bendita manera de hacer esto en Django 1.7+ es:

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

Así, en el ejemplo canónico de todos los tutoriales marco:

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

En caso de que no saben en que aplicación existe el modelo, se puede buscar de esta manera:

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

Recuerde que your_model_name debe estar en minúsculas.

1

Aquí es un enfoque menos específicas de Django para obtener una clase de cadena:

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

o puede utilizar importlib como se muestra here:

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