【问题标题】:Django Class Based Views, get_absolute_url not working基于 Django 类的视图,get_absolute_url 不起作用
【发布时间】:2013-04-06 22:44:31
【问题描述】:

我购买并正在阅读这本书 Django 的两个勺子:Django 1.5 的最佳实践,其中有一个基于类的视图示例。在此实施之后,我在提交表单后收到错误。

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

这是我的 models.py 和视图文件

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.

【问题讨论】:

  • 请出示您的NonProfitCreateForm
  • 为什么不在 manage.py shell 中实例化模型并在其上调用 get_absolute_url .. 从那里您可以使用堆栈跟踪进行调试。
  • 你的模型上有一个重复的参数 slug

标签: python django


【解决方案1】:

看完Austin Phillips的第一句话就解决了问题:

    def form_valid(self, form):
        article = form.save(commit=False)
        article.author = self.request.user
        self.object = article.save()
        return super().form_valid(form)

重点是将article.save()的结果保存回self.object

【讨论】:

    【解决方案2】:

    产生此异常是因为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
    

    使用修改后的get_form_kwargs 函数创建CreateView 的子类可能会更好,并让您的NonProfitCreateView 从子类派生。

    【讨论】:

    • 我认为你解决了这个问题,不幸的是我对此只有一个模糊的理解。我添加了我的 forms.py,你能告诉我如何修复它吗?
    【解决方案3】:

    您可以覆盖基于类的视图的get_success_url 函数。像这样:

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

    【讨论】:

    • 您不需要为CreateView(或任何其他继承ModelFormMixin的视图)执行此操作,因为ModelFormMixin.get_success_url方法将尝试调用实例的get_absolute_url来获取成功网址。
    • 虽然您关于 url reverse 的观点是正确的,但它与此错误无关。问题是找不到get_absolute_url。您的解决方案是找不到反向匹配错误。
    【解决方案4】:

    当您使用 reverse 时,请使用您希望反转的 url 模式的名称。

    您希望重定向到此网址:

    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})  
    

    【讨论】:

    • 为了他人的利益,get_absolute_url 属于原始模型对我来说并不明显,如 docs.djangoproject.com/en/1.9/ref/class-based-views/… 顶部所述,UpdateView/CreateView 是基于该模型的(在重要说明 '此页面上的一些示例假定作者模型已在 myapp/models.py 中定义如下')
    【解决方案5】:

    尝试从您的 get_absolute_url 方法中删除 @permalink 装饰器。不能和reverse一起使用。

    另外,Django documentation 声明如下:

    不再推荐使用 permalink 装饰器。您应该在 get_absolute_url 方法的主体中使用 reverse()

    【讨论】:

      猜你喜欢
      • 2020-12-25
      • 2019-09-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2020-10-11
      • 2021-07-12
      相关资源
      最近更新 更多