Purpose of using a custom manager to create objects with django? - 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.

Related

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: conditional ModelAdmin depending on object

Let's say I have a base class with, for example:
class Base(models.Model):
name = models.CharField(max_length=50, blank=False, null=False)
value1 = models.CharField(max_length=50)
value2 = models.CharField(max_length=50)
Now, I'm inputting several types of objects into the table, some of which use parts of the data, some of which use other parts, all of them using some common part (name in this example).
I want a complete listing, but I want to have different views when I click into an object, depending on it's type. Changes in the modelAdmin include: one of the classes uses inlines, others don't, list_display varies, one has extra CSS, etc, etc. Basically we're talking about different modelAdmins.
Alternatives I'm thinking: one is that each of those types subclasses Base, i.e.:
class Type1(Base):
pass
class Type2(Base):
pass
and then I define a modelAdmin for each of them, and one for the Base class just to get the table listing everything. In this one I would override the links so they don't go to /app/base/id, but instead to /app/type1/id, /app/type2/id, etc depending on the type. For each of these, I modify the modelAdmins so after saving they go back to /app/type
A different alternative would be having a single model and a single modelAdmin, and overriding every single method I'm using for change_view to consider what type of object it's rendering, i.e., get_inline_instances, get_formsets, whatever I need to modify list_display, list_display_links, list_filter, etc.
The first alternative looks way cleaner to me, although I'm not sure how to modify the link other than defining a method in the modelAdmin with the correct call to reverse and adding that method as a column in list_display.
Is there an easier way I'm missing?. How would you do it?.
Oh, and it HAS to use the admin. I'd rather do this using views, or separate models, but sadly this is the way it has to be. The High Command wants everything in one single table.
Thanks!.
Edit: also, I just found this and it looks good:
http://django-polymorphic.readthedocs.org/en/latest/admin.html
Django-Polymorphic definitely seems the way to go. It's easy to use and automatically gives me the correct modelAdmin when I click through a base object, something I couldn't replicate with Proxies.
Only problem is a table is created for each child class, even if the child class doesn't have any additional fields, and an extra query is performed per child class even though nothing is recovered from it (only column in the table is a foreign key to the base object).
But it works. I can live with that.

Django - Polymorphic Models or one big Model?

