What I'm trying to do is Django boilerplate for functional views. Any help here is very much appreciated, as the docs show examples for the template view and list view, but I've found very little for the model-based generic views. Am I missing an example in the docs?
I have a model that represents an entry in a calendar. There's a foreign key to another object (not a user) that owns the entry. What I want to do is simply to create the entry, ensuring that the entry's foreign key is properly set and then return the user to the appropriate calendar page.
I don't know, though, how class-based generic views receive their URL arguments and I'm not clear on how to set the success_url so that it reuses the id that was originally passed to the creation URL. Again, thank you in advance for your help.
What I'm asking, essentially, is, what is the class-based generic view equivalent of the following:
def create_course_entry(request, class_id):
'''Creates a general calendar entry.'''
if request.method == 'POST':
form = CourseEntryForm(request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.course = Class.objects.get(pk=class_id)
new_entry.full_clean()
new_entry.save()
return HttpResponseRedirect('/class/%s/calendar/' % class_id)
else:
form = CourseEntryForm()
return render_to_response('classes/course_entry_create.html',
{ 'class_id': class_id, 'form': form, },
context_instance=RequestContext(request))
You could subclass the edit.CreateView
generic view, set the class/course in the dispatch()
method, and save this by overriding the form_valid()
method:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.views.generic.edit import CreateView
class CourseEntryCreateView(CreateView):
form_class = CourseEntryForm
model = CourseEntry
def dispatch(self, *args, **kwargs):
self.course = get_object_or_404(Class, pk=kwargs['class_id'])
return super(CourseEntryCreateView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.course = self.course
self.object.save()
return HttpResponseRedirect(self.get_success_url())
If you're not customising the CourseEntryForm
ModelForm
, then you can leave out the form_class
property.
Unfortunately, it is not possible to call super()
in the form_valid()
method - due to the way it has been written would mean the object would be saved again.
If you need the Class (course?) instance in the template context, then you can add this in the get_context_data()
method:
def get_context_data(self, *args, **kwargs):
context_data = super(CourseEntryCreateView, self).get_context_data(
*args, **kwargs)
context_data.update({'course': self.course})
return context_data
An alternative to Matt Austin's answer might be to override the get_form
method:
from django.shortcuts import get_object_or_404
from django.views.generic import CreateView
class CourseEntryCreateView(CreateView):
form_class = CourseEntryForm
model = CourseEntry
def get_form(self, form_class):
form = super(CustomCreateView, self).get_form(form_class)
course = get_object_or_404(Class, pk=self.kwargs['class_id'])
form.instance.course = course
return form
This way, .course
is on the CourseEntry
instance in the context, and on the instance created when the form is saved upon POST.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With