2015-07-20 3 views
2

Я создаю модель Django на основе абстрактного класса модели AbstractAttr и обычной модели (скажем, Foo).Добавить динамически сгенерированную модель Model.py в проект Django

Я хочу, чтобы мой foo/models.py выглядеть следующим образом:

from bar.models import Attrs 
# ... 
class Foo(models.Model): 
    .... 
    attrs = Attrs() 

В классе AttrS, который имитирует поле у ​​меня есть contribute_to_class, который генерирует требуемую модель, используя type(). Сгенерированная модель c называется FooAttr.

Все работает. Если я мигрирую, я вижу, что FooAttr появляется в соответствующей таблице.

ЗА ИСКЛЮЧЕНИЕМ ОДНОГО ВЕЩИ.

Я хочу иметь возможность from foo.models import FooAttr. Как-то мой сгенерированный класс FooAttr не связан с файлом models.py, в котором он сгенерирован.

Если я изменить models.py к этому:

class Foo(models.Model): 
    # ... 

FooAttr = generate_foo_attr_class(...) 

это работает, но это не то, что я хочу (например, это заставляет Дев угадать имя генерировать класс).

Является ли это возможным, определите класс, как в первом примере, и привяжите его к определенному mod.py модулю?

Проекта (пра-альфа) здесь (в разработке филиала): https://github.com/zostera/django-mav

Некоторые соответствующий код:

def create_model_attribute_class(model_class, class_name=None, related_name=None, meta=None): 
    """ 
    Generate a value class (derived from AbstractModelAttribute) for a given model class 
    :param model_class: The model to create a AbstractModelAttribute class for 
    :param class_name: The name of the AbstractModelAttribute class to generate 
    :param related_name: The related name 
    :return: A model derives from AbstractModelAttribute with an object pointing to model_class 
    """ 

    if model_class._meta.abstract: 
     # This can't be done, because `object = ForeignKey(model_class)` would fail. 
     raise TypeError("Can't create attrs for abstract class {0}".format(model_class.__name__)) 

    # Define inner Meta class 
    if not meta: 
     meta = {} 
    meta['app_label'] = model_class._meta.app_label 
    meta['db_tablespace'] = model_class._meta.db_tablespace 
    meta['managed'] = model_class._meta.managed 
    meta['unique_together'] = list(meta.get('unique_together', [])) + [('attribute', 'object')] 
    meta.setdefault('db_table', '{0}_attr'.format(model_class._meta.db_table)) 

    # The name of the class to generate 
    if class_name is None: 
     value_class_name = '{name}Attr'.format(name=model_class.__name__) 
    else: 
     value_class_name = class_name 

    # The related name to set 
    if related_name is None: 
     model_class_related_name = 'attrs' 
    else: 
     model_class_related_name = related_name 

    # Make a type for our class 
    value_class = type(
     str(value_class_name), 
     (AbstractModelAttribute,), 
     dict(
      # Set to same module as model_class 
      __module__=model_class.__module__, 
      # Add a foreign key to model_class 
      object=models.ForeignKey(
       model_class, 
       related_name=model_class_related_name 
      ), 
      # Add Meta class 
      Meta=type(
       str('Meta'), 
       (object,), 
       meta 
      ), 
     )) 

    return value_class 


class Attrs(object): 
    def contribute_to_class(self, cls, name): 
     # Called from django.db.models.base.ModelBase.__new__ 
     mav_class = create_model_attribute_class(model_class=cls, related_name=name) 
     cls.ModelAttributeClass = mav_class 
+0

Можете ли вы разместить соответствующую часть (-ы) определения класса Attrs? – ryanmrubin

+0

Отредактированный вопрос, добавлена ​​ссылка на исходный код и запрошенный код inline. Спасибо, что пытался помочь мне. – dyve

+0

Также я не слишком повешен в классе Attrs. Я попробовал решение декоратора, тот же эффект: класс генерируется, переносится и т. Д., Но он не привязан к моделям. – dyve

ответ

1

Я вижу, вы создаете модель изнутри models.py, так что я подумайте, что вы должны добавить его в глобальные возможности модуля. Как насчет:

new_class = create_model_attribute_class(**kwargs) 
globals()[new_class.__name__] = new_class 
del new_class # no need to keep original around 
0

Спасибо всем за размышление об этом. Я обновил исходный код проекта в GitHub и добавил больше тестов. См https://github.com/zostera/django-mav

Поскольку фактическое поколение моделей осуществляются за пределами foo/models.py (это имеет место в mav/models.py, кажется, Pythonically невозможно связать модель с foo/models.py. Кроме того, после переосмысления это, кажется, автомагический для Python (явные лучше, никакой магии).

так что моя новая стратегия не использовать простые функции, декоратора, чтобы сделать его легко добавить mav и связать сгенерированные модели для mac/attrs.py, так что я могу универсально from mav.attrs import FooAttr. Я также связать сгенерированный класс к модели Foo как Foo._mav_class.

(В этом комментарии Foo, конечно, используется в качестве примерной модели, для которой мы хотим добавить значение model-attribute-value).

Смежные вопросы