1

It seems like django was designed to store data in databases. While writing my first app, I forgot about this and tried to set up a model like so:

class Team(models.Model): 
    stage = 0
    users_score = {}

I soon realised that I could get this attribute but I couldn't set it:

team = Team()
team.stage = 1
team.save()
print Team.objects.get(pk=1).stage

This would print 0 when I expected 1. In my models file I change stage = 0 to

stage = models.IntegerField(default=0)

And it works as I want it to. Why can django get this attribute, but not set it? I'm guessing it's because the setattr() method has been changed. How can I verify this?

jazzabeanie
  • 425
  • 4
  • 15

2 Answers2

1

When you do the assignment team.stage = 1 it only changes the stage value of the instance that the variable team is pointing to. Since it is not a model field, it won't be stored in the database when you call .save() method and, it won't be persisted through multiple Team instances.

Because of that, newly created teams won't have any idea about the current value of stage:

>>> t1 = Team()
>>> t1.stage = 1

>>> t2 = Team()
>>> print t2.stage
0

Also, it is a class variable, which means you can assign its value on class level, so that all instances created from it will be able to access the same value:

>>> Team.stage = 1

>>> t1 = Team()
>>> print t1.stage
1
>>> t2 = Team()
>>> print t2.stage
1

Since Team.objects.get(pk=1) will always return a new instance every time it was called, holding a class variable won't help you much, you have to use a model field, preferably models.IntegerField, in order for all instances to have the same value for stage.

Ozgur Vatansever
  • 49,246
  • 17
  • 84
  • 119
  • So in summary, `team.save()` doesn't work on the `.stage` attribute because it's not linked to the database. But I can still get this attribute because `team = Team()` will assign `team.stage` from my models.py file? – jazzabeanie Dec 21 '15 at 04:48
  • Exactly. `stage` will be set to `0` by default for every instance once you created them but `.save()` only persists attributes defined as model fields. By the way, it is a class variable however, I think you probably should define it as an [instance variable](http://stackoverflow.com/questions/2714573/instance-variables-vs-class-variables-in-python) instead. – Ozgur Vatansever Dec 21 '15 at 08:15
1
stage = models.IntegerField(default=0)

Here stage is a database field with int type and default constraint set to 0. Django knows, how to manage this field.

stage = 0

Here stage is a class field. Django does not know, how to manage it in the database layer. That is why Django skips this field.

Why can django get this attribute, but not set it?

Django is only a framework. Python manages all classes, objects and others. When it creates an object of your class, it initializes the field to zero.

awesoon
  • 32,469
  • 11
  • 74
  • 99