如何在动态Django ModelChoiceField中设置初始值?

时间:2015-07-31 04:38:01

标签: python django forms python-2.7

我正在尝试为网站创建一个简单的页面版本控制系统。我希望能够将页面传递给表单,该表单指向与页面相关的所有版本,并使表单下拉列表包含该页面的所有版本,并使初始页面版本成为理想版本在视图中初始化。到目前为止,表单将填充页面的所有版本,但不会选择理想版本作为初始项目。

如果在视图中初始化表单时填充字段,如何设置表单中字段的初始项?

研究

我在以下问题中尝试了答案,但没有一个人有解决方案:

示例代码:

models.py

timezone

forms.py

from django.db import models

from autoslug import AutoSlugField

from django_enumfield import enum

from ..users.models import User


def write_page(name, submitter, content=''):
    page = Page.objects.get_or_create(name=name)[0]
    page_version = PageVersion.create(page, submitter, content)

    return page_version


class Status(enum.Enum):
    DISABLED = 0
    ACTIVE = 1


class Page(models.Model):
    name = models.CharField(max_length=100)
    slug = AutoSlugField(populate_from='name', unique=True)
    status = enum.EnumField(Status, default=Status.ACTIVE)
    current_version = models.IntegerField(default=0)

    def __unicode__(self):
        name_str = "(name='{}', slug='{}')"
        return name_str.format(self.name, self.slug)

    @property
    def versions(self):
        status = ("status = {}".format(Status.ACTIVE),)
        order_by = ("-version",)

        return self.pageversion_set.extra(where=status, order_by=order_by)

    @property
    def all_versions(self):
        order_by = ("-version",)

        return self.pageversion_set.extra(order_by=order_by)

    @property
    def ideal(self):
        try:
            return PageVersion.objects.get(id=self.current_version)
        except self.DoesNotExist:
            return None

    @property
    def version(self):
        if self.ideal:
            return self.ideal.version

        return 0

    @property
    def content(self):
        if self.ideal:
            return self.ideal.content

        return ''

    @property
    def submitter(self):
        if self.ideal:
            return self.ideal.submitter

        return None

    @classmethod
    def create(cls, name):
        page_object = cls.objects.create(name=name)

        return page_object


class PageVersion(models.Model):
    parent = models.ForeignKey(Page)
    version = models.IntegerField(default=0)
    content = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    status = enum.EnumField(Status, default=Status.ACTIVE)
    submitter = models.ForeignKey(User)

    def __unicode__(self):
        name_str = "(name='{}', slug='{}', version={})"
        return name_str.format(self.name, self.slug, self.version)

    @property
    def name(self):
        return self.parent.name

    @property
    def slug(self):
        return self.parent.slug

    @classmethod
    def create(cls, page, submitter, content='', make_current=True):
        if page.all_versions:
            current_max_version = max([i.version for i in page.all_versions])
        else:
            current_max_version = 0

        page_version_object = cls(parent=page, submitter=submitter, content=content)
        page_version_object.version = current_max_version + 1
        page_version_object.save()

        if make_current:
            page.current_version = page_version_object.id
            page.save()

        return page_version_object

views.py

from django import forms

from .models import PageVersion


class PageVersionForm(forms.Form):
    version = forms.ModelChoiceField(queryset=None)

    def __init__(self, *args, **kwargs):
        page = kwargs.pop("page")
        super(PageVersionForm, self).__init__(*args, **kwargs)
        self.fields["version"].queryset = page.versions

1 个答案:

答案 0 :(得分:1)

您需要重置choices属性,因为一旦设置了queryset,它就会缓存在字段上,即使您更新queryset属性,也不会重新验证。

def __init__(self, *args, **kwargs):
    ...
    self.fields['version'].queryset = page.versions
    self.fields['version'].widget.choices = self.fields['version'].choices

你能检查一下Django版本中的ModelChoiceField是否有一个名为_set_queryset的setter方法吗?它似乎是在github中修复的。