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
permalinkdecorator is no longer recommended. You should usereverse()in the body of yourget_absolute_urlmethod instead.