Où sont mes données JSON dans ma requête Django entrante?

162

J'essaie de traiter les demandes JSON / Ajax entrantes avec Django / Python.

request.is_ajax()est Truesur la demande, mais je n'ai aucune idée de l'emplacement de la charge utile avec les données JSON.

request.POST.dir contient ceci:

['__class__', '__cmp__', '__contains__', '__copy__', '__deepcopy__', '__delattr__',
 '__delitem__', '__dict__', '__doc__', '__eq__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__',
 '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__setitem__', '__str__', '__weakref__', '_assert_mutable', '_encoding', 
'_get_encoding', '_mutable', '_set_encoding', 'appendlist', 'clear', 'copy', 'encoding', 
'fromkeys', 'get', 'getlist', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 
'keys', 'lists', 'pop', 'popitem', 'setdefault', 'setlist', 'setlistdefault', 'update', 
'urlencode', 'values']

Il n'y a apparemment aucune clé dans les clés de message de demande.

Lorsque je regarde le POST dans Firebug , des données JSON sont envoyées dans la demande.

Flimm
la source
Que publiez-vous réellement? Montrez-nous l'appel javascript.
Daniel Roseman
Et len(request.POST)et request.POST.items()aiderait également.
Vinay Sajip

Réponses:

233

Si vous publiez du JSON sur Django, je pense que vous le souhaitez request.body( request.raw_post_datasur Django <1.4). Cela vous donnera les données JSON brutes envoyées via la poste. De là, vous pouvez le traiter davantage.

Voici un exemple utilisant JavaScript, jQuery , jquery-json et Django.

JavaScript:

var myEvent = {id: calEvent.id, start: calEvent.start, end: calEvent.end,
               allDay: calEvent.allDay };
$.ajax({
    url: '/event/save-json/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: $.toJSON(myEvent),
    dataType: 'text',
    success: function(result) {
        alert(result.Result);
    }
});

Django:

def save_events_json(request):
    if request.is_ajax():
        if request.method == 'POST':
            print 'Raw Data: "%s"' % request.body   
    return HttpResponse("OK")

Django <1.4:

  def save_events_json(request):
    if request.is_ajax():
        if request.method == 'POST':
            print 'Raw Data: "%s"' % request.raw_post_data
    return HttpResponse("OK")
Jared Knipp
la source
Veuillez expliquer ce que vous entendez par «client de test»? Qu'essayez-vous de faire?
Jared Knipp
Je n'essaye pas d'être impoli: par "client de test", je veux dire le "client de test" de Django. Comment tester les vues si ce n'est avec le client de test?
jMyles
4
Gardez à l'esprit: vous devez terminer l'URL par un caractère barre oblique (/). Désactivez également CSRF avec @csrf_exempt
dani herrera
46
NB si vous utilisez 1.4, cela s'appellera request.body. raw_post_data est obsolète ...
prauchfuss
3
tester avec django unittest just doself.client.post('/event/save-json/', json.dumps(python_dict), HTTP_X_REQUESTED_WITH='XMLHttpRequest', content_type="application/json")
Guillaume Vincent
68

J'ai eu le même problème. J'avais publié une réponse JSON complexe et je ne pouvais pas lire mes données à l'aide du dictionnaire request.POST.

Mes données JSON POST étaient:

//JavaScript code:
//Requires json2.js and jQuery.
var response = {data:[{"a":1, "b":2},{"a":2, "b":2}]}
json_response = JSON.stringify(response); // proper serialization method, read 
                                          // http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
$.post('url',json_response);

Dans ce cas, vous devez utiliser la méthode fournie par aurealus. Lisez le request.body et désérialisez-le avec le json stdlib.

#Django code:
import json
def save_data(request):
  if request.method == 'POST':
    json_data = json.loads(request.body) # request.raw_post_data w/ Django < 1.4
    try:
      data = json_data['data']
    except KeyError:
      HttpResponseServerError("Malformed data!")
    HttpResponse("Got json data")
