I have an model, let's say something like:
class Invoice(models.Model):
client_name = models.CharField(max_length=100)
And I have a file that looks like:
def foo_1():
for inv in Invoice.objects.all():
inv.client_name = "Joe"
inv.save()
def foo_2(inv):
inv.client_name = "Joe"
inv.save()
My issue occurred when I test it:
class FooCase(TestCase):
def test_foo(self):
inv = Invoice("Jack")
print inv.client_name # output Jack, OK
foo_1()
print inv.client_name # output Jack, KO !
print inv.client_name # output Jack, OK
foo_2(inv)
print inv.client_name # output Joe, OK
I don't understand why there is two differents behaviour :(
I added a modification date to my model, and try to output it in foo_1
before and after the loop for
, the save
seems to work properly, but it is like the object is different...
I don't know if that can help but I also output vars(invoice)
from test_foo
and then from foo_1()
and finally from foo_2()
. The state was the same in test_foo
and foo_2()
(<django.db.models.base.ModelState object at 0x32ca090>
), but not in foo_1()
(<django.db.models.base.ModelState object at 0x32cc650>
)
Django returns a different object each time you retrieve a record from the database:
>>> i1 = Invoice.objects.all()[0]
>>> i2 = Invoice.objects.get(pk=i1.pk)
>>> i1 == i2
True // since model instances compare by their id field only
>>> id(i1) == id(i2)
False // since they are actually separate instances
You instantiate inv = Invoice("Jack")
before calling foo_1
, so after foo_1
updates all invoices, you still have your old inv
instance, which hasn't been updated (since foo_1
instantiates its model objects itself, which are separate instances and do not affect inv
) and hasn't been reloaded from the database — nothing has modified inv.client_name
, although the record in the database has been updated. foo_2
, on the other hand, works on that specific instance that you pass as an argument, so you see the changed client_name
; you would actually see that change even if you don't save the instance.