1

I have a question regarding the filter() and all() methods of django objects. It is not a question which one of the two is preferred, I just noticed an odd (to me) behavior. Because, as it is laid out in

Django ORM - objects.filter() vs. objects.all().filter() - which one is preferred?

in Django src, both ways should return the same (they both reference the chain() method):

See:

https://github.com/django/django/blob/0963f184abd96800b76b19a6a181e1b544c7fafe/django/db/models/query.py#L928

And:

https://github.com/django/django/blob/0963f184abd96800b76b19a6a181e1b544c7fafe/django/db/models/query.py#L951

So the filter() and all() method should return the same objects. But I recently discovered the following behavior:

MyModel.objects.all()[0].update(name="Test")

# --> $: AttributeError: type object 'MyModel' has no attribute 'update'

# And to check if it indeed has no update method:

MyModel.objects.all[0].__dir__() # --> no update() method in returned dictionary but a save method

So while above code raises Error, line below would work:

MyModel.objects.all()[0].name = "Test"
MyModel.objects.all()[0].save()

However, if the same object is retrieved by the filter() method, it has the update() method.

Why do I get the same object both times but with seemingly different methods added to it?

Hans T
  • 123
  • 1
  • 13
  • 2
    How exactly are you using `filter()`? Are you indexing into its results as well? The return value of `filter()` or `all()` is a queryset and is expected to have an `update()` method, the return value of `all()[0]` is a model instance and is (probably) not expected to have one - if it does it's because the model class does. – Peter DeGlopper Feb 11 '21 at 23:28
  • 2
    Sorry I forgot to add the example for the filter() method. I just call `test_obj = MyModel.objects.filter(name="Test")` and then `test_obj.update(name="Test2")` – Hans T Feb 11 '21 at 23:32
  • As Peter already said .update() is method on QuerySet and it works same for both – iklinac Feb 11 '21 at 23:33
  • now I see the difference. Sorry, it is a bit late here. So the objects.all() is the same as filter() but if I only return the first object by filter, I also get the update() method for this object. Whereas if I do it with `objects.all()[0]` I lose the update() method because now I am operating the model instance itself. – Hans T Feb 11 '21 at 23:35
  • You didn't return first object by filter, you returned QuerySet which can contain x objects depending on your filter condition. To get to model instance you still need to index it out [0] – iklinac Feb 11 '21 at 23:37
  • @iklinac, yeah, that's what I meant. I get a queryset with one object and the update() method. And I lose the update() method by indexing it out – Hans T Feb 11 '21 at 23:39

1 Answers1

0

the update() function is only on the Manager object. Looking at your comments, you are effectively called MyModel.objects.filter(name="Test").update(name="test2") which is a valid queryset function. If you used MyModel.objects.get(name="Test") which would be the same as the all() version.

In your all() example, you are working on the model, which lacks an update() function.

NiBLiTz
  • 26
  • 3