Reputation: 8199
I know how to set initial values to a form from the view. But how do I go about letting a generic view set initial values to a form? I can write a wrapper view for the generic view, but I still have no access to the form object instantiation.
The specific goal I'm trying to achieve is to have a user create a new object, using the create_object generic view. However, I'd like to set a field of the object 'user' to the currently logged in user, which is only accessible as request.user. How can the form be initialized to have this field?
Edit: I came across __new__. Could this call its own constructor with some default arguments?
Many thanks.
Upvotes: 2
Views: 3975
Reputation: 2718
If you want all the features of the generic view then you can just create a new generic view using the original as a template.
Eg:
def create_object_with_initial(request, model=None, template_name=None,
template_loader=loader, extra_context=None, post_save_redirect=None,
login_required=False, context_processors=None, form_class=None, initial=None):
if extra_context is None: extra_context = {}
if login_required and not request.user.is_authenticated():
return redirect_to_login(request.path)
model, form_class = get_model_and_form_class(model, form_class)
if request.method == 'POST':
form = form_class(request.POST, request.FILES)
if form.is_valid():
new_object = form.save()
msg = ugettext("The %(verbose_name)s was created successfully.") %\
{"verbose_name": model._meta.verbose_name}
messages.success(request, msg, fail_silently=True)
return redirect(post_save_redirect, new_object)
else:
print "creating", form_class, " with initial data ", initial
form = form_class(initial=initial)
# Create the template, context, response
if not template_name:
template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'form': form,
}, context_processors)
apply_extra_context(extra_context, c)
return HttpResponse(t.render(c))
This is copied from /site-packages/django/views/generic/create_update.py with only lines 3 and 21 changing to incorporate the initial data.
Then use it as you might expect:
object_info = {
'model': YourModel,
'initial': {'data' : 'Initial Value'},
'template_name': 'template.html'
}
url(r'^path/$',
login_required(create_object_with_initial),
object_info,
name='url_name'),
That should work.
Upvotes: 0
Reputation: 126631
You could do this in a generic view wrapper by dynamically constructing a form class and passing it to the generic view, but that cure is probably worse than the disease. Just write your own view, and wait eagerly for this to land.
Upvotes: 3
Reputation: 5147
Unfortunately, you cannot achieve this behavior through Django's create_object
generic view; you will have to write your own. However, this is rather simple.
To start off, you must create a new form class, like this:
from django import forms
class MyForm(forms.ModelForm):
class Meta:
model = MyModel # model has a user field
Then you would be able to create a view like this:
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
@login_required
def create_mymodel(request):
if request.method == 'POST':
# Get data from form
form = MyForm(request.POST)
# If the form is valid, create a new object and redirect to it.
if form.is_valid():
newObject = form.save()
return HttpResponseRedirect(newObject.get_absolute_url())
else:
# Fill in the field with the current user by default
form = MyForm(initial={'user': request.user})
# Render our template
return render_to_response('path/to/template.html',
{'form': form},
context_instance=RequestContext(request))
Upvotes: 4