Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Class Based Views, get_absolute_url not working

Tags:

python

django

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.
like image 477
Klanestro Avatar asked Dec 05 '22 11:12

Klanestro


1 Answers

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.

like image 60
Austin Phillips Avatar answered Jan 31 '23 06:01

Austin Phillips