1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from django.db import models
class NewsQuerySet(models.query.QuerySet):
def live(self):
return self.filter(state='published')
def interesting(self):
return self.filter(interesting=True)
class NewsManager(models.Manager):
def get_query_set(self):
model = models.get_model('news', 'NewsItem')
return NewsQuerySet(model)
def __getattr__(self, attr, *args):
try:
return getattr(self.__class__, attr, *args)
except AttributeError:
return getattr(self.get_query_set(), attr, *args)
|
More like this
- Easier chainability with custom QuerySets by bendavis78 1 year, 2 months ago
- FieldLevelPermissionsAdmin by buriy 5 years, 8 months ago
- assertQuerysetEqual by coleifer 3 years ago
- CustomQueryManager by zvoase 4 years, 10 months ago
- Model Choices Helper by pmclanahan 3 years, 3 months ago
Comments
Thanks, looks excellent!
I think you can even avoid repeating the Manager code for each of your classes by using something like:
and then setting the
objectsattribute like this:#
Thanks, ep! I like your improvement. Will do it that way in my own code from now on.
#
I tried using this. In ep's approach Manager's init is overriden and it expects an additional argument compared to Django core's Manager. However, in Django code Manager's are called without arguments. So when using object.delete() and object.someothermodel_set.* methods the system tries to call the Manager without arguments and it throws an error. I don't know however, why Django is calling Manager via the Manager model and not thourgh models Manager instance (so it doesn't help if you make argument optional as class can't find the queryset then).. I found ep's approach much too hazard although you could hack it here and there..
#
herion, just use a default for the qs_class:
#
Thanks for this snippet, it makes for really clean extensions to the Query API.
ep, don't you need to be calling super's
__init__in your improvement?#
Excellent. Althougt leovitch is right. you need to call the super init. The code will look like this:
I recommend this piece since is reusable and complies better with DRY
#
There's something horribly wrong if you try and inherit of the CustomManager though...
I get errors like: site-packages/django/db/models/options.py", line 489, in pk_index return self.fields.index(self.pk)
ValueError: list.index(x): x not in list
#
I find this works fine though, hopefully I won't burn in hell for the __class__ trick!
#
My solution:
Doesn't use the kwarg hack and it's still very self contained.
#
pkoch, your solution seems the best for me since it allows use the chained manager even with reverse relations like:
mymodel.myothermodel_set.mycustomfilter
Thanks :)
#
here is a full gist with an example https://gist.github.com/2587518
#
The solutions listed here didn't work for me when using a custom manager on an abstract base model. This is what I'm using instead:
Usage is exactly like the others:
This has the added bonus that it only proxies the methods you add in your custom QuerySet class (in the example only the 'upcoming' method). So (for instance) MyModel.objects.delete() fails as it's supposed to.
#