2013-04-14 30 views
4

我买了,我正在读本书Django的两个勺子:Django 1.5的最佳实践,它有一个基于类的视图的例子。这个实现后,我提交表单后出现错误。Django基于类的视图,get_absolute_url不起作用

ImproperlyConfigured at /NonProfitCreate/ 
No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model 

做研究,我沿着这个问题Django - Class Based Generic View - "No URL to redirect to"

来到我希望get_absolute_url在我的程序

工作,这是我的forms.py

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# 
# npp/forms.py 

from django import forms 

from .models import NonProfit 

class NonProfitCreateForm(forms.ModelForm): 
    class Meta: 
     model = NonProfit 
     fields = ("name","contact_name","email","phone","address","image","tags",) 

    def __init__(self, *args, **kwargs): 
     self.request = kwargs.pop('request', None) 
     return super(NonProfitCreateForm, self).__init__(*args, **kwargs) 

    def save(self, *args, **kwargs): 
     kwargs['commit']=False 
     obj = super(NonProfitCreateForm, self).save(*args, **kwargs) 
     if self.request: 
      obj.user = self.request.user 
      obj.save() 

class NonProfitUpdateForm(NonProfitCreateForm): 
    class Meta: 
     model = NonProfit 

这是我的模型。 py and views files

from django.db import models 
from django.contrib.auth.models import User 
from django.db.models import permalink 
from django_extensions.db.fields import AutoSlugField 
from django.contrib import admin 

from django.core.urlresolvers import reverse 

import tagging 
from tagging.models import Tag 
# Create your models here. 
''' this is for the Non-Profit Proccess ''' 

class NonProfit (models.Model): 
    User = models.ForeignKey(User) 
    name = models.CharField(max_length=100) 
    contact_name = models.CharField(max_length=100) 
    email = models.EmailField(max_length=75) 
    phone = models.CharField(max_length=20) 
    address = models.TextField(max_length=3000) 
    image = models.ImageField(upload_to='photos/%Y/%m/%d',blank=True) 


    slug = models.SlugField(max_length=128) 
    slug = AutoSlugField(('slug'), max_length=128, unique=True, populate_from=('name',)) 
    tags = tagging.fields.TagField() 

    def get_absolute_url(self): 
     return reverse("npp/nonprofit_detail", kwargs={"slug": self.slug}) 

    def __unicode__(self): 
     return self.name 

    def get_tags(self): 
     return Tag.objects.get_for_object(self) 




    # Create your views here. 
    # Auction/npp/views.py 

from Auction.views import ActionMixin 

from django.contrib import messages 
from django.views.generic import CreateView, UpdateView, DetailView 

from braces.views import LoginRequiredMixin 

from forms import NonProfitCreateForm,NonProfitUpdateForm 


from models import NonProfit 

class NonProfitCreateView(LoginRequiredMixin,ActionMixin,CreateView): 
    model = NonProfit 
    action = "created" 
    form_class = NonProfitCreateForm 

class NonProfitUpdateView(LoginRequiredMixin,ActionMixin,UpdateView): 
    model = NonProfit 
    action = "updated" 
    form_class = NonProfitUpdateForm 


class NonProfitDetailView(DetailView): 
    model = NonProfit 


# Auction/views.py 
class ActionMixin(object): 
    @property 
    def action(self): 
     msg = "{0} is missing action.".format(self.__class__) 
     raise NotImplementedError(msg) 

    def form_valid(self, form): 
     msg = "{0}!".format(self.action) 
     messages.info(self.request, msg) 
     return super(ActionMixin, self).form_valid(form) 

urls.py

url(
    regex=r'^NonProfitCreate/', 
    view=NonProfitCreateView.as_view(), 
    name='NonProfitCreate', 
), 
url(
    regex=r'^NonProfit/(?P<slug>[-\w\d]+)/', 
    view=NonProfitDetailView.as_view(), 
    name='NonProfit' 
    ) 

这是我的堆栈跟踪,Django的括号突出显示,并

/home/talisman/projects/Auction/Auction/views.py in form_valid 
     return super(ActionMixin, self).form_valid(form) 

EEnvironment: 


Request Method: POST 
Request URL: http://127.0.0.1:8000/NonProfitCreate/ 

Django Version: 1.5.1 
Python Version: 2.7.4 
Installed Applications: 
('django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.sites', 
'django.contrib.messages', 
'django.contrib.staticfiles', 
'django.contrib.admin', 
'django.contrib.admindocs', 
'django.contrib.comments', 
'django.contrib.sitemaps', 
'zinnia', 
'tagging', 
'mptt', 
'south', 
'misc', 
'adm', 
'registration', 
'npp', 
'blogs') 
Installed Middleware: 
('django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
'django.middleware.clickjacking.XFrameOptionsMiddleware') 


Traceback: 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/core/handlers/base.py" in get_response 
    115.       response = callback(request, *callback_args, **callback_kwargs) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/base.py" in view 
    68.    return self.dispatch(request, *args, **kwargs) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/django_braces-1.0.0-py2.7.egg/braces/views.py" in dispatch 
    98.    **kwargs) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/base.py" in dispatch 
    86.   return handler(request, *args, **kwargs) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/edit.py" in post 
    199.   return super(BaseCreateView, self).post(request, *args, **kwargs) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/edit.py" in post 
    165.    return self.form_valid(form) 
