Django Class Based Views, get_absolute_url not working
django, python
Solution
This exception is produced because `self.object = None` when attempting to redirect after a valid edit. Since the value of `self.object` is the result of a `form.save()` call, the most likely reason for this error is that you have overridden the `save()` method in `NonProfitCreateForm`, but forgotten to return the saved object.
The `Form.save()` method is expected to return the object that was saved and should not be `None`.
Your `NonProfitCreateForm` could 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 because `commit=False`, the object will not be saved to the database. If `self.request` is not present on your form instance, a the returned object will not have a database primary key, and `get_absolute_url` will still fail.
So, you want to ensure that a `request` parameter is always passed to your form when instantiated. This doesn't happen by default, so you need to arrange your view code to instantiate your form with a `request` parameter.
Looking through the code for `FormMixin` you can see that there is a `get_form_kwargs` function which determines 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 would probably be a better idea to create a subclass of `CreateView` with the modified `get_form_kwargs` function, and have your `NonProfitCreateView` derive from the subclass.
Problem
I bought and am Reading the Book Two Scoops of Django:Best Practices for Django 1.5 and in it has a example of Class based views. After this implementation I get the 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 ``` Doing research I came along this problem Django - Class Based Generic View - "No URL to redirect to" I want the get_absolute_url to work in my program this is 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 ``` this is 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 stacktrace, the django braces is 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. ```