Django Cached Modelforms
The application provides ModelForm, ModelChoiceField, ModelMultipleChoiceField implementations that can accept lists of objects, not just querysets. This can prevent these fields from hitting DB every time they are created.
The problem
Imagine the following form:
class MyForm(forms.Form):
obj = ModelChoiceField(queryset=MyModel.objects.all())
Every time you render the form ModelChoiceField field will hit DB. What if you don’t want it? Can’t you just pass the list of objects (from cache) to the field? You can’t. What to do? Use CachedModelChoiceField.
The solution
Form with CachedModelChoiceField:
from cached_modelforms import CachedModelChoiceField class MyForm(forms.Form): obj = CachedModelChoiceField(objects=lambda:[obj1, obj2, obj3])
This field will act like regular ModelChoiceField, but you pass a callable that returns the list of objects, not queryset, to it. Calable is needed because we don’t want to evaluate the list out only once.
A callable can return:
a list of objects: [obj1, obj2, obj3, ...]. obj should have pk property and be coercible to unicode.
a list of tuples: [(pk1, obj1), (pk2, obj2), (pk3, obj3), ...].
a dict: {pk1: obj1, pk2: obj2, pk3: obj3, ...}. Note that dict is unsorted so the items will be ordered by pk lexicographically.
Same is for CachedModelMultipleChoiceField.
Warnings
There is no special validation here. The field won’t check that the object is an instance of a particular model, it won’t even check that object is a model instance. And it’s up to you to keep cache relevant. Usually it’s not a problem.
Modelform
But what about modelforms? They still use original ModelChoiceField for ForeignKey fields. This app has its own ModelForm that uses CachedModelChoiceField and CachedModelMultipleChoiceField. The usage is following:
# models.py
class Category(models.Model):
title = CharField(max_length=64)
class Tag(models.Model):
title = CharField(max_length=64)
class Product(models.Model):
title = CharField(max_length=64)
category = models.ForeignKey(Category)
tags = models.ManyToManyField(Tag)
# forms.py
class ProductForm(cached_modelforms.ModelForm):
class Meta:
model = Product
objects = {
'category': lambda:[...], # your callable here
'tags': lambda:[...], # and here
}
That’s all. If you don’t specify objects for some field, regular Model[Multiple]ChoiceField will be used.
m2m_initials
If you use ManyToManyField in ModelForm and load an instance to it, it will make one extra DB request (JOINed!) – to get initials for this field. Can we cache it too? Yes. You need a function that accepts model instance and returns a list of pk’s – initials for the field. Here’s a modification of previous example:
# models.py
class Product(models.Model):
title = CharField(max_length=64)
category = models.ForeignKey(Category)
tags = models.ManyToManyField(Tag)
def tags_cached(self):
cache_key = 'tags_for_%(product_pk)d' % {'product_pk': self.pk}
cached = cache.get(cache_key)
if cached is not None:
return cached
result = list(self.tags.all())
cache.set(cache_key, result)
return result
# forms.py
class ProductForm(cached_modelforms.ModelForm):
class Meta:
model = Product
objects = {
'category': lambda:[...], # your callable here
'tags': lambda:[...], # and here
}
m2m_initials = {'tags': lambda instance: [x.pk for x in instance.tags_cached()]}
Compatibility
For sure is works fine with Django 1.2-1.4. Altering ModelForm has required some copy-pasting from Django source code. It couldn’t be done with inheritance. I don’t think there will be problems with futher versions of Django, but don’t forget to run the tests if something seems wrong.
Metadata
Release files for django-cached-modelforms 0.2.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| django-cached-modelforms-0.2.3.tar.gz | 8.0 kB | Without provenance | Details for django-cached-modelforms-0.2.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| django_cached_modelforms-0.2.3-py3-none-any.whl | Python 3 | none | any | Details for django_cached_modelforms-0.2.3-py3-none-any.whl |
Total release size: 16.8 kB
Release files / django-cached-modelforms-0.2.3.tar.gz
| Download URL | django-cached-modelforms-0.2.3.tar.gz |
|---|---|
| Size | 8.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c742227dc4fafd9fd2a75a946dfdfe38a3348504f62791fe96db52bb24e271d3
|
|
BLAKE2b-256 checksum How to use checksums |
88b7f434cff4b7439316f1ec7ddb64d1c44da1a6e7db5e84033faede5c4aafcc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Python-urllib/3.7
|
Release files / django_cached_modelforms-0.2.3-py3-none-any.whl
| Download URL | django_cached_modelforms-0.2.3-py3-none-any.whl |
|---|---|
| Size | 8.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b46d15e91b592c0fd29638f5420a39242acaffb964d7ed4d6a6d0debaf4fb695
|
|
BLAKE2b-256 checksum How to use checksums |
f7c7a99093dfa8e3d87ae829014059c97554b80461cbcde0b7d10a953601f0af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Python-urllib/3.7
|
Security for django-cached-modelforms 0.2.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.