Django Class Based Views, get_absolute_url not working

I bought and read the book Two Scoops Django: Best Practices for Django 1.5, and it has an example of class-based views. After this implementation, I get an error after submitting the form.

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

After researching, I came up with this Django issue - Class Based Generic View - "No URL to redirect to"

I want get_absolute_url to work in my program

these are my 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 

these are my models.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' ) 

this is my stack, django bindings are highlighted, and

 /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. 
+4
source share
4 answers

This exception is thrown because self.object = None when trying to redirect after valid editing. Since the value of self.object is the result of calling form.save() , the most likely cause of this error is that you redefined the save() method in NonProfitCreateForm , but forgot to return the saved object.

The form.save() method is form.save() return an object that was saved and should not be None .

Your NonProfitCreateForm can be modified as shown below:

 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. 

The first two lines of your save() method will create a model instance from the entered form data. But since commit=False , the object will not be stored in the database. If self.request not present in the form instance, the returned object will not have the primary database key, and get_absolute_url will still fail.

So, you want to make sure that the request parameter is always passed to your form when creating the instance. This does not happen by default, so you need to arrange your view code in order to instantiate the form using the request parameter.

Looking through the FormMixin code , you can see that there is a get_form_kwargs function that defines the arguments to pass to any instantiated form. You need to pass request=self.request , so in your view, override get_form_kwargs to add the required parameter, something like this:

 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 

It might be better to create a subclass of CreateView with the modified get_form_kwargs function and pull your NonProfitCreateView out of the subclass.

+8
source

When you use reverse , use the url template name you want to change.

You want to redirect to this URL:

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

Therefore, your get_absolute_url method should be:

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

Try removing the @permalink decorator from your get_absolute_url method. It cannot work together with reverse .

In addition, the following is stated in the Django documentation :

The permalink decorator is no longer recommended. You must use reverse() in the body of your get_absolute_url method.

+1
source

You can override a function of the form get_success_url based on the class. Like this:

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

All Articles