6

I want to store ModelForm data in database, in JSONField, to be able to create object from this data later, simply calling:

form = ModelForm(data_from_jsonfield_as_querydict)
if form.is_valid():
    object = form.save()

Problem 1:

I have data in POST:

>>> print request.POST
{u'field-1': u'value1', u'field-2': [u'value-2a', u'value-2b']}

And I have to convert this QueryDict to dict. But if I call request.POST.dict() I lose list values form field-2:

>>> print request.POST.dict()
{'field-1': 'value1', 'field-2': 'value-2b'}

I tried to use request.POST.getlist but then I obtain all values as a lists:

>>> for k in request.POST.keys():
...     print request.POST.getlist(k)
[u'value1']
[u'value-2a', u'value-2b']

I cannot even check if given value in above loop is list instance, because request.POST.get(k) does not return error if the value is list and on the other hand request.POST[k] returns MultiValueDictKeyError for every field.

The only solution which comes to my mind is to loop over all fields obtained by getlist() and convert one-value lists to strings, but it seems to me like overkill.

Problem 2:

Assuming the Problem 1 is resolved and I have dict with form data stored in database, like so:

# object.data
{u'field-1': u'value1', u'field-2': [u'value-2a', u'value-2b']}

When I want to create object using above dict as form data, I have to convert it do QueryDict, which can be simply done by:

querydict = QueryDict('', mutable=True)
querydict.update(object.data)

And then:

form = ModelForm(querydict)

The problem is that when creating querydict from dict with some values which are list instance, all querydict values are wrapped in lists:

print querydict
{u'field-1': [u'value1'], u'field-2': [[u'value-2a', u'value-2b']]}

For that reason, form validation fails for field-2 because getlist for that field returns list of lists (with one value) and not list of values.

EMiDU
  • 654
  • 1
  • 7
  • 24
  • 2
    This seems like it'd only be necessary if you're building forms dynamically and have no way of knowing what will be in the form when it's generated... in which case you should probably be either defining your fields in a way that includes your type. If that's not what you're doing, you may want to step back and rethink whether this is a good approach to whatever problem you're attempting to solve (and really, putting that in your question would allow for much more useful answers). – kungphu Mar 03 '16 at 08:24
  • Could you please describe the expected `dict` you would like to convert this sample `POST` to? – zsepi Mar 03 '16 at 08:32
  • @kungphu I don't think that converting `QueryDict` to `dict` without loosing `list` data is something unusual. Anyway, I re-edited my question. – EMiDU Mar 03 '16 at 08:39
  • Possible duplicate of [How to change a django QueryDict to Python Dict?](http://stackoverflow.com/questions/13349573/how-to-change-a-django-querydict-to-python-dict) – vishes_shell Mar 03 '16 at 08:41
  • That's not my point. It's just part of working with Django that inputs with multiple values require using `getList`; frankly, I don't like it that much, but it's how the framework handles that use case; realistically, your options are to use what the framework provides (often a good idea) or to subclass/override the classes/functions it provides (which is also sometimes a good solution). Which works for you depends entirely on your specific circumstances. – kungphu Mar 03 '16 at 14:49
  • I've updated my question and divided it into two problems. Generally, the whole operation is simple: I just want to save form data to database (or file) and then create form from this data. It seems like common use-case but I have many troubles with this simple task, especially when form contains multi-value fields. – EMiDU Mar 03 '16 at 16:08

3 Answers3

6

You could use lists(). The format is compatible with the dict contructor.

post_data = dict(request.POST.lists())
Gert
  • 532
  • 12
  • 19
  • 4
    Yes, but then all `dict` values will be lists. Of course, I can use `{k: v[0] if len(v) == 1 else v for k, v in request.POST.lists()}` and it is answer to my question, however I thought it would be simpler. – EMiDU Mar 03 '16 at 10:10
  • 1
    The actual implementation of this functionality is the [MultiValueDict](https://github.com/django/django/blob/master/django/utils/datastructures.py#L48) – Gert Mar 03 '16 at 10:27
0

I believe that

json.dumps(query_dict)

might be what you are looking for. From JSON encoder and decoder

jaqHollow
  • 84
  • 5
  • 4
    Unfortunately `json.dumps(request.POST)` acts as `request.POST.dict()` and loses list values. – EMiDU Mar 03 '16 at 09:44
0

You have to add MultiValueDict along with QueryDict,

from django.http.request import QueryDict, MultiValueDict

dictionary = {'key_1': ['1'], 'key_2': ['1', '2'], }
query_dict = QueryDict('', mutable=True)
query_dict.update(MultiValueDict(dictionary))
Shinto Joseph
  • 2,809
  • 27
  • 25