关于save()方法的Django Form主键 - 获取NoneType回溯

时间:2013-09-14 03:12:41

标签: django django-forms

我正在使用q& a at Get Primary Key after Saving a ModelForm in Django

这正是我需要做的事情。

我有以下型号:

class meetingEvent(models.Model):
    '''
    A meeting event
    '''

    name = models.CharField(max_length=64, help_text="a name for this meeting")
    account_number = models.ForeignKey(account)
    meeting_type = models.ForeignKey(meetingType)
    meeting_group = models.ForeignKey(meetingGroup)
    start_time = models.DateTimeField(help_text="start time for this event")
    end_time = models.DateTimeField(help_text="end time for this event")
    created_time = models.DateTimeField(auto_now_add=True)
    listed_products = models.ForeignKey(product)
    additonal_notes = models.TextField(help_text="additional notes for this meeting")

    def __unicode__(self):
        return self.name

我有以下表格:

class meetingEventForm(forms.ModelForm):
    """
    to create a new meeting event.
    """
    portal_user = forms.CharField(help_text="username to access portal data")
    portal_pass = forms.CharField(widget=forms.PasswordInput, help_text="password to add access portal data")

    def save(self, commit=True):

        super(meetingEventForm, self).save(commit=commit)

    class Meta:
        model = meetingEvent

我有以下观点:

def meeting_event(request):

    if request.method == 'POST':
        form = meetingEventForm(request.POST)
        if form.is_valid():
            new_agenda=form.save()

            return HttpResponseRedirect(reverse('agenda_detail', args=(new_agenda.pk,)))

    else:
        form = meetingEventForm()
        return render_to_response('agendas/event.html',{'form':form,}, context_instance=RequestContext(request))

我已经确认这会让它干净利落地进入数据库。 但是,我收到以下错误:

Traceback:
File "/usr/lib/python2.6/site-packages/Django-1.5.2-py2.6.egg/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/python2.6/site-packages/Django-1.5.2-py2.6.egg/django/contrib/auth/decorators.py" in _wrapped_view
  25.                 return view_func(request, *args, **kwargs)
File "/var/www/html/tamtools/agendas/views.py" in meeting_event
  44.             return HttpResponseRedirect(reverse('agenda_detail', args=(new_agenda.pk,)))

Exception Type: AttributeError at /agendas/add/
Exception Value: 'NoneType' object has no attribute 'pk'

我不知道Django 1.5中有什么变化吗? new_agenda应该是一个meetingEventForm类型,不应该吗?

2 个答案:

答案 0 :(得分:2)

您在模型中覆盖了save方法,但忘记返回模型。

return super( ....

答案 1 :(得分:1)

您不需要覆盖ModeForm保存方法,因为您没有对它执行任何特殊操作。您的ModelForm应如下所示:

class MeetingEventForm(forms.ModelForm):
    """
    to create a new meeting event.
    """
    class Meta:
        model = meetingEvent

我还更改了类名以符合Python style guide

表单中还有两个与模型无关的额外字段。可能有两个原因 - 一个是您需要将这些字段保存在另一个模型中,或者第二个选项是您希望有人在添加新事件之前自行授权。

由于第二个似乎更合理,因此从您的视图中限制对表单的访问:

from django.contrib.auth.decorators import login_required
from django.shorcuts import render, redirect

@login_required()
def meeting_event(request):
    form = MeetingEventForm(request.POST or {})
    context = {'form': form}

    if request.method == 'POST':
        if form.is_valid():
            new_agenda = form.save()
            return redirect('agenda_detail', args=(new_agenda.pk,))
        else:
            return render(request, 'agendas/event.html', context)
    else:
        return render(request, 'agendas/event.html', context)

由于这是一项常见任务,并且您使用的是django 1.5,为什么不使用通用class based views

您的代码将会减少,您不必担心平凡的细节:

首先,在views.py中,创建一个继承自通用CreateView的类,用于显示模型的模型表单,让用户填写它,并保存详细信息:

from django.views.generic.edit import CreateView

class CreateMeetingRequest(CreateView):
    template_name = 'agendas/event.html'
    model = meetingRequest

现在,要将视图映射到网址,我们将其添加到urls.py。由于我们还希望用户在添加会议请求之前登录 - login_required装饰器会为我们处理。它将检查用户是否已登录 - 如果没有,则将用户重定向到登录表单,一旦他们登录,将其重定向回表单:

from django.contrib.auth.decorators import login_required

from .views import CreateMeetingRequest

urlpatterns = patterns('',
    # your other views
    url(r'meeting-request/add/$',
        login_required(CreateMeetingRequest.as_view()), name='add-meeting-req'),
)

最后,我们需要在表单成功后告诉视图去哪里。 CreateView会检查模型是否有get_absolute_url方法,然后调用它。所以在models.py

from django.core.urlresolvers import reverse

class meetingRequest(models.Model):

    # your normal fields

    def get_absolute_url(self):
       return reverse('agenda_detail', args=(self.pk,))