Custom model manager for auth_user - django

I want to include two extra managers on the auth user model, active and inactive, to give me just active, or just inactive users. This is how the model would look (even if the it is invalid):
from django.contrib.auth.models import User
class ActiveManager(models.Manager):
def get_query_set(self):
return super(ActiveManager, self).get_query_set().filter(active=True)
class InactiveManager(models.Manager):
def get_query_set(self):
return super(InactiveManager, self).get_query_set().filter(active=False)
class User(models.Model):
# user model...
all_users = models.Manager()
objects = ActiveManager()
inactive = InactiveManager()
Where / how exactly would I place this so I can do a query such as User.inactive.all() ? Thank you.

You're going to need to use the contribute_to_class method on your Manager. Instead of the User class you have there, you will need something like this:
InactiveManager.contribute_to_class(User, 'inactive')
I suspect it doesn't matter exactly where you do this as long as it happens nice and early (before you use it!) - a models.py somewhere would feel vaguely right.

Related

In Django, can I create an extra custom manager for a reverse ManyToMany relationship?

I want to create an extra manager for fetching a filtered version of a reverse ManyToMany relationship. I have these models:
class Photo(models.Model):
# ...
is_public = models.BooleanField()
albums = models.ManyToManyField('Album')
class Album(models.Model):
# ...
I can get all the photos in an album with album.photo_set.all(). I'd like to provide a way to get only the public photos in an album by doing album.photo_set.public() (which would, somewhere, do a .filter(is_public=True)).
I guess I'm wanting to provide an extra Related manager, but I'm not sure that's possible. I don't want, or need, to replace the default related manager (which sounds like a bad idea anyway). I don't need a custom through model for the relationship, unless that's the only way to achieve this.
Sure, you could make a related manager but that seems a bit overkill for this.
Why not just simply add a function to your model that returns only the public photos in the album?
def get_public(self):
return self.photo_set.filter(is_public = True)
You can create manager like this:
class PublicManager(models.Manager):
use_for_related_fields = True
def public(self, *args, **kwargs):
kwargs.update({
'is_public': True
})
return self.get_queryset().filter(*args, **kwargs)

Subclassing AbstractUser in Django for two types of users

I'm developing a school database system in Django 1.5, and was planning on having a number of different user types (Student, Staff, Parent) which subclass AbstractUser (actually, another abstract subclass of AbstractUser). I was just attempting to add an externally developed app to my system, which uses User in a ForeignKey for some of its models, however, this fails as my user type is not a 'User' instance. I can't set the apps models to use AbstractUser as one can't use abstract classes for Foreign Keys. I was then considering adding to my settings.py AUTH_USER_MODEL = 'myapp.MyUser' and using settings.AUTH_USER_MODEL in place of User for the ForeignKey in the app. However, I have 3 different user types, so can't do this either.
An earlier prototype used Django 1.4, which did not support custom User models, hence had a reference to a User instead, but this required an extra join for every query, which was leading to quite complex queries. Is this the only way I can go forward with this, or is there another solution?
I have successfully used the following solution:
1. Create SchoolUser class in models.py - this will be your AUTH_USER_MODEL class
TYPES = (('Student', 'Student'), ('Staff', 'Staff'), ('Parent', 'Parent'), )
class SchoolUser(AbstractUser):
type = models.CharField(max_length=10, choices=TYPES, default='Student')
2. Create users.py file and put whole users logic there. Have one abstract class that all others inherit from and which will implement the factory method:
class UserManager(object):
def __init__(self, user):
self.user = user
#classmethod
def factory(cls, user):
"""
Dynamically creates user object
"""
if cls.__name__.startswith(user.type): # Children class naming convention is important
return cls(user)
for sub_cls in cls.__subclasses__():
result = sub_cls.factory(user)
if result is not None:
return result
Sample children classes (also go to users.py file):
class StudentUser(UserManager):
def do_something(self):
pass
class StaffUser(UserManager):
def do_something(self):
pass
class ParentUser(UserManager):
def do_something(self):
pass
Views is where the magic happens ;)
def my_view(request):
school_user = UserManager.factory(request.user)
if school_user.do_something: # each class can have different behaviour
This way you don't need to know, which type of user it is, just implement your logic.
I hope this is clear enough, if not let me know!

CRUD users in django , outside of django Admin

