1

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>)

Thom
  • 1,473
  • 2
  • 20
  • 30
  • What error does it give you? Or does it just not save it to the db? – Hoopdady Feb 26 '14 at 17:00
  • Oh, also the `inv = Invoice("Jack")` won't be in the database until you run `inv.save()`, So it won't be affected by `foo_1()`. I'm also very interested that the final `inv.client_name` output is `Joe` it seems like it should be `LOL`. – Hoopdady Feb 26 '14 at 17:03
  • `inv` will not be affected by `foo_1` even if it were saved before calling `foo_1`. – lanzz Feb 26 '14 at 17:12

3 Answers3

4

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.

lanzz
  • 42,060
  • 10
  • 89
  • 98
1

Jack isn't saved in the DB when you save it. You haven't created an object to the database for your query to iterate over. However, you do have an obj you can pass around. Which is why you can change the objects attribute and save them.

user133688
  • 6,864
  • 3
  • 20
  • 36
0

Your inv object is stored locally so has not changed in the first instance. If you wish to continue to use the object just refresh the object from the db to get the latest attribute saved.

print inv.client_name
foo_1()
inv.refresh_from_db()
print inv.client_name
Alex
  • 1