2013-07-06 6 views
42

Würde mich freuen, wenn jemand mir zeigt, wie man eine einfache POST-Anfrage mit JSON mit Django-REST-Framework macht. Ich sehe nirgends Beispiele im Tutorial?Wie mache ich einen einfachen POST JSON mit Django REST Framework? CSRF-Token fehlt oder ist falsch

Hier ist mein Vorbild-Objekt, das ich gerne POST würde. Dies ist eine brandneue Rolle, die ich der Datenbank hinzufügen möchte, aber ich bekomme einen Fehler von 500.

{ 
    "name": "Manager", 
    "description": "someone who manages" 
} 

Hier ist meine curl Anfrage an einer Eingabeaufforderung bash Terminal:

curl -X POST -H "Content-Type: application/json" -d '[ 
{ 
    "name": "Manager", 
    "description": "someone who manages" 
}]' 


http://localhost:8000/lakesShoreProperties/role 

Die URL

http://localhost:8000/lakesShoreProperties/roles 

DOES mit einer GET-Anforderung arbeiten, und ich kann in alle Rollen nach unten ziehen die Datenbank, aber ich kann anscheinend keine neuen Rollen erstellen. Ich habe keine Berechtigungen festgelegt. Ich verwende eine Standardansicht in views.py

class RoleDetail(generics.RetrieveUpdateDestroyAPIView): 
    queryset = Role.objects.all() 
    serializer_class = RoleSerializer 
    format = None 

class RoleList(generics.ListCreateAPIView): 
     queryset = Role.objects.all() 
     serializer_class = RoleSerializer 
     format = None 

Und in meinen urls.py für diese App, die entsprechenden URL - Ansicht Zuordnungen korrekt sind:

url(r'^roles/$', views.RoleList.as_view()), 
url(r'^role/(?P<pk>[0-9]+)/$', views.RoleDetail.as_view()), 

Fehlermeldung ist:

{ 
    "detail": "CSRF Failed: CSRF token missing or incorrect." 
} 

Was ist hier los und was ist die Lösung dafür? Ist localhost eine Cross-Site-Anfrage? Ich habe @csrf_exempt zu RoleDetail und RoleList hinzugefügt, aber es scheint nichts zu ändern. Kann dieser Decorator sogar zu einer Klasse hinzugefügt werden, oder muss er zu einer Methode hinzugefügt werden? Hinzufügen des @csrf_exempt verzieren, mein Fehler wird:

Request Method: POST 
Request URL: http://127.0.0.1:8000/lakeshoreProperties/roles/ 
Django Version: 1.5.1 
Exception Type: AttributeError 
Exception Value:  
'function' object has no attribute 'as_view' 

Dann habe ich deaktiviert CSRF through die gesamte app, und ich erhalte jetzt diese Meldung:

{ "non_field_errors": [ "Ungültige Daten"]}, wenn mein JSON-Objekt, das ich kenne, ist gültig json. Es ist ein Nicht-Feldfehler, aber ich stecke genau hier fest.

Nun, es stellt sich heraus, dass mein JSON nicht gültig war?

{ 
    "name": "admin", 
    "description": "someone who administrates" 
} 

vs

[ 
    { 
     "name": "admin", 
     "description": "someone who administrates" 
    } 
] 

die umschließenden Klammern Mit [] bewirkt, dass die POST-Anforderung fehlschlägt. Aber mit dem Jsonlint.com-Validator validieren beide JSON-Objekte.

Update: Das Problem war mit dem Senden des POST mit PostMan, nicht im Backend. Siehe https://stackoverflow.com/a/17508420/203312

+0

Ist 'RoleSerializer' etwas, das Sie definiert haben? Vielleicht lohnt es sich, einen Blick darauf zu werfen. – stellarchariot

Antwort

9

Sie müssen wahrscheinlich das CSRF-Token mit Ihrer Anfrage senden. Check out https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax

Update: Da Sie bereits versucht haben CSRF befreit, vielleicht könnte dies dazu beitragen, (je nachdem, welche Version von Django Sie verwenden): https://stackoverflow.com/a/14379073/977931

+0

Danke. Es sieht so aus, als wäre CSRF nur ein Haufen Schmerz für meine Zwecke. Das Deaktivieren macht jetzt meine POST-Anfrage gut. Ich möchte CSRF aktiviert halten, aber es spielt nicht gut mit Django REST Framework. – user798719

+0

Der Link zu den Django-Dokumenten wurde aktualisiert. – Duncan

+0

Letzter Link ist https://docs.djangoproject.com/en/dev/ref/csrf/#ajax – Wtower

10

OK, gut jetzt natürlich nehme ich zurück, was Ich sagte. CSRF funktioniert wie vorgesehen.

Ich machte eine POST-Anfrage mit einem Chrome-Plugin namens POSTMAN. Meine POST-Anfrage schlägt fehl, wenn CSRF aktiviert ist.

Aber eine Locke POST-Anfrage mit

curl -X POST -H "Content-Type: application/json" -d ' 
{ 
    "name": "Manager", 
    "description": "someone who manages" 
}' http://127.0.0.1:8000/lakeshoreProperties/roles/ 

