【问题标题】:How to set initial value in a dynamic Django ModelChoiceField?如何在动态 Django ModelChoiceField 中设置初始值?
【发布时间】:2015-10-22 15:51:25
【问题描述】:

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

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

研究:

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

示例代码:

models.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

forms.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

views.py

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.core.urlresolvers import reverse

from .models import Page, write_page
from .forms import PageForm, PageVersionForm
from ..helpers import get_pages


def update_page(request, slug):
    if not request.user.has_perm("can_edit_page"):
        return HttpResponseForbidden()

    page = get_object_or_404(Page, slug=slug)

    if request.method == "POST":
        form = PageForm(request.POST)

        if form.is_valid():
            content = form.cleaned_data["content"]
            user = request.user

            write_page(name=page.name, submitter=user, content=content)

            kwargs = {}
            kwargs["slug"] = slug

            return HttpResponseRedirect(reverse("pages:detail", kwargs=kwargs))

    else:
        data = {}
        data["content"] = page.content

        form = PageForm(data)
        context = {}

        page_version_form = PageVersionForm(page=page)

        context["form"] = form
        context["page_version_form"] = page_version_form
        context["page"] = page
        context["user"] = request.user
        context.update(get_pages())

        return render(request, "pages/page_update.html", context)

【问题讨论】:

    标签: python django forms python-2.7


    【解决方案1】:

    您需要重置 choices 属性,因为它会在设置查询集后缓存在字段中,并且即使您更新 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上修复的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-01
      • 2010-11-23
      • 1970-01-01
      • 2011-08-11
      • 2018-08-21
      • 2016-04-12
      • 1970-01-01
      • 2018-05-01
      相关资源
      最近更新 更多