stricjux
la source
2
J'ai des problèmes avec la 4ème ligne: json_data = simplejson.loads(request.raw_post_data)êtes-vous sûr que c'est correctement indiqué?
wfbarksdale
Je suis tout à fait sûr que request.raw_post_data est la forme correcte car j'ai utilisé cet exemple dans les tests. Quels types de problèmes rencontrez-vous @weezybizzle?
stricjux
1
Les données fournies dans un texte supplémentaire ont également ajouté ce qui gâchait l'analyse. C'était donc à 100% moi.
wfbarksdale
4
django.utils.simplejsona été supprimé dans les versions récentes. Utilisez simplement la jsonbibliothèque stdlib .
Martijn Pieters
Vous voudrez utiliser request.body au lieu de request.raw_post_data pour Django 1.4+
mrooney
38

Méthode 1

Client: envoyer en tant que JSON

$.ajax({
    url: 'example.com/ajax/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    processData: false,
    data: JSON.stringify({'name':'John', 'age': 42}),
    ...
});

//Sent as a JSON object {'name':'John', 'age': 42}

Serveur:

data = json.loads(request.body) # {'name':'John', 'age': 42}

Méthode 2

Client: Envoyer en tant que x-www-form-urlencoded
(Remarque: contentType& processDataont changé, JSON.stringifyn'est pas nécessaire)

$.ajax({
    url: 'example.com/ajax/',
    type: 'POST',    
    data: {'name':'John', 'age': 42},
    contentType: 'application/x-www-form-urlencoded; charset=utf-8',  //Default
    processData: true,       
});

//Sent as a query string name=John&age=42

Serveur:

data = request.POST # will be <QueryDict: {u'name':u'John', u'age': 42}>

Modifié dans la version 1.5+: https://docs.djangoproject.com/en/dev/releases/1.5/#non-form-data-in-http-requests

Données non formelles dans les requêtes HTTP :
request.POST n'inclura plus les données publiées via des requêtes HTTP avec des types de contenu non spécifiques au formulaire dans l'en-tête. Dans les versions précédentes, les données publiées avec des types de contenu autres que multipart / form-data ou application / x-www-form-urlencoded finiraient toujours par être représentées dans l'attribut request.POST. Les développeurs souhaitant accéder aux données POST brutes pour ces cas doivent utiliser à la place l'attribut request.body.

Probablement lié

utilisateur
la source
3
Re 1 -django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
AlxVallejo
24

Il est important de se rappeler que Python 3 a une manière différente de représenter les chaînes - ce sont des tableaux d'octets.

En utilisant Django 1.9 et Python 2.7 et en envoyant les données JSON dans le corps principal (pas un en-tête), vous utiliseriez quelque chose comme:

mydata = json.loads(request.body)

Mais pour Django 1.9 et Python 3.4, vous utiliseriez:

mydata = json.loads(request.body.decode("utf-8"))

Je viens de passer par cette courbe d'apprentissage en créant ma première application Py3 Django!

Richard Cooke
la source
3
Merci pour ton explication! J'utilise Django 1.10 et Python 3.5, mydata = json.loads (request.body.decode ("utf-8")) fonctionne!
Julia Zhao
23

request.raw_responseest désormais obsolète. Utilisationrequest.body plutôt pour traiter des données de formulaire non conventionnelles telles que des charges utiles XML, des images binaires, etc.

Documentation Django sur le problème .

Kevin S Lin
la source
9

sur django 1.6 python 3.3

client

$.ajax({
    url: '/urll/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify(json_object),
    dataType: 'json',
    success: function(result) {
        alert(result.Result);
    }
});

serveur

def urll(request):

if request.is_ajax():
    if request.method == 'POST':
        print ('Raw Data:', request.body) 

        print ('type(request.body):', type(request.body)) # this type is bytes

        print(json.loads(request.body.decode("utf-8")))
Canard en caoutchouc
la source
5

La charge utile HTTP POST est juste un ensemble plat d'octets. Django (comme la plupart des frameworks) le décode dans un dictionnaire à partir de paramètres encodés en URL ou d'un encodage MIME-multipart. Si vous videz simplement les données JSON dans le contenu POST, Django ne les décodera pas. Soit faites le décodage JSON à partir du contenu POST complet (pas du dictionnaire); ou placez les données JSON dans un wrapper MIME en plusieurs parties.

En bref, montrez le code JavaScript. Le problème semble être là.

Javier
la source
Je vois le problème maintenant! Le paramètre type = 'json' dans jquery fait référence au type à attendre, pas à ce qu'il envoie. Il envoie des données post codées sous forme régulière, donc si je veux envoyer "json", je dois en quelque sorte le convertir en une chaîne, et passer "json = {foo: bar,}" etc Je ne peux pas croire, cependant, que c'est comment la plupart des gens le font. Je dois manquer quelque chose ici.
En fait, vous pouvez convertir le formulaire en une chaîne JSON dans jQuery avec la fonction .serialize (). Mais pourquoi avez-vous particulièrement besoin d'envoyer json? Quel est le problème avec l'envoi des données du formulaire?
Daniel Roseman
4
Il existe de nombreux cas où les données sous forme brute ne suffisent pas; JSON vous permet d'envoyer des objets hiérarchiques, pas seulement des paires clé: valeur. Vous pouvez envoyer des ensembles imbriqués, des tableaux, etc. Vous pourriez probablement faire tout cela avec des données de publication, mais ce n'est pas aussi pratique. C'est plutôt agréable de toujours traiter avec JSON, à la fois vers et depuis
taxilian
5

request.raw_post_dataest obsolète. Utilisez request.bodyplutôt

Andrés
la source
Merci pour cela! A parfaitement fonctionné.
Prometheus le
4

Quelque chose comme ça. Cela a fonctionné: demander des données au client

registerData = {
{% for field in userFields%}
  {{ field.name }}: {{ field.name }},
{% endfor %}
}


var request = $.ajax({
   url: "{% url 'MainApp:rq-create-account-json' %}",
   method: "POST",
   async: false,
   contentType: "application/json; charset=utf-8",
   data: JSON.stringify(registerData),
   dataType: "json"
});

request.done(function (msg) {
   [alert(msg);]
   alert(msg.name);
});

request.fail(function (jqXHR, status) {
  alert(status);
});

Traiter la demande sur le serveur

@csrf_exempt
def rq_create_account_json(request):
   if request.is_ajax():
       if request.method == 'POST':
           json_data = json.loads(request.body)
           print(json_data)
           return JsonResponse(json_data)
   return HttpResponse("Error")
Nghia Tu
la source
2
html code 

file name  : view.html


    <!DOCTYPE html>
    <html>
    <head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script>
    $(document).ready(function(){
        $("#mySelect").change(function(){
            selected = $("#mySelect option:selected").text()
            $.ajax({
                type: 'POST',
                dataType: 'json',
                contentType: 'application/json; charset=utf-8',
                url: '/view/',
                data: {
                       'fruit': selected
                      },
                success: function(result) {
                        document.write(result)
                        }
        });
      });
    });
    </script>
    </head>
    <body>

    <form>
        <br>
    Select your favorite fruit:
    <select id="mySelect">
      <option value="apple" selected >Select fruit</option>
      <option value="apple">Apple</option>
      <option value="orange">Orange</option>
      <option value="pineapple">Pineapple</option>
      <option value="banana">Banana</option>
    </select>
    </form>
    </body>
    </html>

Django code:


Inside views.py


def view(request):

    if request.method == 'POST':
        print request.body
        data = request.body
        return HttpResponse(json.dumps(data))
Rajan Mandanka
la source
-2

En utilisant Angular, vous devez ajouter un en-tête à la demande ou l'ajouter aux en-têtes de configuration du module: {'Content-Type': 'application/x-www-form-urlencoded'}

$http({
    url: url,
    method: method,
    timeout: timeout,
    data: data,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
Mikalai Naunyka
la source
-4

request.POST est juste un objet de type dictionnaire, il suffit donc de l'indexer avec la syntaxe dict.

En supposant que votre champ de formulaire est fred, vous pouvez faire quelque chose comme ceci:

if 'fred' in request.POST:
    mydata = request.POST['fred']

Vous pouvez également utiliser un objet de formulaire pour traiter les données POST.

Michael van der Westhuizen
la source
Je cherchais dans request.POST ['json'] qui ne contenait rien. len était de 0
Ensuite, il serait certainement utile de voir votre appel JavaScript, comme l'a suggéré Daniel.
Vinay Sajip
13
request.POST n'est renseigné que lorsque le corps de la requête POST est codé par formulaire, sinon il est vide.
slacy