Changing field values in form.clean_xxx - django

I want to validate form input and if required modify a field used to build a subdomain for a URL. IE take out the illegal characters. Here is a VERY simple example to illustrate the problem.
class MyForm(forms.Form):
def clean_f(self):
f = self.cleaned_data['f']
if f.count('%'):
f = f.replace('%', '')
return f
This doesn't change the form. I want the user to see the 'stripped' value, but it always shows the submitted value.
Is it possible to do this with a simple form clean_xxx method?
Otherwise I will use my AJAX form processor.
Thanks

Related

Django 1.6 request POST/GET empty

I use a function-based view and try to validate a form which is submitted over Ajax (with jquery.form plugin):
Content-Type:application/json; charset=UTF-8
X-CSRFToken:jRr4oOBHQS5mtwopN69xHocjWJBYuJHa
X-Requested-With:XMLHttpRequest
Request payload:
csrfmiddlewaretoken=jRr4oOBHQS5mtwopN69xHocjWJBYuJHa&code=123456
now, in the view function, I have request.GET/POST empty, but request.body as a string, and I can't validate the form.
form = CodeCheckForm(parse_qs(request.body))
form.is_valid()
In the second line, the clean* functions aren't called, which is really weird.
Changing to use data or initial doesn't help either:
form = CodeCheckForm(data=parse_qs(request.body))
What am I doing wrong?
EDIT: among the answers, the decisive was to change the content type. In jquery.forms plugin I set contentType option to application/x-www-form-urlencoded; charset=UTF-8.
EDIT 2: there are 2 ways to supply arbitrary data around the standard way, but they weren't suitable in my case:
1) form = MyForm(parse_qs(request.body)) is almost correct, but Django forms expect this to be a QueryDict, and have some properties, while this is a usual dict. Form class raises exception and crashes the view.
2) form = MyForm(data=parse_qs(request.body)) works, but does not call clean* functions. This is intentional, as Django developers made this way as a way around clean functions. You're supposed to validate the data yourself, and then submit it this way. Django form then does not clean it in any way and decides the form is not validated, hence form.is_valid() will be False.
The GET and POST only contain form data. They are empty for you because your content type is 'application/json'. It's not clear to me why you've used this content type, since the payload looks like form encoded data to me, not json.
If you manually parse the payload, use the data argument. The initial argument is only used to show initial values. If you don't bind the form to data, then the form is unbound, and will never be valid.
I'm not sure why the following line didn't work. What is the value of parse_qs(request.body)?
form = CodeCheckForm(parse_qs(request.body))

DJANGO - change a form value with request.POST?

so i have this code:
post = request.POST.copy()
post['relationshipId'] = theRelationship.id
theStory = StoryForm(post, request = request, initial {'relationshipId' : theRelationship.id})
initially, my code looked like this:
theStory = StoryForm(request.POST, request = request, initial {'relationshipId' : theRelationship.id})
which caused validation problems. The validator would complain that the relationshipId wasn't set. Why would this be?
EDIT: the first block of code works fine, and I am super-happy with it. The question pertains to the second block of code, which was initially what I had (and what i've just spend some time working on) which, to me, is acting "weird"
The first snippet sets the relationshipId field dynamically, instead of taking it from the POST parameters supplied in the web request.
The second snippet will take that value directly from request.POST, so if your form submits an invalid value, or if no value is given, it will not validate.
The initial argument only applies to unbound forms (see https://docs.djangoproject.com/en/1.5/ref/forms/fields/#initial). You could leave it out here, because you are binding the form to post or request.POST.

In a Django form clean function, how can one reliably test if an optional field was filled out?

In Django, I have a form class with a clean function. In this clean function, I check to see if an optional select box was filled out.
def clean_session_1(self):
# Check if session_1 is filled out.
if self.cleaned_data['session_1']:
# more validation
return self.cleaned_data['session_1']
If the select box was filled out, then more validation of the field ensues.
For some reason, this code is not testing whether the field was filled out and runs "more validation" every time.
I was wondering how can one reliably test if this field "session_1" was filled out? Thanks!
Access self._raw_value('key') to get the raw entry in the form field (i.e. just text, not processed to a python object).
Update: As Ahsan says, do it in the clean method. You should probably call the superclass clean method also.
You can check it in form's clean method
def clean(self):
data = self.data # data contains all fields, optional or required both
optional_field = data.get('optional_field', None)
# more validation
return optional_field

Can you set default values for request.get() (not post.get)?

I have 2 HTML submission fields under one submit button, one of which is optional. I'm using the 'get' method to retrieve submitted data, but I want the optional field to have a default value just in case the user submits an empty form. If I don't do this, I get a MultiValueDictKeyError.
if request.method == 'GET':
# required
name = request.GET['name']
# optional
color = request.GET['color']
I think a possible solution is try / except for every field, but is there a more elegant method? I know for get.post() you can do something like
color = request.POST.get('color', False)
But this doesn't seem to work for just request.get()
Any ideas?
Thanks,
fertileneutrino
Confused here... request.get() won't work, but request.GET.get() should. Did you just mistype or were you actually using request.get()?

In Django, how do I deal with an "or" in the url regex once I get to the view?

I'm just learning Django, and am getting stuck with some url logic. I'm trying to allow either a category name or id in the url:
...
url(r'^(?P<booze_q>\w+|\d+)/$','glasses.views.booze'),
...
And then in thew view, only deal with that result once. However, if the url is a string - in this case, Whiskey, I get an error for trying to pass a string where an int is expected. This is the closest I've gotten so far:
def booze(request, booze_q):
booze = get_object_or_404(Booze,Q(pk=booze_q)|Q(name=booze_q))
return render_to_response('booze/detail.html', {'booze': booze})
But this returns an error: invalid literal for int() with base 10: 'Whiskey'
I'm sure it's a pretty easy thing, but this is my first Django app, so any help would be appreciated.
tl;dr: End result, I'd like mysite.com/1/ or mysite.com/Whiskey/ to both call the glasses.views.booze view, and get the object with id=1 or name=Whiskey
This is a common scenario you'll encounter quite often, which is typically handled by resorting to multiple arguments and having views behave differently based on which of the view arguments are then present or not.
What you do is first define a URL pattern that uniquely matches each specific case and then let Django's URL resolver set the arguments accordingly based on which of the patterns was matched.
Here's an example with a class based view, that performs two different queries based on which of the two keyword arguments, booze_id or booze_name, is set:
url(r'^(?P<booze_id>\d+)/$', BoozeDetailView.as_view()),
url(r'^(?P<booze_name>\w+)/$', BoozeDetailView.as_view()),
class BoozeDetailView(DetailView):
model = Booze
def get_object(self):
booze_id = self.kwargs.get('booze_id', None)
booze_name = self.kwargs.get('booze_name', None)
if booze_id:
return self.model.objects.get(id=booze_id)
else:
return self.model.objects.get(name=booze_name)
You will always get a string, even if the string contains a number.
1) You should not have a parameter that could be either an id or something else. One day you will enter an item whose name is a number and your app will fail.
2) When querying for pk with a string django automatically tries to convert it into an integer. You'll have to handle the non-pk case before constructing that query.