In my current project, I'd like to CRUD users OUTSIDE of django's Admin interface.
Let's explain my question as following:
1- I'm using the UserProfile for storing additional attributes for users (their schools, birthday, etc.)
2- The problem is that by deleting a user, I can delete the profile rather than actual User.
Please take at the code for Listing and Deleting Users:
def user_list(request):
''' Shows all of Students '''
return object_list(request,
queryset = UserProfile.objects.all() ,
template_name = 'user_list.html' ,
template_object_name = 'student'
)
def user_delete(request , id):
''' Deletes a student based on his/her ID '''
return delete_object(request,
model = UserProfile ,
object_id = id ,
template_name = 'delete_student.html' ,
post_delete_redirect = reverse("user_list")
)
It looks normal that I'm deleting UserProfile rather than User. But I intended it to be a proxy to actual User. Do I miss something here ?
3- Generally speaking, should I reference each models to User or UserProfile ? For example assume that I have a model for Course. Which of these is the correct way?
class Course(models.Model):
#stuff
student = models.ForeignKey(Urer)
# OR ??
student = models.ForeignKey(UserProfile)
It looks normal that I'm deleting UserProfile rather than User. But I intended it to a proxy to actual User
Why not delete the User directly? By default, Django will CASCADE DELETE to get rid of the UserProfile as well.
Generally speaking, should I reference each models to User or UserProfile
I think this is more a question of personal preference, but I usually tie to User directly as it saves a step when getting to the object you want (you don't need to do user.get_profile().student and can call user.student instead). It also makes more sense to me anyway: the student is a property of the user, not the user's profile.

Adding to the "constructor" of a django model

I want to do an extra initalization whenever instances of a specific django model are created. I know that overriding __init__ can lead to trouble. What other alternatives should I consider?
Update. Additional details: The intent is to initialize a state-machine that the instances of that model represent. This state-machine is provided by an imported library, and it's inner state is persisted by my django-model. The idea is that whenever the model is loaded, the state machine would be automatically initialized with the model's data.
Overriding __init__ might work, but it's bad idea and it's not the Django way.
The proper way of doing it in Django is using signals.
The ones that are of interest to you in this case are pre_init and post_init.
django.db.models.signals.pre_init
Whenever you instantiate a Django
model, this signal is sent at the beginning of the model’s __init__()
method.
django.db.models.signals.post_init
Like pre_init, but this one is sent
when the __init__(): method finishes
So your code should be something like
from django.db import models
from django.db.models.signals import post_init
class MyModel(models.Model):
# normal model definition...
def extraInitForMyModel(**kwargs):
instance = kwargs.get('instance')
do_whatever_you_need_with(instance)
post_init.connect(extraInitForMyModel, MyModel)
You can as well connect signals to Django's predefined models.
While I agree that there often is a better approach than overriding the __init__ for what you want to do, it is possible and there might be cases where it could be useful.
Here is an example on how to correctly override the __init__ method of a model without interfering with Django's internal logic:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# add your own logic
The two suggested methods in the docs rely on the instance being created in an arbitrary way:
Add a classmethod on the model class:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
#classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
Add a method on a custom manager:
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create_book("Pride and Prejudice")
If that is your case, I would go that way. If not, I would stick to #vartec's answer.

Loose coupling of apps & model inheritance

I have a design question concerning Django. I am not quite sure how to apply the principle of loose coupling of apps to this specific problem:
I have an order-app that manages orders (in an online shop). Within this order-app I have two classes:
class Order(models.Model):
# some fields
def order_payment_complete(self):
# do something when payment complete, ie. ship products
pass
class Payment(models.Model):
order = models.ForeignKey(Order)
# some more fields
def save(self):
# determine if payment has been updated to status 'PAID'
if is_paid:
self.order.order_payment_complete()
super(Payment, self).save()
Now the actual problem: I have a more specialized app that kind of extends this order. So it adds some more fields to it, etc. Example:
class SpecializedOrder(Order):
# some more fields
def order_payment_complete(self):
# here we do some specific stuff
pass
Now of course the intended behaviour would be as follows: I create a SpecializedOrder, the payment for this order is placed and the order_payment_complete() method of the SpecializedOrder is called. However, since Payment is linked to Order, not SpecializedOrder, the order_payment_complete() method of the base Order is called.
I don't really know the best way to implement such a design. Maybe I am completely off - but I wanted to build this order-app so that I can use it for multiple purposes and wanted to keep it as generic as possible.
It would be great if someone could help me out here!
Thanks,
Nino
I think what you're looking for is the GenericForeignKey from the ContentTypes framework, which is shipped with Django in the contrib package. It handles recording the type and id of the subclass instance, and provides a seamless way to access the subclasses as a foreign key property on the model.
In your case, it would look something like this:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Payment(models.Model):
order_content_type = models.ForeignKey(ContentType)
order_object_id = models.PositiveIntegerField()
order = generic.GenericForeignKey('order_content_type', 'order_object_id')
You don't need to do anything special in order to use this foreign key... the generics handle setting and saving the order_content_type and order_object_id fields transparently:
s = SpecializedOrder()
p = Payment()
p.order = s
p.save()
Now, when your Payment save method runs:
if is_paid:
self.order.order_payment_complete() # self.order will be SpecializedOrder
The thing you want is called dynamic polymorphism and Django is really bad at it. (I can feel your pain)
The simplest solution I've seen so far is something like this:
1) Create a base class for all your models that need this kind of feature. Something like this: (code blatantly stolen from here)
class RelatedBase(models.Model):
childclassname = models.CharField(max_length=20, editable=False)
def save(self, *args, **kwargs):
if not self.childclassname:
self.childclassname = self.__class__.__name__.lower()
super(RelatedBase, self).save(*args, **kwargs)
#property
def rel_obj(self):
return getattr(self, self.childclassname)
class Meta:
abstract = True
2) Inherit your order from this class.
3) Whenever you need an Order object, use its rel_obj attribute, which will return you the underlying object.
This solution is far from being elegant, but I've yet to find a better one...