samedi 29 novembre 2014

python - Django ORM - objects.filter() vs objects.all().filter() - lequel est préférable ? -Débordement de pile


Very often I see constructs like


MyModel.objects.all().filter(...)

which will return a QuerySet of the default Mananger. At first all() seems to be quite redundant, because


MyMode.objects.filter(...)

delivers the same result.


However, this seems to be save for the default Manager only, because of the following two statements in the Django documentation:


Excerpt fromt the Chapter "Adding extra manager methods"



A custom Manager method can return anything you want. It doesn’t have to return a QuerySet.



Definition of the all() manager method:



all() Returns a copy of the current QuerySet (or QuerySet subclass). This can be useful in situations where you might want to pass in either a model manager or a QuerySet and do further filtering on the result. After calling all() on either object, you’ll definitely have a QuerySet to work with.



This seems a bit like a contradiction to me. On one hand Django offers the freedom to let a manager method return whatever preferred and on the other hand it requires a QuerySet for the all() method. I'm aware that each manager has a get_queryset method which is called by all(). But who stops me from overriding all() in my custom manager? Although I agree it would be bad design to do so.



  • So as far as I can see, the all() method does not guarantee to return a QuerySet. What exactly does MyModel.objects return? Does this statement call all()? or `get_queryset()?


  • Do you prefer MyModel.objects.filter(...) or MyModel.objects.all().filter(...). And if so, why?


  • Have you ever encountered wonky managers that would mess with those methods in a undesirable way?





all() is actually just an alias to get_queryset(), as you can see in the Django source code:


def all(self):
return self.get_queryset()

https://github.com/django/django/blob/1.6.2/django/db/models/manager.py#L132-L133


So it's just a way to get the queryset. As they explain in the documentation, this can be handy to ensure that you're dealing with a queryset and not a model manager, because MyModel.objects returns a model manager.


For example, if you want to iterate over all the items, you can't do this:


for item in MyModel.objects:
# do something with item

Because you can't iterate over a model manager. all() returns the queryset, you can iterate over a queryset:


for item in MyModel.objects.all():
# do something with item

Generally, you should never overwrite all(). You can overwrite get_queryset() but this method must return a queryset.


If you would use a filter method like filter() or exclude(), you would already have the queryset, because these methods are proxied to the queryset. See: https://github.com/django/django/blob/1.6.2/django/db/models/manager.py#L135-L235. So you don't have to do something like all().filter().





  1. MyModel.objects returns the manager instance. all() return get_query_set(). I think all is there for when you need all objects.

  2. I prefer MyModel.objects.filter() cause the other is just one more method call, and I don't need all objects if I do filter :)

  3. It depends on the purpose. But if they override a base method of the manager, they return the same result format (eg. a QuerySet)



Very often I see constructs like


MyModel.objects.all().filter(...)

which will return a QuerySet of the default Mananger. At first all() seems to be quite redundant, because


MyMode.objects.filter(...)

delivers the same result.


However, this seems to be save for the default Manager only, because of the following two statements in the Django documentation:


Excerpt fromt the Chapter "Adding extra manager methods"



A custom Manager method can return anything you want. It doesn’t have to return a QuerySet.



Definition of the all() manager method:



all() Returns a copy of the current QuerySet (or QuerySet subclass). This can be useful in situations where you might want to pass in either a model manager or a QuerySet and do further filtering on the result. After calling all() on either object, you’ll definitely have a QuerySet to work with.



This seems a bit like a contradiction to me. On one hand Django offers the freedom to let a manager method return whatever preferred and on the other hand it requires a QuerySet for the all() method. I'm aware that each manager has a get_queryset method which is called by all(). But who stops me from overriding all() in my custom manager? Although I agree it would be bad design to do so.



  • So as far as I can see, the all() method does not guarantee to return a QuerySet. What exactly does MyModel.objects return? Does this statement call all()? or `get_queryset()?


  • Do you prefer MyModel.objects.filter(...) or MyModel.objects.all().filter(...). And if so, why?


  • Have you ever encountered wonky managers that would mess with those methods in a undesirable way?




all() is actually just an alias to get_queryset(), as you can see in the Django source code:


def all(self):
return self.get_queryset()

https://github.com/django/django/blob/1.6.2/django/db/models/manager.py#L132-L133


So it's just a way to get the queryset. As they explain in the documentation, this can be handy to ensure that you're dealing with a queryset and not a model manager, because MyModel.objects returns a model manager.


For example, if you want to iterate over all the items, you can't do this:


for item in MyModel.objects:
# do something with item

Because you can't iterate over a model manager. all() returns the queryset, you can iterate over a queryset:


for item in MyModel.objects.all():
# do something with item

Generally, you should never overwrite all(). You can overwrite get_queryset() but this method must return a queryset.


If you would use a filter method like filter() or exclude(), you would already have the queryset, because these methods are proxied to the queryset. See: https://github.com/django/django/blob/1.6.2/django/db/models/manager.py#L135-L235. So you don't have to do something like all().filter().




  1. MyModel.objects returns the manager instance. all() return get_query_set(). I think all is there for when you need all objects.

  2. I prefer MyModel.objects.filter() cause the other is just one more method call, and I don't need all objects if I do filter :)

  3. It depends on the purpose. But if they override a base method of the manager, they return the same result format (eg. a QuerySet)


0 commentaires:

Enregistrer un commentaire