Gdzie są moje dane JSON w moim przychodzącym żądaniu Django?


162

Próbuję przetwarzać przychodzące żądania JSON / Ajax za pomocą Django / Python.

request.is_ajax()jest Truena żądanie, ale nie mam pojęcia, gdzie jest ładunek z danymi JSON.

request.POST.dir zawiera to:

['__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']

Najwyraźniej nie ma kluczy w kluczach pocztowych żądań.

Kiedy patrzę na POST w Firebug , w żądaniu wysyłane są dane JSON.


Co tak naprawdę publikujesz? Pokaż nam wywołanie javascript.
Daniel Roseman,

A len(request.POST)i request.POST.items()to też pomaga.
Vinay Sajip

Odpowiedzi:


233

Jeśli wysyłasz JSON do Django, myślę, że chcesz request.body( request.raw_post_datana Django <1.4). W ten sposób otrzymasz nieprzetworzone dane JSON wysłane pocztą. Stamtąd możesz go dalej przetwarzać.

Oto przykład wykorzystujący JavaScript, jQuery , jquery-json i 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")

Proszę wyjaśnić, co masz na myśli mówiąc „klient testowy”? Co próbujesz zrobić?
Jared Knipp

Nie próbuję być niegrzeczny: przez „klienta testowego” mam na myśli „klienta testowego” django. Jak testujesz widoki, jeśli nie z klientem testowym?
jMyles

4
Pamiętaj: adres URL powinien kończyć się ukośnikiem (/) char. Wyłącz również CSRF za pomocą @csrf_exempt
dani herrera

46
Uwaga: jeśli używasz wersji 1.4, będzie to nazywane request.body. raw_post_data jest przestarzała ...
prauchfuss

3
aby przetestować z django unittest, po prostu zróbself.client.post('/event/save-json/', json.dumps(python_dict), HTTP_X_REQUESTED_WITH='XMLHttpRequest', content_type="application/json")
Guillaume Vincent,

67

Miałem ten sam problem. Publikowałem złożoną odpowiedź JSON i nie mogłem odczytać moich danych za pomocą słownika request.POST.

Moje dane POST JSON to:

//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);

W takim przypadku musisz skorzystać z metody dostarczonej przez aurealus. Przeczytaj request.body i zdeserializuj go przy użyciu standardowego biblioteki json.

#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")

2
Mam problemy z czwartą linią: json_data = simplejson.loads(request.raw_post_data)czy na pewno to poprawnie określono?
wfbarksdale

Jestem całkiem pewien, że request.raw_post_data jest poprawną formą, ponieważ użyłem tego przykładu w testowaniu. Jakie masz problemy z @weezybizzle?
stricjux

1
Dane przychodzące w dodatkowym tekście również były dołączane, co zepsuło parsowanie. Więc to byłem w 100% ja.
wfbarksdale

4
django.utils.simplejsonzostał usunięty w ostatnich wersjach. Po prostu użyj jsonbiblioteki stdlib .
Martijn Pieters

Będziesz chciał użyć request.body zamiast request.raw_post_data dla Django 1.4+
mrooney

38

Metoda 1

Klient: wyślij jako 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}

Serwer :

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

Metoda 2

Klient: Wyślij jako x-www-form-urlencoded
(Uwaga: contentType& processDatazostały zmienione, JSON.stringifynie są potrzebne)

$.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

Serwer :

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

Zmieniono w wersji 1.5+: https://docs.djangoproject.com/en/dev/releases/1.5/#non-form-data-in-http-requests

Dane nieformalne w żądaniach HTTP :
request.POST nie będzie już zawierał danych wysyłanych za pośrednictwem żądań HTTP z typami treści niezwiązanymi z formularzami w nagłówku. We wcześniejszych wersjach dane publikowane z typami zawartości innymi niż multipart / form-data lub application / x-www-form-urlencoded nadal były reprezentowane w atrybucie request.POST. Deweloperzy, którzy chcą uzyskać dostęp do nieprzetworzonych danych POST w takich przypadkach, powinni zamiast tego użyć atrybutu request.body.

