Django Model vs. Manager - django

Not really sure what the difference is. Seems like all the Manager does is have a bunch of functions related to the Model. But these functions could also be placed in the Model too....
Django documentation describes the Manager as follows,
A Manager is the interface through which database query operations are
provided to Django models.
So is there anything else fundamentally different about the Manager than this simple abstraction?
Or a better question: what methods should be defined in the Model vs. the Manager? Is there an ACTUAL difference or just stylistic one?

In Django, a models' manager is the object through which models perform database queries. Each Django model has at least one manager, which is objects, and you can create your own to change the default behavior.
So, your statement
But these functions could also be placed in the Model too
Well, not really because the model is still depending on the default manager to retrieve the queryset.
Let me try to explain in terms of an example. Lets say your application requires a model object to show only objects with a status of published. Now, MyModel.objects.all() retrieves everything, and you would have to specify the filter MyModel.objects.filter(published=True) every single time.
Now, you can override this default behavior.
class MyModelAdmin(admin.ModelAdmin):
def queryset(self, request):
return MyModel.objects.filter(published=True)
What we just did was override the default behaviour of the default manager.
Now, lets say you want everything, You can do something like
class MyModelAdmin(admin.ModelAdmin):
def queryset(self, request):
return MyModel.objects.filter(published=True)
def all_objects(self, request):
return MyModel.objects.all()
and while accessing all objects, just do
MyModel.objects.all_objects()
It is also possible to have multiple managers to a single model
In short, managers give a lot of flexibility in terms of accessing querysets to the model.

Related

Does the model, the view or the serializer represent a REST resource in Django Rest Framework?

I am building an API using Django Rest Framework, and I'm trying to make it as RESTful as possible. Following this question (and also this question on SoftwareEngineering), I have described a number of resources that my API endpoints will expose, such as an Invoice that can be seen at the following URL: /api/v1/invoices/<invoicenumber>/
However, I am having trouble relating the RESTful design principles to the concrete workings of Django Rest Framework. It is unclear to me what constitues a resource: the model, the serializer or the view?
In particular, I am confused about the correct place to implement my calculate_total() method. In a regular Django application it would certainly live in the the Invoice model:
class InvoiceModel(models.Model):
def calculate_total(self):
# do calculation
return total
Although the actual calculation could be complex, the "total" is conceptually a part of the representation of the Invoice. In this sense, the resource is more equivalent to the InvoiceSerializer:
class InvoiceSerializer(serializers.Serializer):
total = serializers.SerializerMethodField()
def get_total(self, obj):
# do calculation
return total
Finally, the resource will always be accessed by a view. So you could also argue that the view is actually the resource, while the serializer and the model are simply implementation details:
class InvoiceView(APIView):
def calculate_total(self, obj):
# do calculation
return total
If I would have to designate one of the above classes as the canonical representation of the Invoice as a resource, which one would it be? Should I implement my method on the model class, the serializer class, or the view class? Or perhaps I am overthinking this and any one of them will do?
Well, although I agree that there might be different solutions, In this case I would definitely go with the model. As the resource and the place where to put the function.
In the case of the function, it could even be implemented as a calculated attribute of the invoice. Actually, to me TOTAL looks more like an attribute that a method.
Anyway, it seems interesting to me your train of thought and how you get to the other two options, serializer and the view.
I think that the model it is definitely a resource. In this case for me, the invoice resource is the model. So I would say that every model that your API is going to publish, is a resource.
I also think that whenever the resource is not directly related to a single model, the view could be considered the resource.
Now, the serializer is an enigma to me. I can't think of a case that it could be think it as a resource.

Django - getting the original class name in abstact method

What I am trying to do is best described by the following example:
class MyAbstractClass(models.Model):
abstract_field = IntegerField()
class Meta:
abstract = True
def abstract_method(self):
# THE ISSUE LIES IN THE LINE BELOW
ParentClass.objects.filter(..).update(....)
return self
class InheritedClass(MyAbstractClass):
# Field
def my_view(request):
obj = InheritedClass.objects.get(id=1)
obj.save()
return obj
So basically, the question is, is there any way in the abstract_method to tell Django to address the calling class (that is, InheritedClass)?
Technical answer : Well, quite simply yes :
def abstract_method(self):
type(self).objects.filter(..).update(....)
return self
Note that this is Python methods are called with the "calling" object (the object on which the method is invoked) as first parameter, and all attributes lookups will happens on this object and it's class - else inheritance just wouldn't work at all. The only django-specific part here is that Django prevents you from using a ModelManager on a model instance so you need to explicitely get the object's class, which is returned by type(self).
BUT :
Coding style considerations
Django recommands that model methods acting on the whole table should belong to the ModelManager (by contrast with methods acting on the current row only which are to be implemented as plain methods), so since your method obviously acts on the whole table it might be better as a ModelManager method.
I say "might" because there's a grey area, where updating one row implies updating some other rows too - a typical example is when you have a flag that should always only be set for one single record so you also want to unset it on all other records. There's (of course) not enough context in your question to tell which is the right choice here.
you can just do self.objects.filter(...).update(..)
An abstract class just implements methods that are inherited by its concrete class, here InheritedClass. Therefore, everything for methods and fields are available in the inheriting class.
However, for this instance, I would suggest you look at making a custom model manager. Methods in a model are meant to work with that specific row's fields, whereas managers are intended to work table-wide as described at model methods
Define custom methods on a model to add custom “row-level” functionality to your objects. Whereas Manager methods are intended to do “table-wide” things, model methods should act on a particular model instance.
If you have a method doing filtering in a model method, that is a code smell and it belongs in a custom Manager.

