Prepopulate Django (non-Model) Form - django

I'm trying to prepopulate the data in my django form based on some information, but NOT using ModelForm, so I can't just set the instance.
This seems like it should be really easy, but for some reason I can't find any documentation telling me how to do this. This is my form:
class MyForm(forms.Form):
charfield1 = forms.CharField(max_length=3)
charfield2 = forms.CharField(max_length=3)
choicefield = forms.ModelChoiceField(MyModel.objects.all())
I tried just doing:
form = MyForm()
form.charfield1 = "foo"
form.charfield2 = "bar"
# a model choice field
form.choicefield = MyModel.objects.get(id=3)
which does not work.

Try:
form = MyForm({'charfield1': 'foo', 'charfield2': 'bar'})
The constructor of Form objects can take a dictionary of field values. This creates a bound form, which can be used to validate the data and render the form as HTML with the data displayed. See the forms API documentation for more details.
Edit:
For the sake of completeness, if you do not want to bind the form, and you just want to declare initial values for some fields, you can use the following instead:
form = MyForm(initial={'charfield1': 'foo', 'charfield2': 'bar'})
See the documentation of initial values for details.

There are two ways of populating a Django form.
The first is to pass a dictionary as the first argument when you instantiate it (or pass it as the data kwarg, which is the same thing). This is what you do when you want to use POST data to populate and validate the form.
data_dict = {'charfield1': 'data1', 'charfield2': 'data2', 'choicefield': 3}
form = MyForm(data_dict)
However, this will trigger validation on the form, so only works if you are actually passing in valid and complete data to begin with - otherwise you will start off with errors.
The other way to populate a form is to use the initial parameter (documented here). This gives initial values for the form fields, but does not trigger validation. It's therefore suitable if you're not filling in all values, for example.
form = MyForm(initial=data_dict)
To populate a choicefield via initial, use the pk value.

You can use model_to_dict() to convert an instance to a dictionary, and then populate a form with that. Something like this should work:
from django.forms.models import model_to_dict
...
my_obj = MyModel.objects.get(abc=123)
form = MyForm(initial=model_to_dict(my_obj))
Note: I'm using django version 1.3

For what it's worth, the FormView class-based view way to do this would be to override the FormView's get_initial function. get_initial returns the initial keyword arguments used by get_form_kwargs to instantiate the form.
Docs:
for get_initial, here,
for get_form_kwargs, here.
Sample code:
from django.views.generic.edit import FormView
class MyFormView(FormView):
def get_initial(self):
initial = super(MyFormView, self).get_initial()
# update initial field defaults with custom set default values:
initial.update({'charfield1': 'foo', 'charfield2': 'bar'})
return initial

Related

Sending form to another view django

I am building a website and I want various views that will ask the user to request a quote from our page. I want to keep the code as DRY as possible so I am writing a view quote which will receive the quote requests from various views and, if there is a validation error redirect back to the page that made the request. I managed to solve this using the super bad practice 'global variables'. I need a better solution, I would like redirecting to respective view with the current form so I can iterate through the form.errors. Here is my code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
global session_form
session_form = form
return redirect('Main:' + quote_for) # Here I would like to send form instead of storing in global variable`
You can use the HttpResponseRedirect function, and pass as argument the page that made the request.
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
All the META data is store on a dictionary, if you want to learn more check the documentation.
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
If you redirect to the referrer, form.errors will be empty, as redirection is always a GET request.
I can think of two solutions to your problem:
Submit forms asynchronously using JavaScript and so populate the errors
Make all the views containing the form support POST - one way to do this would be to create a base class that inherits from FormView
The second option is a typical way of handling forms in Django - you process both POST and GET inside the same view.
After two days of searching I finally found the answer. Instead of saving form in request.session I just save request.POST and then redirect. Here is the code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
request.session['invalid_form'] = request.POST
return redirect('Main:endview')
def endview(request):
session_form = request.session.pop('invalid_form', False)
if session_form:
form = Quote(session_form)
# render template again with invalid form ;)
Now I can repeat this with all the views I want and just change the what_for input of each form to match the respective view (Like I intended).

Django web application Taking user input and processing it

I am building a web application using django. I need to take a string input from the user and process it using a method I have written myself. How to achieve this in Django? Here are the things I need to do
Get User Input userinput = (string) On start page
Put this string as an argument in my method MyMethod(userinput) and Run it in the backend
Display what MyMethod() returns on another page.
I suggest that you start from django tutorial: https://docs.djangoproject.com/en/1.9/intro/tutorial01/
Basically, what you are going to need is form with one text field, HTML template that will render the form, view that will render HTML template with instance of a form when GET request arrives and call your MyMethod with value from form when POST request arrives and URL rule to call your view function on some URL.
Without additional data or any attempt to solve it and concrete problem you encounter - I can hardly offer more help.
You need to create a model with fields which you want to update by user input, then create a form based on this model. Then import this in a view and render it in a template
simple example:
forms.py:
class InputForm(forms.ModelForm):
class Meta:
model = YourModel
fields = ['fields_from_YourModel']
views.py:
from .forms import InputForm
def user_input(request):
input = CustomUser.objects.get(pk=request.user.pk)
if request.POST:
form = ProfileForm(request.POST, instance=input)
if form.is_valid:
form.save()
else:
form = ProfileForm()
return render(request, 'input.html', {'form':form})
Other steps more easier for beginner, you'll find examples in docs

Can I turn a Django form into a GET request string?

