Django: Lấy mô hình từ chuỗi?


133

Trong Django, bạn có thể chỉ định các mối quan hệ như:

author = ForeignKey('Person')

Và sau đó, bên trong nó phải chuyển đổi chuỗi "Person" thành mô hình Person.

Chức năng này ở đâu? Tôi muốn sử dụng nó, nhưng tôi không thể tìm thấy nó.

Câu trả lời:


167

Kể từ Django 3.0, nó AppConfig.get_model(model_name, require_ready=True)

Theo Django 1.9, phương pháp này là django.apps.AppConfig.get_model(model_name).
- danihp

Kể từ Django 1.7, việc django.db.models.loadingnày không được chấp nhận (sẽ bị xóa trong 1.9) để ủng hộ hệ thống tải ứng dụng mới.
- Scott Woodall


Tìm thấy rồi. Nó được định nghĩa ở đây:

from django.db.models.loading import get_model

Định nghĩa là:

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

11
Giải pháp này không được chấp nhận trong Django 1.7, hãy xem câu trả lời khác cho giải pháp này: stackoverflow.com/a/26126935/155987
Tim Saylor

4
Xin chào @mpen, tôi đề nghị bạn cập nhật câu trả lời của bạn. Trên django 1.9 get_model được xác định trên AppConfig :from django.apps import AppConfig
dani herrera

1
django.apps.AppConfig là một loại trình tạo không thể hoạt động như đối tượng mô hình.
Neeraj Kumar

2
Trong Django 1.7+, tốt hơn là sử dụng get_model () trên sổ đăng ký ứng dụng Django, có sẵn thông qua django.apps.apps.get_model(model_name). Các đối tượng AppConfig được dành cho một mục đích khác và yêu cầu bạn tạo một cá thể AppConfig để gọi get_model().
zlovelady

2
Django 1.11 cần câu trả lời được cung cấp bởi @luke_aus
Georg Zimmer

132

django.db.models.loadingkhông được chấp nhận trong Django 1.7 ( đã bị xóa trong 1.9 ) vì hệ thống tải ứng dụng mới .

Thay vào đó, các tài liệu Django 1.7 cho chúng ta như sau:

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

Tôi đã từng sử dụng chức năng "định vị" của pydoc ... không chắc về sự khác biệt ở đây, nhưng để ở trong Django, tôi đã chuyển sang phương pháp này. Cảm ơn.
codath-coder

61

chỉ dành cho bất cứ ai gặp khó khăn (như tôi đã làm):

from django.apps import apps

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

app_namenên được liệt kê bằng cách sử dụng dấu ngoặc kép, như vậy model_name(nghĩa là đừng cố gắng nhập nó)

get_model chấp nhận chữ thường hoặc chữ hoa 'model_name'


32

Hầu hết các "chuỗi" mô hình xuất hiện dưới dạng "appname.modelname", do đó bạn có thể muốn sử dụng biến thể này trên get_model

from django.db.models.loading import get_model

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

Một phần của mã django thường biến các chuỗi như vậy thành một mô hình phức tạp hơn một chút Điều này từ 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)

Đối với tôi, đây có vẻ là một trường hợp tốt để phân tách điều này thành một chức năng duy nhất trong mã lõi. Tuy nhiên, nếu bạn biết chuỗi của bạn ở định dạng "App.Model", hai lớp lót ở trên sẽ hoạt động.


3
Tôi nghĩ rằng dòng thứ 2 nên là : your_model = get_model(*your_string.rsplit('.', 1)). Nhãn ứng dụng đôi khi là định dạng chấm, tuy nhiên tên mô hình luôn là định danh hợp lệ.
Rockallite

1
Có vẻ như điều này không cần thiết trong cái mới apps.get_model. "Là một phím tắt, phương thức này cũng chấp nhận một đối số duy nhất trong biểu mẫu app_label.model_name."
Ryne Everett

16

Cách may mắn để làm điều này trong Django 1.7+ là:

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

Vì vậy, trong ví dụ kinh điển của tất cả các hướng dẫn khung:

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

9

Trong trường hợp bạn không biết mô hình của mình tồn tại trong ứng dụng nào, bạn có thể tìm kiếm theo cách này:

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

Hãy nhớ rằng your_model_name phải là chữ thường.


4

Tôi không chắc nó đã được thực hiện ở đâu trong Django, nhưng bạn có thể làm điều này.

Ánh xạ tên lớp vào chuỗi thông qua sự phản chiếu.

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

1
Có phải clls .__ class __.__ name__ hay chỉ clls .__ name__?
Vinayak Kaniyarakkal

4

Một phiên bản khác với ít mã hơn cho người lười biếng. Đã thử nghiệm trong Django 2+

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

1

Đây là một cách tiếp cận ít cụ thể hơn django để có được một lớp từ chuỗi:

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

hoặc bạn có thể sử dụng importlib như hiển thị ở đây :

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.