Prawdopodobnie powiązane


3
Ad 1 -django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
AlxVallejo

24

Należy pamiętać, że Python 3 inaczej przedstawia łańcuchy - są to tablice bajtowe.

Używając Django 1.9 i Python 2.7 i wysyłając dane JSON w głównej części (nie nagłówku), użyłbyś czegoś takiego:

mydata = json.loads(request.body)

Ale dla Django 1.9 i Python 3.4 użyłbyś:

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

Właśnie przeszedłem tę krzywą uczenia się, tworząc moją pierwszą aplikację Py3 Django!


3
Dziękuję za wyjaśnienie! Używam Django 1.10 i Python 3.5, mydata = json.loads (request.body.decode ("utf-8")) działa!
Julia Zhao


9

na django 1.6 python 3.3

klient

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

serwer

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")))

5

Ładunek HTTP POST to tylko płaska wiązka bajtów. Django (podobnie jak większość frameworków) dekoduje go do słownika z parametrów zakodowanych w adresie URL lub z kodowania wieloczęściowego MIME. Jeśli po prostu zrzucisz dane JSON w treści POST, Django ich nie zdekoduje. Albo wykonaj dekodowanie JSON z pełnej zawartości POST (nie ze słownika); lub umieść dane JSON w opakowaniu wieloczęściowym MIME.

Krótko mówiąc, pokaż kod JavaScript. Wydaje się, że problem istnieje.


Teraz widzę problem! Parametr type = 'json' w jquery odnosi się do tego, jakiego typu się spodziewać, a nie do tego, co wysyła. Wysyła zwykłe dane zakodowane pocztą, więc jeśli chcę wysłać „json”, muszę jakoś przekonwertować go na ciąg i przekazać „json = {foo: bar,}” itd. Nie mogę jednak uwierzyć, że to jak większość ludzi to robi. Coś tu chyba brakuje.

Właściwie możesz przekonwertować formularz na ciąg JSON w jQuery za pomocą funkcji .serialize (). Ale dlaczego musisz wysyłać json? Co jest złego w samym wysyłaniu danych formularza?
Daniel Roseman

4
Jest wiele przypadków, w których surowe dane formularzy nie wystarczą; JSON umożliwia wysyłanie obiektów hierarchicznych, a nie tylko par klucz: wartość. Możesz wysyłać zagnieżdżone zestawy, tablice itp. Prawdopodobnie możesz to wszystko zrobić z danymi pocztowymi, ale nie jest to tak wygodne. Miło jest po prostu zawsze zajmować się JSON, zarówno do, jak i od
taksówkarza

5

request.raw_post_datazostał wycofany. Użyj request.bodyzamiast tego


Dzięki za to! Działał doskonale.
Prometeusz

4

Coś takiego. Zadziałało: poproś o dane od klienta

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);
});

Przetwarzaj żądanie na serwerze

@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")

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))

-2

Używając Angulara, powinieneś dodać nagłówek do żądania lub dodać go do nagłówków konfiguracji modułu: {'Content-Type': 'application/x-www-form-urlencoded'}

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

-4

request.POST jest po prostu obiektem podobnym do słownika, więc po prostu zindeksuj go za pomocą składni dict.

Zakładając, że twoje pole formularza jest fred, możesz zrobić coś takiego:

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

Alternatywnie użyj obiektu formularza do obsługi danych POST.


Szukałem w request.POST ['json'], które nie zawierało nic. len było 0

Wtedy zdecydowanie pomogłoby zobaczyć wywołanie JavaScript, jak zasugerował Daniel.
Vinay Sajip

13
request.POST jest wypełniane tylko wtedy, gdy treść żądania POST jest zakodowana w formacie Form, w przeciwnym razie jest pusta.
slacy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.