Django получить класс из строки

Я ищу общий способ в Python для создания экземпляра класса по его имени аналогично тому, как это делается в Java, без необходимости явно указывать имя класса в условии IF..ELIF.

Это связано с тем, что у меня есть несколько разных моделей и сериализаторов, и я хочу сделать их доступными по параметрам в HTTP-запросе. Это должно улучшить слабую связанность и модульность.

Например, https://www.domain.com/myapp/sampledata.json?model=<modelname> должен получить классы <modelname> и <modelname>Serializer.

Есть некоторые изменения в этом, начиная с Django 1.7 https://docs.djangoproject.com/en/1.7/ref/models/queries/, до того, как get_model использовался для аналогичных целей.

Начиная с Django 1.7, django.db.models.loading устарел (будет удален в версии 1.9) в пользу новой системы загрузки приложений.

Предупреждение:

RemovedInDjango19Warning: Утилиты в django.db.models.loading устарели в пользу новой системы загрузки приложений.
return f(*args, **kwds)

Как следует изменить следующий код, чтобы получить класс из строки?

просмотры.py

from myapp.models import Samplemodel, Simplemodel1, Simplemodel2
from myapp.serializers import SamplemodelSerializer, Simplemodel1Serializer, Simplemodel2Serializer
from django.db.models.loading import get_model # deprecated
from myapp.jsonp_decorator import json_response

@json_response
def sampledata(request):

    model = request.GET.get('model','Samplemodel')

    if model=='Samplemodel':
        modelName = "Samplemodel"
        serializer = SamplemodelSerializer
    elif model=='Simplemodel1':
        modelName = "Simplemodel1"
        serializer = Simplemodel1Serializer
    elif model=='Simplemodel2':
        modelName = "Simplemodel2"
        serializer = Simplemodel2Serializer

    return serializer(get_model("myapp",modelName).objects.all(), many=True)  

person Peter G.    schedule 01.12.2015    source источник


Ответы (3)


Вы можете использовать getattr:

import my_serializers

serializer_class = getattr(my_serializers, 'SimpleSerializer')
serializer = serializer_class()
person eugecm    schedule 01.12.2015
comment
Кажется, работает с атрибутами, мне нужно что-то подобное с моделями и сериализаторами. - person Peter G.; 01.12.2015
comment
Это будет работать и для классов внутри модулей. Это атрибуты модуля. - person eugecm; 01.12.2015
comment
Вы правы, это работает хорошо, я опубликую обновленный код здесь. - person Peter G.; 01.12.2015

для Django 3+ универсальный способ получить экземпляр модели:

def get_data_instance(model_name):
    """
    Try to find application with name "data" with specific "model_name"
    :param model_name: the name of the class
    :return: model instance or None
    """

    try:
        app_config = apps.get_app_config('data')
        return app_config.get_model(model_name)
    except LookupError:
        pass

    return None
person Igor Fedun    schedule 07.03.2020

Лучший способ разрешить динамическую загрузку классов в этом случае:

from myapp import models
from myapp import serializers
from myapp.jsonp_decorator import json_response

@json_response
def sampledata(request):

    model = request.GET.get('model','Samplemodel')
    serializer_class = getattr(serializers, model+"Serializer")
    return serializer_class(getattr(models,modelName).objects.all(), many=True)
person Peter G.    schedule 01.12.2015