2012-03-05 4 views
1

Я хочу, чтобы мое поле модели пользовательской модели Django устанавливало атрибут экземпляра модели.Экземпляр экземпляра модели из поля модели

Я уверен, что это не работает таким образом, но вот пример:

class MyField(models.Field): 
    __metaclass__ = models.SubfieldBase 
    def __init__(self, *args, **kwargs): 
     super(MyField, self).__init__(*args, **kwargs) 
     model_instance = ???? 
     setattr(model_instance, "extra_attribute", "It's working!") 

class MyModel(models.Model): 
    my_field = MyField() 

model_instance = MyModel.objects.get(pk=123) 
print model_instance.extra_attribute # output: "It's working!" 

ForeignKey модель поле Джанго делает подобную вещь, так что можно: P Я думаю ForeignKey поля с помощью Способ Contrib_to_class.

ответ

-2

Как насчет

model_instance = SomeExtraModel.objects.get(pk=1456) 

1456 замена с чем-то, что имеет смысл

+0

Нет, вы должны положить это вместо строки с помощью ???? –

+0

Хорошо. Как передать значение pk в поле? –

-1

INIT вызывается, когда Джанго обрабатывает модель класса, а не экземпляра модели. Таким образом, вы можете добавить атрибут в класс модели (например, используя «add_to_class» http://www.alrond.com/en/2008/may/03/monkey-patching-in-django/). Чтобы добавить атрибут к экземпляру, вы должны переопределить init экземпляра (но я думаю, что это не ваш случай).

+0

Нет, init называется последним шагом в построении объекта. – Marcin

+0

@Marcin: Спасибо, я, вероятно, неправильно понял фактический поток. Можете ли вы опубликовать некоторую документацию об этом? – Don

+0

У них нет google в вашей стране? – Marcin

0

У вас нет доступа к экземпляру модели из вашего объекта Field, извините. Django's ForeignKey выполняет команду foo_id, имея отдельные поля name и attname, но фактическая настройка foo_id = 123 выполняется так же, как и все другие поля модели, deep in the QuerySet code, не взаимодействуя с полевыми классами.

И концептуально, что вы пытаетесь сделать, это плохая идея - действие на расстоянии. Что делать, если добавление определенного поля может привести к ошибкам в несвязанной функциональности модели, скажем, если атрибут, который ожидало другое поле, получил переопределение? Было бы сложно отладить, мягко говоря. Я не знаю, какова ваша основная цель, но это, вероятно, должно быть сделано в коде модели, а не в полевом классе.

Вот ModelField, который делает то, что вы хотите:

https://gist.github.com/1987190

Это на самом деле довольно старая (как, может быть предварительно 1.0, не помню), пришлось вычистить его немного - я m не уверен, что он все еще работает. Но это определенно выполнимо, надеюсь, это дает вам представление.

+0

Я пытаюсь создать поле, которое поддерживает отношение к любой модели (например, GenericForeignKey, но в одном поле). Он сохранит «% d.% D»% (model_type, instance.pk) в charfield. Имя поля будет «% s_guid»% name (= model_instance.my_field_guid). Я хочу попасть в БД и обслуживать соответствующий экземпляр, когда вызывается model_instance.my_field (как это делает Foreignkey). Спасибо –

+0

О, ну это просто :). Я думал, вы хотели установить произвольные другие поля. Я обновлю пример «ModelField», который я сижу. – AdamKG

+0

= D это здорово! –

0

Вы можете создать специальный класс Proxy, который заменит это поле. Когда вы получаете или устанавливаете значение поля, вы можете использовать атрибут «obj» для доступа к экземпляру модели. См. Этот пример:

class ObjectField(models.PositiveSmallIntegerField): 
    class ObjectProxy: 
     def __init__(self, field): 
      self.field = field 

     def __get__(self, obj, model): 
      if obj is None: 
       return self.field # this is required for initializing model field 

      value = obj.__dict__[self.field.name] # get actual field value 
      # ... here you can do something with value and model instance ("obj") 

      return value 

     def __set__(self, obj, value): 
      # same here 
      obj.__dict__[self.field.name] = value 

    def contribute_to_class(self, cls, name): 
     super().contribute_to_class(cls, name) 
     # set up our proxy instead of usual field 
     setattr(cls, name, ObjectField.ObjectProxy(self)) 
Смежные вопросы