Custom model manager chaining (Python 3 re-write)
This is a Python 3 re-write for https://djangosnippets.org/snippets/2117/
- manager
- queryset
- factory
This is a Python 3 re-write for https://djangosnippets.org/snippets/2117/
I want to create Mixins for QuerySet objects that will by default filter out certain records (e.g. filter out "deleted" records, or filter out "unapproved" records, etc). I'd like those to be separate independent mixins. So in each of those, I override all() to filter out deleted or unapproved, etc. But, I also want to offer a method in the queryset to remove those filters or remove some part of those filters. That's where this code comes in. After some examination of how QuerySets work, this seemed like the simplest method for "undoing" some filter in a queryset
Although configuring filtering in TastyPie is possible, it is limited to per-field filters, which are not enough for more complex filtering. If your model implement custom manager methods for complex filters, exposing these methods as TastyPie Resource list endpoints is not an easy task. The ModelResource subclass provided here does this, providing 3 ways of complex filtering: * define querysets for filters directly in the Resource declaration * use Model manager custom method * use QuerySet custom method
Intro ----- I found a question on SO for which Justin Lilly's answer was correct but not as thorough as I'd like, so I ended up working on a simple snippet that shows how to bind signals at runtime, which is nifty when you want to bind signals to an abstract class. Bonus: simple cache invalidation! Question -------- [How do I use Django signals with an abstract model?](http://stackoverflow.com/questions/2692551/how-do-i-use-django-signals-with-an-abstract-model) I have an abstract model that keeps an on-disk cache. When I delete the model, I need it to delete the cache. I want this to happen for every derived model as well. If I connect the signal specifying the abstract model, this does not propagate to the derived models: pre_delete.connect(clear_cache, sender=MyAbstractModel, weak=False) If I try to connect the signal in an init, where I can get the derived class name, it works, but I'm afraid it will attempt to clear the cache as many times as I've initialized a derived model, not just once. Where should I connect the signal? Answer ------ I've created a custom manager that binds a post_save signal to every child of a class, be it abstract or not. This is a one-off, poorly tested code, so beware! It works so far, though. In this example, we allow an abstract model to define CachedModelManager as a manager, which then extends basic caching functionality to the model and its children. It allows you to define a list of volatile keys that should be deleted upon every save (hence the post_save signal) and adds a couple of helper functions to generate cache keys, as well as retrieving, setting and deleting keys. This of course assumes you have a cache backend setup and working properly.
Django allows you to specify your own ModelManager with custom methods. However, these methods are chainable. That is, if you have a method on your PersonManager caled men(), you can't do this: Person.objects.filter(birth_date__year=1978).men() Normally, this isn't a problem, however your app may be written to take advantage of the chainability of querysets. For example, you may have an API method which may return a filtered queryset. You would want to call with_counts() on an already filtered queryset. In order to overcome this, we want to override django's QuerySet class, and then make the Manager use this custom class. The only downside is that your functions will not be implemented on the manager itself, so you'd have to call `Person.objects.all().men()` instead of `Person.objects.men()`. To get around this you must also implement the methods on the Manager, which in turn call the custom QuerySet method.
Because select_related() only works on ForeignKeys that are not null or blank, when you are customizing the admin, even if you set "list_select_related=True" you can still end up with way too many querys in the Admin changelist. By adding this code to your model you can decrease the queries dramatically. I found I needed this when I was working with Django apps with a lot of legacy data and I couldn't set the ForeignKey null=False.
Manager Mixin to implement get_random() in your models. You can override get_objects to tune the queriset To use, define your class: class MyManager(models.Manager, RandomObjectManager): DEFAULT_NUMBER = 5 # I can change that def get_objects(self): return self.filter(active=True) # Only active models plz class MyModel(models.Model): active = models.BooleanField() objects = MyManager() Now you can do: MyModel.objects.get_random()
This is a small manager that just adds a "bulk_insert" function. This is very basic, I'm basically throwing it up here because it's simple and works for my current needs. Feedback on improvements (which I know would be a ton) are very welcome. Some known "gotchas": 1. This doesn't handle relationships. If, however, you want to do one-to-one or foreignkeys you'll have to use the actual table column name ('whatever_id' typically) 2. When using this I typically make a bulk_insert call every 500 iterations or so Some improvements that I think could be good: 1. Possibly just find the fields from the first object in the objs array and leave the fields argument as optional 2. Create a bulk_insert_from_file function and use LOAD DATA INFILE for mysql and whatever else supports it
A zero-boilerplate generalisation of http://djangosnippets.org/snippets/2114/
Using Python mixins, you can chain methods on your queryset.
A drop-in chainable manager for providing models with basic search features such as +/- modifiers, quoted exact phrases and ordering by relevance.
The popular [django-tagging](http://code.google.com/p/django-tagging/) app has, in its implementation and semantics, a highly usable and transparent elegance -- but then you have to call methods on a Tag instances' items collection. These classes let you inline the tag name in the chain of queryset filter methods instead. TO USE: ### models.py ... from tagging.fields import TagField from tagging.models import Tag as Tag class YourModel(models.Model): ... yourtags = TagField() objects = TaggedManager() ... ### and then elsewhere, something like-- ... ym = YourModel.objects.order_by("-modifydate")[0] anotherym = YourModel.objects.get(id=7) ## distinct from ym ym.yourtags = "tag1 tag2" anotherym.yourtags = "tag1 othertag" ym.save() anotherym.save() with_tag1 = YourModel.objects.tagged('tag1') with_tag2 = YourModel.objects.tagged('tag2').order_by('-modifydate') print ym in with_tag1 ## True print anotherym in with_tag1 ## True print ym in with_tag2 ## False ... since these are QuerySets, you can easily create unions (e.g. `with_tag1 | with_tag2` and othersuch) as you need and filter them to your hearts' content, without having to instantiate Tag all the time (which you can of course do as well).
This is an improvement on [snippet 1079](http://www.djangosnippets.org/snippets/1079/). Please read its description and [this blog post](http://zerokspot.com/weblog/2008/08/13/genericforeignkeys-with-less-queries/) for any information. This is a manager for handling generic foreign key. Generic foreign objects of the same type are fetched together in order to reduce the number of SQL queries. To use, just assign an instance of GFKManager as the objects attribute of a model that has generic foreign keys. Then: `MyModelWithGFKs.objects.filter(...).fetch_generic_relations()` The generic related items will be bulk-fetched to minimize the number of queries. **Improvement:** Problem I had with previous version from snippet 1079 : if two or more items shares the same generic foreign object, then only the first one is cached. Next ones generates new unwanted SQL queries. I solved this problem by putting all the needed foreign objects in a temporary data_map dictionary. Then, the objects are distributed to every items, so that if two items shares the same foreign object, it will only be fetched once.
A Django model manager capable of using different database connections. Inspired by: * [Eric Florenzano](http://www.eflorenzano.com/blog/post/easy-multi-database-support-django/) * [Kenneth Falck](http://kfalck.net/2009/07/01/multiple-databases-and-sharding-with-django) There's a more detailed version in Portuguese in my blog: [Manager para diferentes conexões de banco no Django](http://ricobl.wordpress.com/2009/08/06/manager-para-diferentes-conexoes-de-banco-no-django/)
If you have a model with foreign key to User, you can use this manager to show (i.e. in admin interface) only objects, that are related to currently logged-in user. Superuser sees all objects, not only his. Requires: [ThreadlocalsMiddleware](http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser)
33 snippets posted so far.