2013-09-16 1 views
0

У меня есть две разные модели, которые я хотел бы фильтровать аналогичным образом с помощью общего имени поля в разное время, поэтому я написал одну функцию контекста, которая обрабатывает обе модели, беря строку как аргумент для использования в качестве имени модели. Прямо сейчас я использую eval(), но что-то в моей кишке говорит мне, что это серьезная ошибка. Есть ли более питонический способ сделать то, что я описываю?Рекомендации по передаче имен моделей в виде строк

Вот сокращенный вариант того, что мой код выглядит на данный момент:

def reference_context(model, value): 
    menu = main_menu() 
    info = company_info() 
    pages = get_list_or_404(eval(model), category = value) 

Во-вторых, есть ли способ передать ключевое слово в подобной манере, так что я мог бы что-то вдоль линий:

def reference_context(model, category, value): 
    menu = main_menu() 
    info = company_info() 
    pages = get_list_or_404(eval(model), eval(category) = value) 

И комментарий по любой другой проблеме приветствуется и очень рекомендуется.

+0

Почему вам нужно передать модель в виде строки, а не в качестве эталона? Например. reference_context (MyModel, value) –

+0

Не знаю, насколько я знаю. В таком случае я бы сделал свой собственный явный реестр имен-> моделей (простой dict будет делать) и использовать это. Таким образом, вы избегаете неожиданных проблем с безопасностью, когда кто-то вводит «Пользователь» в качестве модели в ваших формах. –

ответ

1

Если они происходят из того же модуля (models.py), вы можете использовать getattr, чтобы получить класс модели, и kwargs (а ДИКТ с двумя звездочками) следующим образом:

from myapp import models 

def reference_context(model, value): 
    menu = main_menu() 
    info = company_info() 
    pages = get_list_or_404(getattr(models, model), **{category: value}) 
1

Вы можете использовать get_model функция утилит, которая принимает имя приложения и имя модели.

from django.db.models import get_model 
User = get_model("auth", "User") # returns django.contrib.auth.models.User 
1

Я действительно не понимаю, почему вам нужно передать модель в виде строки - просто передайте ссылку на модель. Например.

class ModelA(models.Model): 
    ... 

class ModelB(models.Model): 
    ... 

def reference_context(model, **kw): 
    menu = main_menu() 
    info = company_info() 
    pages = get_list_or_404(model, **kw) 
    # ... 

В этой настройке вы можете передать любую модель и любой интересующий вас запрос, например.

reference_context(ModelA, category="Hello") 

или

reference_context(ModelB, item__ordered__lte=now) 

Как объяснялся в моем комментарии, если вам действительно нужно отобразить строки в модель, использовать явный реестр/отображение. Это не позволяет манипулировать данные формы, которые могли бы позволить им создать пользователь в смене, например, «Книга»:

model_map = dict(book=ModelA, magazine=ModelB) 
reference_context(model_map[model_as_string], ...)