Why use custom Querysets instead of custom model Managers? - python

It seems like much of what can be done by a custom Queryset can be accomplished by a model Manager. So why use custom Querysets instead of model Managers?

Custom querysets allow for chaining methods, while custom managers only let you access defined methods directly from the manager. If you need to expose methods from the manager and the queryset, you can use Queryset.as_manager.
Take a look at: https://docs.djangoproject.com/en/1.9/topics/db/managers/#create-manager-with-queryset-methods

Related

Should my soft-deletion-honouring model manager be my model's default manager?

I am building soft-deletion functionality for my Django project. I have implemented this using a custom model manager (i.e. performing an initial filter on get_queryset(), plus overriding Model / Manager / QuerySet delete().
Django documentation (1.11):
If you use custom Manager objects, take note that the first Manager Django encounters (in the order in which they’re defined in the model) has a special status. Django interprets the first Manager defined in a class as the “default” Manager, and several parts of Django (including dumpdata) will use that Manager exclusively for that model. As a result, it’s a good idea to be careful in your choice of default manager in order to avoid a situation where overriding get_queryset() results in an inability to retrieve objects you’d like to work with.
My soft delete-honouring manager is currently my model's default manager (first manager declared on the model class). It's also assigned to objects.
This is convenient for me as a lot of Django code uses the default model manager (e.g. MultipleObjectMixin.get_queryset() if your MultipleObjectMixin-inheriting View just has the model attribute defined).
However the fact that dumpdata also uses the custom model manager has scared me off, and has me thinking about other unknown unintended consequences of setting the default model manager. In the event that I perform a manage.py dumpdata, I'd want my soft-deleted models to be contained in the dump. So I am beginning to doubt myself regarding my choice in overriding the default model manager to filter down the available records.
At the same time, I appreciate the convenience that setting the default model manager is giving me (zero-effort support for generic CBVs.etc), which I want to maintain if possible.
What's the best way to approach this?
As per this documentation, if you run ./manage.py dumpdata -a or ./manage.py dumpdata --all, then it will dump data using default manager instead of custom manager. If you want to use your default manager instead of custom manager(without changing in models) then you can try like this:
objects = YourModel._base_manager
objects.all()

when should I write custom methods in model vs model manager/ queryset

when should I write methods in the model itself and when in the model manager?
is it like all methods to get something should be written in manager and others in model
There's a simple difference. Model methods act on a single instance. Manager methods create queries to act on multiple instances.

Where is the declaration of objects of django model?

In django documentation, it say that we can retrieve data entry as below
entry = Entry.objects.get(pk=1)
Entry is a model class in models.py. I tried to find the declaration of objects, but I can't find its declaration in manager.py, just know it is a instance of Manager. So, where is the declaration of objects? Does it represent a set of Entry instances?
When you define model, you extend Model class from django.db.models module.
It will provide default model manager in objects property.
If you want to define custom model manager, you can do it by subclassing django.db.models.Manager class.
Look at the docs how to do that: https://docs.djangoproject.com/en/1.11/topics/db/managers/
Add methods to custom model managers to if you want to manipulate with the collection of data. If you manipulate with single row, add method to your model.
It's defined in ModelBase, which is the metaclass for model classes. See https://github.com/django/django/blob/master/django/db/models/base.py#L360

If model has a customized manager, how can I use default?

If model defined with custom manager, but I need to query database with default Django manager django.db.models.manager.Manager - how can I do that?
UPDATE
Main issue is that I don't have access to the code, and the model does not have standard manager available, only customized one.
Keep your custom managers after the default manager. Like this:
# Then hook it into the Book model explicitly.
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
dahl_objects = DahlBookManager() # The Dahl-specific manager.
You are free to use both Book.objects.<...> and Book.dahl_objects.<...> for filtering. However, there are a few things to note with managers, esp. default ones. From managers documentation:
If you use custom Manager objects, take note that the first Manager Django encounters (in the order in which they’re defined in the model) has a special status. Django interprets the first Manager defined in a class as the “default” Manager, and several parts of Django (including dumpdata) will use that Manager exclusively for that model. As a result, it’s a good idea to be careful in your choice of default manager in order to avoid a situation where overriding get_queryset() results in an inability to retrieve objects you’d like to work with.
A reminder which has caused me headaches in the past:
Do not filter away any results in this type of manager subclass
One reason an automatic manager is used is to access objects that are related to from some other model. In those situations, Django has to be able to see all the objects for the model it is fetching, so that anything which is referred to can be retrieved.

Django: user profile creation forms

As I've understood the deal, the standard way of extending the User Django model is by implementing profiles.
This suits me wonderfully, since I have 3 types of profiles (3 different Model subclasses) all based upon the User model for uniqueness and authentication.
I'm having trouble deciding, however, on the best way of implementing a user creation form. Should I...
Use mixins: inherit a ModelForm with model=User and one with model=Profile, manually overriding save() and clean() to call the bases' methods and perform the foreign key assignment.
Use composition: inherit Form and manually instantiate and manage two ModelForms.
Instantiate the forms separately, and save() them in a manually ordered fashion.
The Best Way I Didn't Think Of.
I would appreciate a (however minimal) implementation so I can be sure I'm making the right calls.
Thanks in advance.
You can write a single form that acts as a combined ModelForm for both your Profile model and the contrib User model. To accomplish this, a little manipulation of the forms kwargs on init is required. See this snippet: http://djangosnippets.org/snippets/2081/

Categories