File "/home/talisman/projects/auction/Auction/views.py" in form_valid 
    54.  return super(ActionMixin, self).form_valid(form) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/edit.py" in form_valid 
    128.   return super(ModelFormMixin, self).form_valid(form) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/edit.py" in form_valid 
    65.   return HttpResponseRedirect(self.get_success_url()) 
File "/home/talisman/virt_env/Auction/local/lib/python2.7/site-packages/Django-1.5.1-py2.7.egg/django/views/generic/edit.py" in get_success_url 
    119.      "No URL to redirect to. Either provide a url or define" 

Exception Type: ImproperlyConfigured at /NonProfitCreate/ 
Exception Value: No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model. 
+0

请显示您的NonProfitCreateForm。 – Alasdair

+0

为什么你不在manage.py shell中实例化模型并在其上调用get_absolute_url ..从那里你可以使用堆栈跟踪进行调试。 – zallarak

+0

你的模型有一个重复的参数slu 012 –

回答

8

尝试后有效编辑重定向此异常时,因为self.object = None生产。由于self.object的值是form.save()调用的结果,导致此错误的最可能原因是您已覆盖NonProfitCreateForm中的save()方法,但忘记返回保存的对象。

Form.save()方法预计将返回保存的对象,不应该是None

,如下图所示你NonProfitCreateForm可以修改:

class NonProfitCreateForm(forms.ModelForm): 
    ... 
    def save(self, *args, **kwargs): 
     kwargs['commit']=False 
     obj = super(NonProfitCreateForm, self).save(*args, **kwargs) 
     if self.request: 
      obj.user = self.request.user 
      obj.save() 
     return obj #<--- Return saved object to caller. 

save()方法将输入的表单数据创建一个模型实例的前两行。但由于commit=False,对象将而不是保存到数据库。如果您的表单实例上不存在self.request,则返回的对象将没有数据库主键,并且get_absolute_url仍然会失败。

所以,你要确保一个request参数总是在实例化时传递给你的表单。这种情况在默认情况下不会发生,因此您需要安排您的视图代码以request参数实例化您的表单。

通过code for FormMixin可以看到有一个get_form_kwargs函数,它决定了传递给任何实例化形式的参数。你需要传递request=self.request,所以在您看来覆盖get_form_kwargs添加所需的参数,这样的事情:

class NonProfitCreateView(LoginRequiredMixin,ActionMixin,CreateView): 
    model = NonProfit 
    action = "created" 
    form_class = NonProfitCreateForm 

    def get_form_kwargs(self): 
     # Ensure the current `request` is provided to NonProfitCreateForm. 
     kwargs = super(NonProfitCreateView, self).get_form_kwargs() 
     kwargs.update({ 'request': self.request }) 
     return kwargs 

这可能会是一个更好的主意来创建的CreateView与改性get_form_kwargs功能的子类,并有你的NonProfitCreateView派生自子类。

+0

我认为你已经明白了这个问题,不幸的是,我只对这个问题有了更深入的了解。我添加了我的forms.py你能告诉我如何解决它。 – Klanestro

+0

@Klanestro答案更新。 –

1

尝试从get_absolute_url方法去除@permalink装饰。它不能与reverse一起使用。

此外,Django documentation规定如下:

permalink装饰不再建议。相反,您应该在get_absolute_url方法的主体中使用reverse()

+0

谢谢,但没有效果我仍然得到相同的错误 – Klanestro

3

当您使用reverse时,请使用您想要反转的网址格式的名称。

您希望重定向到该网址:

url(
    regex=r'^NonProfit/(?P<slug>[-\w\d]+)/', 
    view=NonProfitDetailView.as_view(), 
    name='NonProfit' 
    ) 

因此您get_absolute_url方法应该是:

def get_absolute_url(self): 
    return reverse("NonProfit", kwargs={"slug": self.slug}) 
+1

我得到了同样的错误 – Klanestro

+0

为了别人的利益,我不明白'get_absolute_url'属于原模型,UpdateView/CreateView的基础是在https://docs.djangoproject.com/en/1.9/ref/class-based-views/generic-editing/的顶部所描述的(在关键注释'部分本页上的示例假定作者模型已经在myapp/models.py'中定义如下) – sage

1

您可以覆盖你的基于类的视图的get_success_url功能。就像这样:

def get_success_url(self): 
    return reverse("NonProfit", kwargs={"slug": self.object.slug}) 
+0

您应该不需要为“CreateView”(或任何其他继承了“ModelFormMixin”的视图)执行此操作,因为['ModelFormMixin.get_success_url'](https://github.com/django/django/blob/1.5/django/views/generic/edit.py#L108)方法将尝试调用实例的'get_absolute_url'来获取成功的网址。 – Alasdair

+0

尽管您对url反转的观点很有道理,但与此错误无关。问题是找不到'get_absolute_url'。您的解决方案是找不到反向匹配找到的错误。 – Peyman