Django: รับโมเดลจากสตริง?


133

ใน Django คุณสามารถระบุความสัมพันธ์เช่น:

author = ForeignKey('Person')

และจากนั้นภายในก็มีการแปลงสตริง "บุคคล" Personลงในรูปแบบ

ฟังก์ชันนี้อยู่ที่ไหน อยากใช้ แต่หาไม่เจอ

คำตอบ:


167

สำหรับ Django 3.0 มันคือ AppConfig.get_model(model_name, require_ready=True)

สำหรับ Django 1.9 วิธีการคือdjango.apps.AppConfig.get_model(model_name).
- danihp

ในขณะที่ Django 1.7 django.db.models.loadingถูกเลิกใช้งาน (ที่จะลบออกใน 1.9) เพื่อรองรับระบบโหลดแอปพลิเคชันใหม่
- Scott Woodall


พบแล้ว กำหนดไว้ที่นี่:

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
Tim Saylor

4
สวัสดี @mpen ฉันขอแนะนำให้คุณอัปเดตคำตอบของคุณ บน django 1.9 get_model ถูกกำหนดบน AppConfig :from django.apps import AppConfig
dani herrera

1
django.apps.AppConfig เป็นประเภทเครื่องกำเนิดไฟฟ้าที่ไม่สามารถทำงานได้เหมือนกับวัตถุโมเดล
Neeraj Kumar

2
ใน Django 1.7+ จะดีกว่าถ้าใช้ get_model () ในการลงทะเบียนแอป Django ซึ่งมีให้ผ่านทางdjango.apps.apps.get_model(model_name)ไฟล์. วัตถุ AppConfig มีไว้สำหรับวัตถุประสงค์อื่นและต้องการให้คุณสร้างอินสแตนซ์ AppConfig เพื่อเรียกget_model()ใช้
zlovelady

2
Django 1.11 ต้องการคำตอบจาก @luke_aus
Georg Zimmer

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
ฉันคิดว่าบรรทัดที่ 2 ควรเป็น: your_model = get_model(*your_string.rsplit('.', 1)). ป้ายกำกับแอปบางครั้งเป็นรูปแบบจุด แต่ชื่อรุ่นจะเป็นตัวระบุที่ถูกต้องเสมอ
Rockallite

1
apps.get_modelลักษณะเช่นนี้ไม่จำเป็นในใหม่ "ในฐานะทางลัดวิธีนี้ยังยอมรับอาร์กิวเมนต์เดียวในรูปแบบapp_label.model_name"
Ryne Everett

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()

โปรดจำไว้ว่า your_model_name ต้องเป็นตัวพิมพ์เล็ก


4

ฉันไม่แน่ใจว่าจะทำที่ไหนใน Django แต่คุณสามารถทำได้

การแม็พชื่อคลาสกับสตริงผ่านการสะท้อน

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

1
มัน clls .__ class __.__ name__ หรือ clls .__ name__?
Vinayak Kaniyarakkal


1

นี่คือวิธีการเฉพาะ django ที่น้อยลงในการรับคลาสจากสตริง:

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')

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.