Django, Custom Managers affect save method?

I'm using Django 1.7. I've got a default custom manager that filters on an "active" boolean field. According to the docs, it needs to be the default manager to work with related fields (ie. accessing User.story_set only shows active Story objects). I'm keeping the standard manager for admin and shell access, but I am unable to save changes to objects, I'm speculating because save() methods pass through the default manager at some point.
class Story(models.Model):
active = models.BooleanField(default=True)
....
objects = ActiveStoryManager()
full_set = models.Manager()
class ActiveStoryManager(models.Manager):
def get_query_set(self):
return super(ActiveStoryManager, self).get_query_set().filter(active=True)
use_for_related_fields = True
This works well for all public-facing use. However, in admin and shell I am unable to affect inactive objects, including turning them back active.
story = Story.full_set.get(id=#) will fetch a story with active=False, but after setting active=True I am unable to save, getting a
django.db.utils.IntegrityError: duplicate key value violates unique constraint "stories_story_pkey"
DETAIL: Key (id)=(#) already exists.
Calling save.(force_update=True) returns django.db.utils.DatabaseError: Forced update did not affect any rows.
So while save() is a model method, it seems to depend on the default manager at some point in the saving process.
A workaround is using the Queryset API, e.g. Story.full_set.filter(id=#).update(active=True), but that's only usable in the shell, and requires manually typing each change, still can't save inactive instances in the admin.
Any help on this?
It cannot be done! As inancsevinc pointed out, save() calls on the default manager. The Django docs mention that get_query_set should not be modified on default managers, and I have sadly found out why. Hopefully in the future relatedManagers can be specified/controlled, but for now this method will not work for me. Confirmed in Django IRC chat.
Instead, I'm throwing together a ordinary Manager method, as well as model methods for some models, to get equivalent functionality. Also requires changing all the related_set calls in the template to include the new methods, so it's a pain, but no other way.
To make admin page work with a different manager, you can implement get_queryset method on your ModelAdmin class.
class StoryAdmin(ModelAdmin):
def get_queryset(self, request):
return self.model.full_set.get_queryset()

Purpose of using a custom manager to create objects with django?

I see in the Django documentation :
Model Instance reference : Creating objects
You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved.
Rather than overriding __init__, try using one of these approaches:
Add a classmethod on the model class.
Add a method on a custom manager (usually preferred)
Why is the second solution "usually preferred" ?
In a situation where I have a model B which extends a model A through a OneToOne relation, and I want to create a method generating a B object which generates the corresponding A object as well, how is it "better" to use a custom manager as suggested, given I'll probably not use this manager for anything other than what is provided by default manager ?
I think it is preferred because it looks cleaner in code. You might also be reading into the emphasizes a bit too much, as the benefit or difference isn't that big. That said, when implementing things myself I do use the proposed approach.
Consider the following model (purely for illustrative purposes):
class Vehicle(models.Model):
wheels = models.IntegerField()
color = models.CharField(max_length=100)
In your application, the need often arises to get all cars, or all motorcycles, or whatever type of vehicle. To keep things DRY, you want some standard form of retrieving this data. By using class methods, you'd get the following:
class Vehicle(models.Model):
#(...)
#classmethod
def cars(cls):
return Vehicle.objects.filter(wheels=4)
cars = Vehicle.cars()
green_cars = Vehicle.cars().filter(color='green')
If you create a manager, you'll get something like this:
class CarManager(models.Manager):
def get_query_set(self):
return super(CarManager, self).get_query_set().filter(wheels=4)
class Vehicle(models.Model):
#(...)
car_objects = CarManager()
cars = Vehicle.car_objects.all()
green_cars = Vehicle.car_objects.filter(color='green')
In my opinion, the latter looks cleaner, especially when things get more complex. It keeps the clutter out of your model definitions, and keeps things similar to using the default objects manager.

Django Model Manager for Default Options

I have a Django model which has a foreign key that is optional. I set it up this way so that table would contain default options of different service_types but one could override this option by specifying a controller foreign key.
Now in my views I have a bunch of code that looks like this:
try:
modeService = RegressionServices.objects.get(controller=controller, service_type=SERVICE_TYPE_CONTROLLER_MODE)
except RegressionServices.DoesNotExist:
modeService = RegressionServices.objects.get(service_type=SERVICE_TYPE_CONTROLLER_MODE)
I would like to reduce this down to one call and I think that a Django model Manager should be the way to do so. Essentially it would check for the controller in **kwargs and if present it would basically do the code above. I am looking in the docs and only finding that the get_query_set method is usually being overridden. Is it okay to override the get() method? Will I even have access to the RegressionServices model in a model Manager get() method?
Can anyone think of a way to do this other than a model manager?
Just do a logical OR, using Q objects.