无法更新对象并初始化表单

时间:2015-06-27 07:11:07

标签: django django-models django-forms django-views

我有一个项目模型如下:

class Project(models.Model):
    name = models.CharField(max_length=255, null=False)
    launch_date = models.CharField(max_length=20, null=False)
    possession_date = models.CharField(max_length=20, null=False)

每个项目都有权限表中的一组权限:

class Permissions(models.Model):
    name = models.CharField(max_length=255)

现在权限表中可能有多个权限。对于权限表中的每个权限,都有相应的值,例如grant / applied等。所以有一个项目权限表如下:

class ProjectPermission(models.Model):
    project = models.ForeignKey('Project')
    permission = models.ForeignKey('Permissions')
    value = models.CharField(max_length=255)

所以我做了以下表格:

class PermissionForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(PermissionForm, self).__init__(*args, **kwargs)

        permissions = Permissions.objects.all()
        for permission in permissions:
            self.fields[permission.name] = forms.CharField(
                widget=forms.Select(choices=(
                    ('Approved', 'Approved'),
                    ('In Process', 'In Process'),
                    ('Not Applied', 'Not Applied'),
                    ('Denied', 'Denied'),
                )))

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.disable_csrf = True
        self.helper.form_id = 'permission-form'

    def save(self, *args, **kwargs):
        project = kwargs.pop('project')
        for field in self.fields:
            permission = Permissions.objects.filter(name=field).first()
            p = ProjectPermission(
                project=project,
                permission=permission,
                value=self.cleaned_data[field]
            )
            p.save()
        return project

但问题是一个数据被保存,我无法使用正确的数据重新呈现表单,也无法更新数据。如果我更改字段的值并保存表单,它会在ProjectPermission表中创建一个新条目。

这是因为我在初始化表单时没有指定实例吗?如果是这样,我该如何指定实例?

1 个答案:

答案 0 :(得分:0)

Django有ModelForms to save you repeating your model code in forms。我假设您使用了您发布的代码中的crispy forms。我将带您了解一个简单的ModelForms示例。

首先,我想创建一个自己的基本表单类来分解一些常见的布局,如下所示:

# core Django imports
from django.forms import ModelForm

# third-party imports
from crispy_forms.helper import FormHelper


class MyForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.form_class = 'form-horizontal'

现在假设我们有一个这样的模型,我们想要创建/更新/等等:

class Event(models.Model):
    """
    Represents an individual event.

    """
    name = models.CharField(max_length=50)
    topic = models.ForeignKey(Topic)
    date = models.DateField(help_text='dd/mm/yyyy')
    start_time = models.TimeField(help_text='HH:MM - 24hr clock')
    finish_time = models.TimeField(help_text='HH:MM - 24hr clock')
    location = models.CharField(max_length=50)
    attendees_need_to_sign_up = models.BooleanField(
        default=False,
        help_text="Tick the box if you're giving an open invite to attend",
    )
    organiser = models.ForeignKey(
        Person,
        related_name = "organiser",
    )
    ...

您现在可以拥有这样的ModelForm:

class EventForm(MyForm):
    def __init__(self, *args, **kwargs):
        super(EventForm, self).__init__(*args, **kwargs)
        self.helper.form_id = 'event-form'
        self.helper.layout = Layout(
            Field(
                'topic',
                template='events/related_topic.html',
            ),
            Field('name', css_class='input-xlarge'),
            Field('agenda', css_class='input-xlarge'),
            Field('date', css_class='input-xlarge'),
            Field('start_time', css_class='input-xlarge'),
            Field('finish_time', css_class='input-xlarge'),
            Field('location', css_class = 'input-xlarge'),
            Field('attendees_need_to_sign_up', css_class = 'input-xlarge'),
            FormActions(
                Submit(
                    'save_changes',
                    'Save changes',
                    css_class = "btn-primary",
                ),
                Button(
                    'cancel',
                    'Cancel',
                    onclick = 'history.go(-1);'
                ),
            ),
        )
        self.fields['name'].label = 'Event name'

    def clean(self):
        # custom validation goes here
        ...

    class Meta:
        model = Event
        fields = (
            'topic',
            'name',
            'agenda',
            'date',
            'start_time',
            'finish_time',
            'location',
            'attendees_need_to_sign_up',
        )

现在你只需要你的观点和模板。观点很简单:

# core django imports
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect
from django.views.generic import (
    CreateView,
    DetailView,
    ListView,
    UpdateView,
)

# third party imports
from braces.views import LoginRequiredMixin
...

class EventCreateView(LoginRequiredMixin, CreateView):
    model = Event
    form_class = EventForm
    login_url = "/login/"

    def get_context_data(self, **kwargs):
        context = super(EventCreateView, self).get_context_data(**kwargs)
        context['topics'] = Topic.objects.all()
        return context


class EventUpdateView(LoginRequiredMixin, UpdateView):
    model = Event
    form_class = EventUpdateForm
    login_url = "/login/"

LoginRequiredMixin来自Django braces

您的模板现在非常简单,因为您已经在Python代码中定义了所有表单。您需要在{% extends %}声明之后放置以下内容来包含crispy表单模板标记:

{% load crispy_forms_tags %}

然后放置:

{% crispy form %}

您想要表格的任何地方。