change request.GET QueryDict values - python

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.

Related

Override serializer.data in Django REST Framework

I've been trying to alter the value of a form field the Django REST Framework's admin panel and for some reason the change never takes place. I have the serializer below
class SomeView(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
# I Want to override this and change the POST data
def perform_create(self, serializer):
user = self.request.user.id
# this was a form field where I manually entered the user ID
# I now want it to default to the logged in user
serializer.data['user'] = user
# This returns the original user that was entered into the form field
print serializer.data
I checked out serializer.data with dir() and it's just a python dictionary so I can't figure out why I can't modify the value. As a test, I tried to add extra values but that doesn't work either
# this doesnt work
serializer.data['some_new_field'] = 'test'
EDIT
On another note, I can copy the data and edit it
fake_data = serializer.data.copy()
fake_data['old_value'] = 'new value'
However, it always fails to validate
serializer = MyModelSerializer(data=fake_data)
serializer.is_valid() # returns false
EDIT EDIT:
Ok, so the validation error was caused by Django returning a SimpleLazyObject. Everything works now when I perform a copy of the data, but I'm really curious as to why I can't edit serializer.data directly without copying it. The problem is solved now, but if anyone can provide insight on the issue just for curiosity, that would be awesome.
I checked out serializer.data with dir() and it's just a python dictionary so I can't figure out why I can't modify the value.
While the value returned from Serializer.data is indeed a dictionary, Serializer.data is not a simple instance variable.
If you look at rest_framework/serializers.py:
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
# [...]
#property
def data(self):
ret = super().data
return ReturnDict(ret, serializer=self)
ReturnDict inherits from OrderedDict, but you still get a new dictionary every time you access Serializer.data.
The real data is in _data, however as noted by the underscore you might not want to modify that either as it is not intended to be public. The values are filled by Serializer.to_representation() which you could override on the viewset.
As for the second part: ModelViewSet defines get_serializer() that is called with the request POST data to create the serializer you want to modify. I'd suggest try to change the input data before the serializer is created, instead.

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)

django change model form instance

Is there any easy way to change the instance of a Django model form after it's been initialised?
For example the following would pre-populate the form in a template with the contents currently in the db for the object with an id of 1:
form = exampleModelForm(instance = Model.objects.get(pk=1)
This will also save the relevant object when save() is called rather than create a new one.
Where this will create a new object and not pre-populate the form in the template:
form = exampleModelForm()
As I'm returning a blank form from a different method, I would then like to assign an instance to it after it's been created and amend the object so that it can be saved and the template is pre-populate with the values that exist in the db. I want something like this but what I've tried doesn't seem to work:
form = methodThatGetsForm(somearg)
form.instance = ExampleModel.objects.get(pk = getId(somearg))
Is there a simple function that I'm missing here?
I have NOT tested this, but I wonder if you can reinitialize a new form with the returned form data and the instance as the new object.
form = methodThatGetsForm(somearg)
new_form = ExampleModelForm(form.cleaned_data, instance=ExampleModel.objects.get(pk=getID(somearg)))
new_form.save()
If not, there should be a way to get the data as a dictionary of key/value pairs for the fields from the form returned, using it's ._meta data. I think if you send that dictionary to the form init it will assign those values to the instance object, just like sending it request.POST.

Django HttpRequest problem

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.

How do I build a custom "list-type" entry to request.POST

Basically I have a model with a ManyToMany field, and then a modelform derived from that model where that field is rendered as a "multiple choice" selectbox. In my template I'm having that field omitted, electing instead to prepare the values for that field in the view, then pass those prepared values into request.POST (actually a copy of request.POST because request.POST is immutable), then feeding request.POST to the form and then carry on as normal. I can't figure out how to do this, because request.POST isn't just a simple python dictionary, but instead a QueryDict, which behaves a little differently.
The field I need to populate is called "not_bases". When I create the widget using the form, it works perfectly well internally, but just not to my liking UI-wise. When I inspect the django-form submitted POST value via django's handy debug error window, the working QueryDict looks like this:
<QueryDict: {u'not_bases': [u'005', u'00AR', u'00F', u'00FD'], [...] }>
It appears the value for "not_bases" is a list, but it's not simply a list. I can't just .append() to it because it won't work. I dug around the documentation and found .update(), which appears to work, but doesn't. Here is my code:
newPOST = request.POST.copy()
for base in bases:
newPOST.update({"not_bases": base.identifier})
and here is the output:
<QueryDict: {u'not_bases': [u'KMER', u'KYIP'], u'reference': [u''], [...] }>
But when I feed that QueryDict to the form, I get an form validation error that says "not_bases: Enter a list of values.". Its obvious that the list-looking things coming from the str() representation of the QueryDict are not the same in the two cases above, even though they look exactly the same
So how do I do this?
It's really not clear what you're trying to do here, but I doubt that hacking the QueryDict is the right way to achieve it.
If you are trying to customise the display of the not_bases field, you can simply override the definition in your modelform declaration:
class MyModelForm(forms.ModelForm):
not_bases = forms.ChoiceField(choices=[(base, base) for base in bases])
class Meta:
model = MyModel
Or, if you simply want to avoid showing it on the form, you can exclude it from the form and set the value after validation.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
exclude = ['not_bases']
....
if request.POST:
if form.is_valid():
instance = form.save(commit=False)
instance.not_bases = bases
instance.save()
Does either of these do what you want?

Categories