跳转到主要内容

支持接受对象列表的ModelChoiceField实现,而不仅仅是查询集

项目描述

该应用程序提供ModelFormModelChoiceFieldModelMultipleChoiceField实现,可以接受对象列表,而不仅仅是查询集。这可以防止这些字段在创建时每次都击中数据库。

问题

想象以下表单

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,它使用 CachedModelChoiceFieldCachedModelMultipleChoiceField。用法如下

# 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 更新版本的问题,但如果有任何问题,别忘了运行测试。

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪一个,请了解更多关于 安装包 的信息。

源代码分发

django-cached-modelforms-0.2.3.tar.gz (8.0 kB 查看哈希值)

上传时间 源代码

构建分发

django_cached_modelforms-0.2.3-py3-none-any.whl (8.8 kB 查看哈希值)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面