Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django "can't set attribute" in model

Tags:

python

django

I have a model like this one:

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 

to which I added a location property. I get this error at run-time. I pasted only parts below my latest call, which was to len() in this case (I know, use count instead).

  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 

I cannot figure why the error? If I call it locationx then there is no error.

Are there some special property definition rules for Django?

How could I debug this?

I added the property since I added the test indirection and want to change as little code as possible. I could, of course, just change each report.location to report.test.location, but that's a nuisance. It would be great if I could define an alias for DB searches so I would need to change those either.

EDIT: To answer the comments:

  1. I do not want to set the value, I just want a property (getter). I want to be able to do report.location instead adding an indirection report.test.location (don't want to change existing code where location was inside the report model).
  2. self.test.location and report.test.location work, and also reports.locationx works as well.
  3. I mentioned this above, but I will repeat. All I did was to call len() on a query, e.g. len(MyReport.objects.all()).

Here is a full trace from the Eclipse console:

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 
like image 963
mibm Avatar asked Feb 23 '16 17:02

mibm


People also ask

Can't set attribute values?

How is it possible? The explanation you are getting this error is that you are naming the setter method mistakenly. You have named the setter method as set_x which is off base, this is the reason you are getting the Attribute Error.

Can't set attribute named tuple?

Namedtuples are immutable objects, so you cannot change the attribute values. But standard Python classes are mutable, so they can be changed arbitrarily. Specifically, you can change an existing attribute's value and even dynamically add a new attribute to an existing object.


2 Answers

The problem was a name clash.

Apparently when querying the DB I had:

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

This added location to the objects (didn't see it in __dict__, but maybe I just missed it). This means I could give up the property since I could call report_instance.location. Of course, this means that all places that access MyReport I need to add the annotation (a special manager?).

like image 109
mibm Avatar answered Sep 28 '22 10:09

mibm


I have the same problem. I solved it by

@location.setter def location(self, val):     pass 
like image 32
Ivan Lavrenov Avatar answered Sep 28 '22 10:09

Ivan Lavrenov