Django HttpRequest problem - python

I'm trying to gat the value of a form field in django, now
xxx = request.POST[u'a1']
gives me a value, but
xxx = request.POST.get(u'a1')
gives me nothing
what am I doing wrong?
Update:
Using the first method, request.method = POST,
using the second method changes it to GET,
all I am doing is replacing one line of code.
Ingmar, yes this does return true.
Shawn, first method produces DEBUG:root:[(u'a1', u'A1_6')],
second method produces DEBUG:root:[]

The get method takes two parameters: key and a return value for where there's no match for the key (defaults to None).
Maybe the first example worked only in cases where the form had a value in the field 'a1'.
Either set a return value for the get method (e.g. xxx = request.POST.get(u'a1', 'something')) or check in advance whether you have that field in the form (if u'a1' in request.POST ...)

A bit confusing question, but the way I understand you, you have a request that at one point contains a QueryDict with data in request.POST, but at a later point in the code cointains an empty QueryDict: {} in request.POST, and you are looking for the reason why and where the data disappears.
The Django docs say the QueryDict in HttpRequest is immutable, and cannot be changed. So you probably shouldn't be looking for code changing the value of the request.POST QueryDict, but some code that replaces the whole request.POST QueryDict with another one.
My guess is that you are assigning the value 'GET' to request.method at some point in the code, since you say that in function number two, request.method is changed to GET
When tinkering with a response of the type PUT some time ago I discovered that django actually applies logic to the HttpResponse object if response.method is changed, resulting in a changed request.POST QueryDict.

Related

JavaScript Null does not convert to None

#parser_classes([MultiPartParser, FormParser])
#api_view(['POST', ])
def product_list(request):
print(request.POST.get('key'))
print(request.data.get('key'))
print(request.FILES)
When I am sending form data with value of key=null it displays null as string but didn't convert to None what should I do. The work around that I have to do
is something like
if request.data.get('key', None) in ['null', None]:
#then do something
But this doesn't seem to be a clean way of doing this. So what should I do?
I expected that django or django rest framework will automatically convert null to None.
There is no such thing as null/none in HTTP form-data content (in fact there's no such thing as types in the way we'd usually understand, though there can be a content-type associated with each item).
So what happens here is on the javascript side the null gets converted to a string, added to the data, sent to the server, which just gets a null string without any more information.
Generally, "null" items would be missing entirely, alternatively, they would have an empty value associated with them.
Either way, this is not an issue with django.
I made a small workaround to solve this issue by designing a middleware. I dont know if its good but it worked for me. I made it first mutable, changed it then made immutable again.
Note : if data sent is nested json you have to alter it to handle json recursively.
from django import http
from django.utils.deprecation import MiddlewareMixin
class NullStringToNoneMiddleware(MiddlewareMixin):
"""Responsible for converting all string null values to None"""
def process_request(self, request):
request.POST._mutable = True
for j in request.POST:
if request.POST[j] == 'null':
request.POST[j] = None
request.POST._mutable = False

Passing data through Django forms

I feel I'm missing the obvious but I can't work it out!
I have written a custom form (for use outside of django admin), which I want to use to create / update instances of a number of model instances as well as hold conditional fields. However I seem to be losing my conditional data.
In my view I instansiate an instance of my form and pass it into the request context:-
view.py
form = MyForm(my_bool=True, pid=7)
render(request 'my_page.html', {'form': form})
forms.py
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
my_bool = kwargs.pop('my_bool', False)
self.pid = kwargs.pop('pid', None)
super(MyForm, self).__init__(*args, **kwargs)
if my_bool:
self.fields['textbox'] = forms.CharField(max_length=256)
That all works fine and the form renders as expected. Now when I submit the form it hits the below
view.py
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
# Do Stuff
My problem is that the form object in the above code does not contain my 'textbox' or 'pid' fields even though the form I submitted did. I'm certain whatever I'm doing wrong is extremely obvious but from a whole lot of googling I cant work out a simple way to instantiate a form, pass it some data about what fields I want to show as well as say the id of the model I eventually want it to update and then have access to the info I passed in the post part of the code.
The # Do Stuff part of my code is supposed to take the 'pid' I passed to the form and use that to fetch a product e.g. Product.objects.get(pk=pid), however without storing the pid in the session I cant work out how to access it from the postback.
If a validation error occurs in my form i.e. form.is_valid() returns false I render the request again passing the form I already have, that way I see the validation errors however any conditional fields I passed initially are missing and their values ignored.
Maybe I'm just going about it completely wrong and I should be doing this a different way. What I am trying to achieve is a content entry form whose fields change depending on the type of product it is passed, once filled in the form saves the data to that instance of the product.
Any help would be greatly appreciated, I've found Django to be extremely accommodating to anything I've thrown at it so far and this feels like such a common use-case that I must just be doing it wrong!
I'm on Django v1.11 & Python v3.6.
you are passing two arguments to create the form, namely my_bool and pid. But you are not passing those arguments in the POST view. In particular my_bool is None so the textbox field never gets generated. Changing
form = MyForm(request.POST)
to
form = MyForm(request.POST, my_bool=True, pid=7)
should do the trick.

