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 afte
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.
You can override your class-based view's get_success_url
function. Like this:
def get_success_url(self):
return reverse("NonProfit", kwargs={"slug": self.object.slug})
Solved the problem after reading the first sentence of 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)
the point is the save article.save()
's result back to self.object
When you use reverse
, use the name of the url pattern you wish to reverse.
You wish 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})
Try to remove the @permalink
decorator from your get_absolute_url
method. It cannot work together with reverse
.
Also, the Django documentation states the following:
The
permalink
decorator is no longer recommended. You should usereverse()
in the body of yourget_absolute_url
method instead.