Reputation: 321
I have User table in my DB, they can be active or inactive. If I only want to query on active user, I define a Proxy Model like following.
class User(models.Model):
name = models.CharField(max_length=50)
location = models.CharField(max_length=50)
active = models.BooleanField()
class UserActive(models.Manager):
def get_queryset(self):
return super(UserActive, self).get_queryset().filter(active=True)
class ActiveUser(User):
objects = UserActive()
class Meta:
proxy = True
Then by working with ActiveUser, I can do my calculation/statistic with only active user.
The problem is, I need to define both UserActive and ActiveUser class, it seems awkward to me. Because with each main class (in this case is User), we need to define two other classes. Imaging we have several other model need to implement Proxy, the code would look messy. May I know if we can have more elegant way ?
Thanks Alex
Upvotes: 2
Views: 66
Reputation: 476659
I would really avoid overwriting the .objects
manager, and use this as some sort of implicit filtering. The Zen of Python is explicit is better than implicit, by using ActiveUser
, you basically implement a filtering manager, but propose it like the entire set.
Perhaps a more elegant solution is to define multiple managers. So we can construct a filtering manager decorator:
def filter_manager(**kwargs):
def decorator(klass):
def get_queryset(self):
return super(klass, self).get_queryset().filter(**kwargs)
klass.get_queryset = get_queryset
return klass
return decorator
This decorator will however throw away a get_queryset
that is defined on the manager itself, so you can not perform an extra patch with this.
Now we can define some managers in a rather elegant way:
@filter_manager(active=True)
class ActiveManager(models.Manager):
pass
@filter_manager(active=False)
class InactiveManager(models.Manager):
pass
Finally we can add these managers to the User
model, and use explicit names:
class User(models.Model):
name = models.CharField(max_length=50)
location = models.CharField(max_length=50)
active = models.BooleanField()
objects = models.Manager()
active_users = ActiveManager()
inactive_users = InactiveManager()
So now we can use User.active_users
to query for the active users. We thus have no proxy models, and can query with User.active_users.count()
for example (well we can perform all operations like with .objects
but then for .active_users
.
Upvotes: 2
Reputation: 321
I created a new Django project, with only User model. My models.py look like this
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
def filter_manager(**kwargs):
def decorator(klass):
def get_queryset(self):
return super(klass, self).get_queryset().filter(**kwargs)
klass.get_queryset = get_queryset
return klass
return decorator
@filter_manager(active=True)
class ActiveManager(models.Manager):
pass
@filter_manager(active=False)
class InactiveManager(models.Manager):
pass
class User(models.Model):
name = models.CharField(max_length=50)
location = models.CharField(max_length=50)
active = models.BooleanField()
active_user = ActiveManager()
When I tried User.objects.all().
Error: type object 'User' has no attribute 'objects'
Upvotes: 0