Джанго: Отримайте модель зі струни?


133

У Django ви можете вказати такі відносини, як:

author = ForeignKey('Person')

І тоді внутрішньо він повинен перетворити рядок "Person" в модель Person .

Де функція, яка це робить? Я хочу його використовувати, але не можу його знайти.

Відповіді:


167

Що стосується Django 3.0, то це AppConfig.get_model(model_name, require_ready=True)

Станом на Джанго 1.9 цей метод є django.apps.AppConfig.get_model(model_name).
- данихп

Станом на Django 1.7 django.db.models.loadingце застаріле (буде видалено в 1.9) на користь нової системи завантаження додатків.
- Скотт Вуддол


Знайшов це. Тут визначено:

from django.db.models.loading import get_model

Визначено як:

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

11
Це рішення застаріло в Django 1.7, дивіться цю іншу відповідь на рішення: stackoverflow.com/a/26126935/155987
Тім Сейлор

4
Привіт @mpen, пропоную тобі оновити свою відповідь. На django 1.9 get_model визначено на AppConfig :from django.apps import AppConfig
dani herrera

1
django.apps.AppConfig - тип генератора, який не може працювати як об'єкт моделі.
Неєрай Кумар

2
У Django 1.7+ краще використовувати get_model () в реєстрі додатків Django, який доступний через django.apps.apps.get_model(model_name). Об'єкти AppConfig призначені для іншої мети, і вам потрібно створити екземпляр AppConfig для виклику get_model().
zlovelady

2
Джанго 1,11 потрібна відповідь, надана @luke_aus
Георг Циммер

132

django.db.models.loadingбув застарілий в Django 1.7 ( видалено в версії 1.9 ) на користь нової системи завантаження додатків .

Документи Django 1.7 дають нам наступне:

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

Я використовував функцію "locate" pydoc ... не впевнений у різниці тут, але для того, щоб залишитися в Django, я перейшов на цей метод. Дякую.
warath-coder

61

тільки для тих, хто застряг (як я):

from django.apps import apps

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

app_nameслід перераховувати, використовуючи лапки model_name(тобто не намагайтеся імпортувати їх)

get_model приймає малі та великі регістри 'model_name'


32

Більшість моделей "рядків" відображаються у формі "appname.modelname", тому ви можете використовувати цю варіацію в get_model

from django.db.models.loading import get_model

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

Частина коду django, яка зазвичай перетворює такі рядки в модель, трохи складніша. Це з 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)

Для мене, здається, це хороший випадок, щоб розділити це на одну функцію в основному коді. Однак якщо ви знаєте, що ваші рядки у форматі "App.Model", два вкладені вище працюватимуть.


3
Я думаю , що друга лінія повинна бути: your_model = get_model(*your_string.rsplit('.', 1)). Мітка програми іноді має крапковий формат, проте назва моделі завжди є дійсним ідентифікатором.
Рокалліт

1
Схоже, що в новому це не потрібно apps.get_model. "Як ярлик, цей метод також приймає один аргумент у формі app_label.model_name."
Райне Еверет

16

Благодатний спосіб зробити це в Django 1.7+:

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

Отже, на канонічному прикладі всіх навчальних посібників:

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

9

Якщо ви не знаєте, в якому додатку існує ваша модель, ви можете шукати її таким чином:

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

Пам’ятайте, що ваше ім’я_модель_ має бути з малих літер.


4

Я не впевнений, де це робиться в Джанго, але ти міг би це зробити.

Зображення назви класу в рядку за допомогою відображення.

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

1
Це клітини .__ клас __.__ ім'я__ або просто дзвінки .__ ім'я__?
Vinayak Kaniyarakkal

4

Ще одне видання з меншим кодом для ледачих. Тестували в Django 2+

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

1

Ось менш специфічний для джанго підхід для отримання класу з рядка:

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

або ви можете використовувати importlib, як показано тут :

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.