Django: Dapatkan model dari string?

133

Di Django, Anda dapat menentukan hubungan seperti:

author = ForeignKey('Person')

Dan kemudian secara internal harus mengubah string "Person" ke dalam model Person.

Di mana fungsi yang melakukan ini? Saya ingin menggunakannya, tetapi saya tidak dapat menemukannya.

Mpen
sumber

Jawaban:

167

Pada Django 3.0, itu AppConfig.get_model(model_name, require_ready=True)

Pada Django 1.9 metodenya adalah django.apps.AppConfig.get_model(model_name).
- danihp

Pada Django 1.7 yang django.db.models.loadingsudah usang (akan dihapus pada 1.9) mendukung sistem pemuatan aplikasi baru.
- Scott Woodall


Menemukannya. Itu didefinisikan di sini:

from django.db.models.loading import get_model

Didefinisikan sebagai:

def get_model(self, app_label, model_name, seed_cache=True):
Mpen
sumber
11
Solusi ini sudah usang dalam Django 1.7, lihat jawaban lain untuk solusinya: stackoverflow.com/a/26126935/155987
Tim Saylor
4
Hai @mpen, saya sarankan kepada Anda untuk memperbarui jawaban Anda. Pada django 1.9 get_model didefinisikan di AppConfig :from django.apps import AppConfig
dani herrera
1
django.apps.AppConfig adalah tipe generator yang tidak bisa bekerja seperti objek model.
Neeraj Kumar
2
Dalam Django 1.7+ lebih baik menggunakan get_model () pada registri aplikasi Django, yang tersedia via django.apps.apps.get_model(model_name). Objek AppConfig dimaksudkan untuk tujuan yang berbeda, dan mengharuskan Anda untuk membuat instance AppConfig untuk memanggil get_model().
zlovelady
2
Django 1.11 membutuhkan jawaban yang diberikan oleh @luke_aus
Georg Zimmer
132

django.db.models.loadingitu usang dalam Django 1,7 ( dihapus dalam 1,9 ) mendukung baru sistem loading aplikasi .

Django 1.7 docs memberi kami yang berikut:

>>> 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
sumber
Saya dulu menggunakan fungsi "temukan" pydoc ... tidak yakin akan perbedaannya di sini, tetapi untuk tetap berada dalam Django saya sudah beralih ke metode ini. Terima kasih.
warath-coder
61

hanya untuk siapa saja yang macet (seperti saya):

from django.apps import apps

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

app_nameharus terdaftar menggunakan tanda kutip, sebagaimana mestinya model_name(yaitu jangan mencoba mengimpornya)

get_model menerima huruf kecil atau huruf besar 'model_name'

lukeaus
sumber
32

Sebagian besar model "string" muncul sebagai bentuk "appname.modelname" sehingga Anda mungkin ingin menggunakan variasi ini di get_model

from django.db.models.loading import get_model

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

Bagian dari kode Django yang biasanya mengubah string tersebut menjadi model sedikit lebih kompleks dari ini 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)

Bagi saya, ini tampaknya menjadi kasus yang baik untuk memisahkan ini menjadi satu fungsi dalam kode inti. Namun, jika Anda tahu string Anda dalam format "App.Model", kedua liner di atas akan berfungsi.

Ch'marr
sumber
3
Saya pikir 2 baris harus: your_model = get_model(*your_string.rsplit('.', 1)). Label aplikasi terkadang berupa format bertitik, namun nama model selalu merupakan pengidentifikasi yang valid.
Rockallite
1
Sepertinya ini tidak perlu di yang baru apps.get_model. "Sebagai jalan pintas, metode ini juga menerima satu argumen dalam formulir app_label.model_name."
Ryne Everett
16

Cara terberkati untuk melakukan ini dalam Django 1.7+ adalah:

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

Jadi, dalam contoh kanonik semua tutorial kerangka kerja:

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

Jika Anda tidak tahu di mana aplikasi model Anda ada, Anda dapat mencarinya dengan cara ini:

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

Ingat bahwa nama_model_Anda harus lebih kecil.

Ola Nguyen Van
sumber
4

Saya tidak yakin di mana hal itu dilakukan di Django, tetapi Anda bisa melakukan ini.

Memetakan nama kelas ke string melalui refleksi.

classes = [Person,Child,Parent]
def find_class(name):
 for clls in classes:
  if clls.__class__.__name__ == name:
   return clls
jbcurtin
sumber
1
Apakah itu clls .__ class __.__ name__ atau hanya clls .__ name__?
Vinayak Kaniyarakkal
4

Rendition lain dengan kode kurang untuk malas. Diuji dalam Django 2+

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

Berikut ini adalah pendekatan yang kurang spesifik jjango untuk mendapatkan kelas dari string:

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

atau Anda dapat menggunakan importlib seperti yang ditunjukkan di sini :

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