I'm currently working on a model in Django involving one model that can have a variety of different traits depending on what kind of object it is. So, let's say we have a model called Mammal, which can either be an Elephant or a Dolphin (with their own traits "tusk_length" and "flipper_length" respectively).
Basic OOP principles shout "polymorphism", and I'm inclined to agree. But, as I'm new to Django, I first want to know whether or not it is the best way to do so in Django. I've heard of plenty of examples of and some people giving their preferences toward singular giant models
I've already tried using GenericForeignKeys as described here: How can I restrict Django's GenericForeignKey to a list of models?. While this solution works beautifully, I don't like the inability to filter, and that the relationship is only one way. That is, while you can get a Dolphin from a Mammal object, you can't get the Mammal object from the Dolphin.
And so, here are my two choices:
Choice A:
from django.db import models
class Mammal(models.Model):
hair_length = models.IntegerField()
tusk_length = models.IntegerField()
flipper_length = models.IntegerField()
animal_type = models.CharField(max_length = 15, choices = ["Elephant", "Dolphin"]
Choice B:
from django.db import models
class Mammal(models.Model):
hair_length = models.IntegerField()
class Elephant(Mammal):
tusk_length = models.IntegerField()
class Dolphin(Mammal):
flipper_length = models.IntegerField()
Choice B, from what I understand, has the advantage of nicer code when querying and listing all Elephants or Dolphins. However, I've noticed it's not as straightforward to get all of the Elephants from a list of Mammals (is there a query for this?) without putting animal_type in the class, with default being dependent on the class.
This leads to another problem I see with polymorphism, which won't come up in this example above or my application, but is worth mentioning is that it would be difficult to edit a Dolphin object into an Elephant without deleting the Dolphin entirely.
Overall, is there any general preference, or any big reason I shouldn't use polymorphism?
My recommendation, in general with database design, is to avoid inheritance. It complicates both the access and updates.
In Django, try using an abstract class for your base model. That means a db table will not be created for it. Its fields/columns will be auto-created in its child models. The benefit is: code reuse in Django/Python code and a simple, flat design in the database. The penalty is: it's more work to manage/query a mixed collection of child models.
See an example here: Django Patterns: Model Inheritance
Alternatively, you could change the concept of "Mammal" to "MammalTraits." And include a MammalTraits object inside each specific mammal class. In code, that is composition (has-a). In the db, that will be expressed as a foreign key.
We ended up going with a large table with a lot of usually-empty columns. Our reasoning was that (in this case) our Mammal table was all we'd be querying over, and there was no (intuitive) way to filter out by certain types of Mammals besides manually checking whether they had a "dolphin" or "elephant" object, which then threw an error if they didn't. Even looking for the type of an object returned from a query that was definitely an Elephant still returned "Mammal". It would be hard to extend any Pythonic workarounds to writing pure SQL, which one of our data guys does regularly.

Django: using ContentType vs multi_table_inheritance

I was having a similar problem as in
How to query abstract-class-based objects in Django?
The thread suggests using multi_table_inheritance. I personally think using content_type more conceptually comfortable (just feels more close to logic, at least to me)
Using the example in the previous link, I would just add a StelarType as
class StellarType(models.Model):
"""
Use ContentType so we have a single access to all types
"""
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
Then add this to the abstract base model
class StellarObject(BaseModel):
title = models.CharField(max_length=255)
description = models.TextField()
slug = models.SlugField(blank=True, null=True)
stellartype = generic.GenericForeignKey(StellarType)
class Meta:
abstract = True
To sync between StellarObject and StellarType, we can connect post_save signal to create a StellarType instance every time a Planet or Star is created. In this way, I can query StellarObjects through StellarType.
So I'd like to know what's the PRO and CON of using this approach against using multi_table_inheritance? I think both create an additional table in the databse. But how about database performance? how about usability/flexibility? Thanks for any of your input!
To me, ContentType is the way to go when you want to relate an object to one of many models that aren't fundamentally of the same "type". Like if you want to be able to key Comments to Users, Pages, and Pictures on a social network, but there's no reasonable supertype shared by those three models. Sure you could create a "Commentable" supertype, but to me that feels more like a mixin than a fundamental type from which those three things derive. Before ContentType came out, you would have had no choice but to invent supertypes for these kind of relations, which can get really ugly really quickly if you need to do it multiple times in the same application (lets say you also have Events, Alerts, Messages, etc., each of which can apply to a different set of models).
Multi-table inheritance makes the most sense when you want to attach attributes to the base model, such that they will be shared in all concrete models that extend from it, so that you can get polymorphic behavior. Commentable doesn't really fit this mold, because all of that behavior can be put on the Comment model, less so on the Commentable objects. But if you have different classes of Users that share much of the same behavior and should be aggregable, then it makes a lot more sense.
The major pro of multi-table inheritance to me is a cleaner data model, with implicit relationships and inheritance that can be taken advantage of on the Python side (polymorphism is still a bit messy though, as seen here and here). The major pro of ContentType is that it is more general and keeps auxiliary functionality out of your models, at the cost of a bit of a slightly less pristine schema (lots of "meta" fields on your models to define these relationships). And for your example, you still have to rely on post_save, which seems unnecessarily messy/magical to me, as well.
Sorry for reviving old thread. I think it all boils down to the lookup direction. Whether you look up all subclasses for a certain FK (multitable inheritance) or define the referenced class as a content type and look it up based on the table reference and id (contenttypes) makes no big difference in performance - hint: they both suck. I think content types is a nice choice if you want your app to be easily extendible, i.e. others can add new content types to reference against. Multitable is good if you only sometimes need the extra columns defined in extra tables. Sometimes it might also be a good idea to merge all your subtypes and make only one which has a few fields left empty most of the time.

Django: many-to-one fields and data integrity

Let's say that I have a Person who runs an inventory system. Each Person has some Cars, and each Car has a very large number of Parts (thousands, let's say).
A Person, Bob, uses a Django form to create a Car. Now, Bob goes to create some Parts. It is only at the form level that Django knows that the Parts belong to some specific Car, and that the Parts.ForeignKey(Car) field should only have a specific Car as a choice. When creating a Part, you have to mess with the form's constructor or similar in order to limit the choice of Cars to only the cars owned by Bob.
It does not seem at all proper or secure to enforce this ownership at the form level. First, it seems that other users' Cars must be inaccessible to anyone but the owner of the Car; currently, only solid form programming prevents anyone from viewing any other Person's Cars! Second, it is seems sloppy to take care of the problem by modifying constructors in this manner. What do you all think about this, and is there any way to enforce this?
first of all part of this should happen at a level where you know who is the current user.
In Django theres nothing like a global request.user, so you need to check for this where you have a request object or pass it as a paremeter.
One way of achieving what you ask for is to use a custom manager. For the Car class you could use
class CarManager(models.Manager):
def for_user(self, user):
return super(CarManager, self).get_query_set().filter(creator=user)
You might also want to override the default manager and it's default methods to only allow this method.
For the second part, you don't need to modify the constructor there are other ways if you don't like it. But modifying them assures you for example you can't create a form without a logged user. Another way is to use a ModelChoiceField and override it's queryset attr in the view:
form.car.queryset = Car.objects.for_user(request.user)
but this approach is error prone. You should sitck to modifying the form constructor as this:
class PartForm(forms.ModelForm):
def __init__(self,user,*args,**kwargs):
super (PartForm,self ).__init__(*args,**kwargs)
self.fields['car'].queryset = Car.objects.for_user(user)
Hope this helps.