I want to take a ready-made form (i.e an object of a class derived from django.Forms.form with validated bound data) and urlencode it as though it were submitted with GET. Is there a built-in way?
To show why I'm asking this questino, and why I can't just call urlencode, the output from this should be "box=on".
from django import forms
from urllib import urlencode
class DemoForm(forms.Form):
box = forms.BooleanField(required=False)
instance = DemoForm({"box": True}) # it's irrelevant how this data is supplied
instance.is_valid()
print "encoded:", urlencode(instance.cleaned_data)
In fact it's "box=True", because urlencode isn't encoding the form it's encoding the cleaned values (and believe me, BooleanField is the simplest case).
So I'm asking for a way to encode the form as though it were a GET string. A correct GET string.
Calling urllib's urlencode on the form's cleaned_data won't work well in two cases:
If you are using a ModelChoiceField, the cleaned_data will contain the actual object(s), not the IDs. These will urlencode() to their string representations instead of their primary keys.
If you are using a field that can hold multiple values (such as MultiValueField, MultipleChoiceField or others), urlencode() will lose all but one value from that field. So {'mykey':[1,2,3]} becomes ?mykey=3 instead of ?mykey=1&mykey=2&mykey=3 the way django does it.
To deal with both of these problems, use the form's built-in urlencode function:
form = MyForm(request.POST) #or a dict or whatever
form.is_valid()
querystring = form.data.urlencode()
Note that this is called on data, not cleaned_data. If your form changes values as part of validation, those changes won't be reflected here.
I'm not fully sure what you mean with ready-made form, since a form will normally have no values associated. Or do you mean to take a form a user filled and have it posted as a get?
You can use urllibs encode to create a get-string:
import urllib
print urllib.urlencode({'key1': 'value1', 'key2': 'value2'})
# key1=value1&key2=value2
If you want to take a posted form and create a GET-string from this data:
form = MyForm(request.POST)
if form.is_valid():
print urllib.urlencode(form.cleaned_data)
# name=value&name=value etc
If you want to create a GET for an unbound form:
# this form contains intitial values
# which are shown when printing the form
form = MyForm()
print urllib.urlencode(form.initial)
# name=value&name=value etc

Validation of modelformsets from modelforms

One view I have is using a modelform with custom field cleaning. One type of cleaning is checking if the user is trying to submit a change to a field that is already set to the value, and it works exactly how I want it to work by throwing a ValidationError. The problem of course is that I can only submit one form at a time, so I'd like to use a modelformset to submit multiple forms.
I know it is possible to override the modelformset's clean method, but I'm asking if it's possible to use the modelform's field cleaning methods on the modelformset?. Currently when I submit the modelformset with empty fields the is_valid() passes which seems strange to me...
I also would like to know "typically" where the custom modelformset validation code would go? I was thinking with the forms.py.
*Edit -- with answer. My httpResponseRedirect was allowing the form to be submitted without validation.
def mass_check_in(request):
# queryset
qs = Part.objects.none()
errlst=[]
c = {}
c.update(csrf(request))
# Creating a model_formset out of PartForm
PartFormSetFactory = modelformset_factory(model=Part,
form=PartForm,
formset=BasePartFormSet,
extra=2)
if request.method == 'POST':
PartFormSet = PartFormSetFactory(request.POST)
if PartFormSet.is_valid():
PartFormSet.save()
return http.HttpResponseRedirect('/current_count/')
else:
PartFormSet = PartFormSetFactory(queryset=qs, initial=[
{'serial_number':'placeholder',
},
{'serial_number':'placeholder'
}])
return render(request,'mass_check_in.html',{
'title':'Add Item',
'formset': PartFormSet,
'formset_errors': PartFormSet.non_form_errors(),
})
If you don't enter any data at all in one of the modelforms in your model formset, it will skip validation for that form; from the docs:
The formset is smart enough to ignore extra forms that were not changed.
You can actually disable this functionality though by forcing empty_permitted=False on the forms; see the accepted answer to this question for more: Django formsets: make first required?
Formsets do have their own clean method, but it's used to validate information between two or more forms in the formset, not for validating the individual forms themselves (which should be taken care of in the forms clean method - as you are doing now.
A formset has a clean method similar to the one on a Form class. This is where you define your own validation that works at the formset level:
Here's another similar question:
Django formset doesn't validate

Django: Form in base template

Hi Stackoverflow people,
In my Django project I created a form to register users. This forms can be called through a specific url -> view method. Once the user has filled in the form, presses submit, the same view method will be called and if form.is_valid() is true, then ... simply a standard form, nothing special.
Now, I would like to integrate this little form on every page, and therefore I would like to add it to the base template. I have read that I could populate the form variable through a context_processor, but could I define the process after the submission of the form?
I have created the context_processor.py (as below), added the context_processor to the TEMPLATE_CONTEXT_PROCESSOR dir in the settings (as described here):
from app.forms import Form
def registration_form(request):
return {
registration_form : Form()
}
First of all, the form variable won't be displayed.
And secondly, how do I manipulate the form submission?
I think I misunderstanding the context_processor of Django and would be more than happy about comments on the overall process.
Thank you!
how are you trying to access to form in your template? you probably don't want to use a function name as your dictionary key, maybe you want
return {
'registration_form': Form(),
}
not sure what you mean by manipulate the form submission, but i guess you'd need all the form processing logic in your context processor
if request.POST:
form = Form(request.POST)
# validate etc
instead of creating context processor, create template tag for the purpose and place the tag in base.html
for form submission and displaying errors use ajax, and front-end validations.