支持接受对象列表的ModelChoiceField实现,而不仅仅是查询集
项目描述
该应用程序提供ModelForm、ModelChoiceField、ModelMultipleChoiceField实现,可以接受对象列表,而不仅仅是查询集。这可以防止这些字段在创建时每次都击中数据库。
问题
想象以下表单
class MyForm(forms.Form): obj = ModelChoiceField(queryset=MyModel.objects.all())
每次渲染表单时,ModelChoiceField字段都会击中数据库。如果您不希望这样,能否直接将对象列表(从缓存)传递给该字段?您不能这样做。那怎么办?使用CachedModelChoiceField。
解决方案
带有CachedModelChoiceField的表单
from cached_modelforms import CachedModelChoiceField class MyForm(forms.Form): obj = CachedModelChoiceField(objects=lambda:[obj1, obj2, obj3])
此字段将像常规ModelChoiceField一样操作,但是您需要传递一个可调用的函数来返回对象列表,而不是查询集。可调用是因为我们不想只评估列表一次。
可调用的函数可以返回
一个对象列表:[obj1, obj2, obj3, ...]。obj应该具有pk属性,并且可以强制转换为Unicode。
一个元组列表:[(pk1, obj1), (pk2, obj2), (pk3, obj3), ...]。
一个字典:{pk1: obj1, pk2: obj2, pk3: obj3, ...}。请注意,dict 是未排序的,所以项将按 pk 的字典顺序排序。
对于 CachedModelMultipleChoiceField 也是如此。
警告
这里没有特殊的验证。字段不会检查对象是否是特定模型的实例,甚至不会检查对象是否是模型实例。保持缓存相关是您的责任。通常这不会成为问题。
Modelform
那么关于 modelforms 呢?它们仍然使用原始的 ModelChoiceField 用于 ForeignKey 字段。该应用有其自己的 ModelForm,它使用 CachedModelChoiceField 和 CachedModelMultipleChoiceField。用法如下
# 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 }
这就结束了。如果您为某些字段未指定 objects,则将使用常规的 Model[Multiple]ChoiceField。
m2m_initials
如果您在 ModelForm 中使用 ManyToManyField 并将其加载到实例中,它将进行一个额外的数据库请求(JOINed!)- 获取该字段的初始值。我们也能缓存它吗?是的。您需要一个接受模型实例并返回一个包含 pk 的列表的函数 - 该字段的初始值。下面是前面示例的修改
# 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()]}
兼容性
当然,它与 Django 1.2-1.4 兼容良好。修改 ModelForm 需要从 Django 源代码中复制一些内容。这无法通过继承来完成。我不认为会有与 Django 更新版本的问题,但如果有任何问题,别忘了运行测试。
项目详情
哈希值 for django_cached_modelforms-0.2.3-py3-none-any.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | b46d15e91b592c0fd29638f5420a39242acaffb964d7ed4d6a6d0debaf4fb695 |
|
MD5 | 3ec6fd2c316d21c7118debcd0726d53d |
|
BLAKE2b-256 | f7c7a99093dfa8e3d87ae829014059c97554b80461cbcde0b7d10a953601f0af |