2016-02-23 2 views
4

У меня есть модель, как эта:Джанго «не могут установить атрибут» в модели

class MyReport(models.Model): 
    group_id = models.PositiveIntegerField(blank=False, null=False) 
    test  = models.ForeignKey(Test, on_delete=models.CASCADE) 
    owner  = models.ForeignKey(User, editable=False, default=get_current_user, on_delete=models.CASCADE) 

    user_objects = UserFilterManager() 

    @property 
    def location(self): 
     return self.test.location 

, к которому я добавил местоположения недвижимости. Я получаю эту ошибку во время выполнения. Я вставил только части ниже моего последнего вызова, который был в len() в этом случае (я знаю, используйте вместо счет).

File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 240, in __len__ 
    self._fetch_all() 
    File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 1074, in _fetch_all 
    self._result_cache = list(self.iterator()) 
    File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 75, in __iter__ 
    setattr(obj, attr_name, row[col_pos]) 
AttributeError: can't set attribute 

Не могу понять, почему ошибка? Если я назову это locationx, то ошибок не будет.

Существуют ли какие-либо специальные правила определения свойств для Django?

Как я мог отладить это?

Я добавил собственность, поскольку я добавил тест косвенным образом и хочу изменить как можно меньше кода. Я мог бы, конечно, просто изменить каждый report.location на report.test.location, но это неприятность. Было бы здорово, если бы я мог определить псевдоним для поиска БД, поэтому мне тоже нужно будет изменить их.

EDIT: Для того, чтобы ответить на комментарии:

  1. Я не хочу, чтобы установить значение, я просто хочу, свойство (геттер). Я хочу иметь возможность делать report.location вместо добавления нумерации report.test.location (не хочу менять существующий код, где местоположение находилось внутри модели отчета).
  2. self.test.location и report.test.location работа, а также reports.locationx работ также.
  3. Я упомянул об этом выше, но повторю. Все, что я сделал, это вызвать len() по запросу, например. len(MyReport.objects.all()).

Вот полный след от консоли Eclipse:

Traceback (most recent call last): 
    File "C:\Eclipse-SDK-4.2.1-win32-x86_64\plugins\org.python.pydev_2.7.1.2012100913\pysrc\pydevd_comm.py", line 765, in doIt 
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec) 
    File "C:\Eclipse-SDK-4.2.1-win32-x86_64\plugins\org.python.pydev_2.7.1.2012100913\pysrc\pydevd_vars.py", line 378, in evaluateExpression 
    sys.stdout.write('%s\n' % (result,)) 
    File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 234, in __repr__ 
    data = list(self[:REPR_OUTPUT_SIZE + 1]) 
    File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 258, in __iter__ 
    self._fetch_all() 
    File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 1074, in _fetch_all 
    self._result_cache = list(self.iterator()) 
    File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 75, in __iter__ 
    setattr(obj, attr_name, row[col_pos]) 
AttributeError: can't set attribute 
+0

Если вы хотите установить значение 'self.test.location', а затем определите [setter] (https://docs.python.org/2/library/functions.html#property) для' location ':' @ location.setter'. –

+0

Совет: поставьте 'import ipdb; ipdb.set_trace'just перед возвратом свойства попытайтесь получить доступ к 'self.test.location'. ;-) –

+0

Вы не показали, что вы делаете, чтобы вызвать эту ошибку. –

ответ

6

Проблема была конфликта имен.

Видимо при запросе DB у меня был:

objs = MyReport.objects.annotate(location=F('test__location'))

Это добавило location к объектам (не видел его в __dict__, но, возможно, я просто пропустил его). Это означает, что я мог бы отказаться от собственности, так как я мог позвонить report_instance.location. Конечно, это означает, что все места, которые обращаются к MyReport, мне нужно добавить аннотацию (специальный менеджер?).

+0

Спасибо, что поделились ответами. У меня была та же проблема, а затем обнаружил, что свойство было сохранено на модели с тем же именем, на которое я пытаюсь аннотировать. –

0

Try, чтобы гарантировать, что test установлено:

@property 
def location(self): 
    return self.test.location if self.test else None 
+0

Функция 'location' ** не называется ** вообще. Неважно, что делает функция (я попробовал распечатать строку и вернуть «Нет»). По какой-то причине мне не нравится имя, которое мне нужно использовать - * sheet * в этом конкретном случае. – mibm