funktioniert gut ... Ich hatte die Klammern zu entfernen, das heißt, [], und stellen Sie sicher, es gibt einen Schrägstrich nach dem ‚s‘ in Rollen , dh Rollen/und csrf aktiviert hat keine Fehler ausgelöst.

Ich bin nicht sicher, was der Unterschied zwischen dem Anrufen mit POSTMAN vs curl ist, aber POSTMAN wird im Webbrowser ausgeführt, was der größte Unterschied ist. Das heißt, ich habe csrf für die gesamte Klassen-RoleList deaktiviert, aber eine identische Anfrage funktioniert mit Curl, scheitert jedoch mit POSTMAN.

33

CSRF ist standardmäßig in Django REST Framework ausgenommen. Daher funktioniert die POST-Anforderung "curl" einwandfrei. POSTMAN-Anforderungsaufruf hat CSRF inkorrekt zurückgegeben, da POSTMAN das csrf-Token enthalten hat, wenn es in Cookies gefunden wird. Sie können dies lösen, indem Sie Cookies löschen.

+1

Danke für diesen Postman Kommentar! Es waren total Cookies, die das für mich verursachten :) – Gezim

3

Wie Sie gesagt haben Ihre URL war

http://localhost:8000/lakesShoreProperties/roles

Postman hat einige Probleme mit localhost. Das Senden des POST an 127.0.0.1:8000/your-api/endpoint tat stattdessen den Trick für mich.

25

Es stammt aus Ihren REST Framework-Einstellungen. in Ihrer Datei sollte Ihr REST_FRAMEWORK folgendes haben.

REST_FRAMEWORK = { 
    'DEFAULT_AUTHENTICATION_CLASSES': (
     'rest_framework.authentication.TokenAuthentication', 
    ), 
    'DEFAULT_PERMISSION_CLASSES': (
     'rest_framework.permissions.AllowAny', 
    ), 
} 

Dadurch wird in Ihrem REST Framework die Token-Authentifizierung anstelle der csrf-Authentifizierung verwendet. Und indem Sie die Berechtigung auf AllowAny festlegen, können Sie nur dort authentifizieren, wo Sie möchten.

+0

Das löste mein Problem auch. Ich habe 'rest_framework.permissions.IsAuthenticated' anstelle von' AllowAny' verwendet und es funktioniert gut. – wcyn

1

die alte Postman hat ein Problem mit csrf Token, weil es nicht mit Cookies funktioniert.

Ich schlage vor, dass Sie auf die neue Version von postman umstellen, es funktioniert mit Cookies und Sie werden dieses Problem nicht wieder haben.

0

wenn Sie AllowAny Erlaubnis eingestellt haben und Sie konfrontieren mit csrf Ausgabe

REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': [ 
     'rest_framework.permissions.AllowAny' 
    ] 
} 

dann folgende Platzierung in den settings.py wird das Problem

REST_SESSION_LOGIN = False 
4

lösen, um ein Update zu aktuellem Status zu geben, und die Summe ein paar Antworten:

AJAX-Anforderungen, die innerhalb der s erfolgen Ein Kontext als die API, mit der sie interagieren, verwendet typischerweise SessionAuthentication. Dies stellt sicher, dass nach der Anmeldung eines Benutzers alle vorgenommenen AJAX-Anforderungen mit derselben sessionbasierten Authentifizierung authentifiziert werden können, die für den Rest der Website verwendet wird.

AJAX Anfragen, die auf einer anderen Seite von der API gemacht werden sie mit in der Regel kommunizieren müssen ein nicht-sitzungsbasierte Authentifizierungsschema, wie TokenAuthentication verwenden.

Daher Antworten Empfehlung ersetzen SessionAuthentication mit TokenAuthentication das Problem lösen kann, aber nicht unbedingt völlig korrekt.

Um diese Art von Angriffen vorzubeugen, müssen Sie zwei Dinge tun:

  1. Stellen Sie sicher, dass die ‚sichere‘ HTTP-Operationen, wie GET, HEAD und OPTIONS nicht zu verändern, verwendet werden können, Server-seitiger Zustand.

  2. Stellen Sie sicher, dass alle 'unsicher' HTTP-Operationen, wie POST, PUT, PATCH und DELETE, erfordern immer eine gültige CSRF-Token. Wenn Sie SessionAuthentication verwenden, müssen Sie gültige CSRF-Tokens für alle POST, PUT, PATCH oder DELETE Operationen einschließen.

Um AJAX-Anforderungen zu machen, müssen Sie CSRF-Token im HTTP-Header, enthalten wie in der Dokumentation Django beschrieben.

Daher ist es wichtig, dass csrf im Header enthalten ist, wie zum Beispiel this answer schlägt vor.

Referenz: Working with AJAX, CSRF & CORS, Django REST framework documentation.

3

Sie können auch die CSRF deaktivieren Sie Ihre eigene Middleware zu machen:

class DisableCSRF(object): 
    def process_request(self, request): 
     setattr(request, '_dont_enforce_csrf_checks', True) 

und nimmt diese Middleware in Ihrem settings.py Datei in MIDDLEWARE_CLASSES.