Checkboxes in a table and values post

I'm new on django and I wish to POST checkboxes values from a view to another view.
This is the snippet:
When I check the two only checkboxes that are in my table rows I have only one value (from Django debug window):
Variable Value
csrfmiddlewaretoken u'6i8aRyhvTq29EOy6sfffzPtKy9jXUsVi'
Login u'jhgjghj'
but the post objects should be:
Variable Value
csrfmiddlewaretoken u'6i8aRyhvTq29EOy6sfffzPtKy9jXUsVi'
Login u'jhgjghj'
Login u'sdfsfd' (the second object not posted)
In addition I have a second problem.
This is the view to which I pass these POST data:
def deleteObjects(request):
template = 'delObj.html'
objects = []
for obj in request.POST.items():
if obj('Login'):
todelete = Login.objects.get(obj('Login'))
objects.append(todelete)
context = {'objects' : objects}
return render(request, template, context)
I get an error "Tuple object is not callable" (for the row if obj('name') == 'Login':), but i can't understand why.
Aren't POST data elements KEY and VALUE of a dict-like object?
Thanks in advance
Yes, POST is a dict-like object, but you seem to have a misunderstanding about how those work. items() returns a tuple of (key, value) for each item in the dict - so, for example, obj would be ('Login', 'jhghghj'). So it makes no sense to say obj('Login'): obj is not callable, and neither is it accessed via dict notation (which would be obj['login']). Instead you would want this:
for key, value in request.POST.items():
if key == 'Login':
todelete = Login.objects.get(value)
However, and here's where we get to your first problem, I can't understand why you want to iterate through at all. Like you said, request.POST is a dict-like object, and you want a single key, Login. So normally you would simply get the value of Login via request.POST['Login'] - except that you have two values for Login, and the reason POST is only dict-like and not actually a dict is that it defines a getlist method for exactly this use case. So, this is what you want:
for value in request.POST.getlist('Login'):
todelete = Login.objects.get(value)

change request.GET QueryDict values

I want to change request.GET querydict object in django. I tried this but changes made by me are not reflected. I tried this
tempdict = self.request.GET.copy() # Empty initially
tempdict['state'] = ['XYZ',]
tempdict['ajaxtype'] = ['facet',]
print self.request.GET
I get
<QueryDict: {}> as my output
Is it possible to change the request.GET querydict object in django?
You can't change the request.GET or request.POST as they are instances of QueryDict which are immutable according to the docs:
QueryDict instances are immutable, unless you create a copy() of them. That means you can’t change attributes of request.POST and request.GET directly.
Your code should work if you add one little step: you are now making a copy of the request.GET, but you have not assigned it back to the request. So it is just a standalone object which is not related to the request in any way.
This would the the necessary improvement:
tempdict = self.request.GET.copy()
tempdict['state'] = ['XYZ',]
tempdict['ajaxtype'] = ['facet',]
self.request.GET = tempdict # this is the added line
print(self.request.GET)
I have tested it in writing custom middleware, but I assume it works the same way in all places.

How to properly validate a MultipleChoiceField in a Django form

I have a MultipleChoiceField representing US states, and passing a GET request to my form like ?state=AL%2CAK results in the error:
Select a valid choice. AL,AK is not one of the available choices.
However, these values are definitely listed in the fields choices, as they're rendered in the form field correctly.
I've tried specifying a custom clean_state() method in my form, to convert the value to a list, but that has no effect. Printing the cleaned_data['state'] seems to show it's not even being called with the data from request.GET.
What's causing this error?
from django import forms
class MyForm(forms.Form):
state = forms.MultipleChoiceField(
required=False,
choices=[('AL','Alabama'),('AK','Alaska')],
)
MultipleChoiceFields don't pass all of the selected values in a list, they pass several different values for the same key instead.
In other words, if you select 'AL' and 'AK' your querystring should be ?state=AL&state=AK instead of ?state=AL%2CAK.
Without seeing your custom clean_state() method I can't tell you what's going wrong with it, but if the state field isn't valid because the querystring is wrong then 'state' won't be in cleaned_data (because cleaned_data only holds valid data).
Hopefully that helps. If you're still stuck try adding a few more details and I can try to be more specific.

Categories