Ich versuche, partial_update
mit Django Rest Framework zu implementieren, aber ich brauche einige Klarstellungen, weil ich nicht weiterkomme.
Warum müssen wir partiell = True angeben?
Nach meinem Verständnis könnten wir das Demo-Objekt innerhalb derpartial_update
Methode leicht aktualisieren . Was ist der Zweck davon?Was ist in der serialisierten Variablen enthalten?
Was steckt in derserialized
Variablen in derpartial_update
Methode? Ist das ein Demo-Objekt? Welche Funktion heißt hinter den Kulissen?- Wie würde man die Implementierung hier beenden?
Viewset
class DemoViewSet(viewsets.ModelViewSet):
serializer_class = DemoSerializer
def partial_update(self, request, pk=None):
serialized = DemoSerializer(request.user, data=request.data, partial=True)
return Response(status=status.HTTP_202_ACCEPTED)
Serializer
class DemoSerializer(serializers.ModelSerializer):
class Meta:
model = Demo
fields = '__all__'
def update(self, instance, validated_data):
print 'this - here'
demo = Demo.objects.get(pk=instance.id)
Demo.objects.filter(pk=instance.id)\
.update(**validated_data)
return demo
python
django
django-rest-framework
Intelis
quelle
quelle
Antworten:
Ich hatte die gleichen Fragen wie Sie zuvor, aber als ich mich mit dem Quellcode von rest_framework befasste, erhielt ich die folgenden Ergebnisse, hoffe, es hilft:
Zu Frage 1. Warum müssen wir partiell = True angeben?
Diese Frage bezieht sich auf HTTP-Verben .
PUT : Die PUT-Methode ersetzt alle aktuellen Darstellungen der Zielressource durch die Anforderungsnutzlast.
PATCH : Mit der PATCH-Methode werden teilweise Änderungen an einer Ressource vorgenommen.
Im Allgemeinen
partial
wird verwendet, um zu überprüfen, ob die Felder im Modell für die Feldvalidierung benötigt werden, wenn der Client Daten an die Ansicht sendet.Zum Beispiel haben wir ein
Book
Modell wie diese, pls Anmerkung beide diename
undauthor_name
Felder sind obligatorisch (nicht null & nicht leer).class Book(models.Model): name = models.CharField('name of the book', max_length=100) author_name = models.CharField('the name of the author', max_length=50) # Create a new instance for testing Book.objects.create(name='Python in a nut shell', author_name='Alex Martelli')
Bei einigen Szenarien können wir zu aktualisieren Teil der Felder in dem Modell nur benötigen, zB wir Update nur müssen
name
Feld in derBook
. In diesem Fall sendet der Client nur dasname
Feld mit dem neuen Wert an die Ansicht. Die vom Kunden übermittelten Daten können folgendermaßen aussehen:{"pk": 1, name: "PYTHON IN A NUT SHELL"}
Möglicherweise haben Sie jedoch bemerkt, dass unsere Modelldefinition nicht
author_name
leer sein darf. Also müssen wirpartial_update
statt verwendenupdate
. Das restliche Framework führt daher keine Feldvalidierungsprüfung für die Felder durch, die in den Anforderungsdaten fehlen.Zu Testzwecken können Sie zwei Ansichten für beide
update
und erstellenpartial_update
, und Sie werden besser verstehen, was ich gerade gesagt habe.Beispiel:
views.py
urls.pyfrom rest_framework.generics import GenericAPIView from rest_framework.mixins import UpdateModelMixin from rest_framework.viewsets import ModelViewSet from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = Book class BookUpdateView(GenericAPIView, UpdateModelMixin): ''' Book update API, need to submit both `name` and `author_name` fields At the same time, or django will prevent to do update for field missing ''' queryset = Book.objects.all() serializer_class = BookSerializer def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) class BookPartialUpdateView(GenericAPIView, UpdateModelMixin): ''' You just need to provide the field which is to be modified. ''' queryset = Book.objects.all() serializer_class = BookSerializer def put(self, request, *args, **kwargs): return self.partial_update(request, *args, **kwargs)
urlpatterns = patterns('', url(r'^book/update/(?P<pk>\d+)/$', BookUpdateView.as_view(), name='book_update'), url(r'^book/update-partial/(?P<pk>\d+)/$', BookPartialUpdateView.as_view(), name='book_partial_update'), )
Zu übermittelnde Daten
{"pk": 1, name: "PYTHON IN A NUT SHELL"}
Wenn Sie den obigen JSON an das
/book/update/1/
senden, wird der folgende Fehler mit HTTP_STATUS_CODE = 400 angezeigt:{ "author_name": [ "This field is required." ] }
Wenn Sie jedoch den obigen json an
/book/update-partial/1/
senden, erhalten Sie HTTP_STATUS_CODE = 200 mit der folgenden Antwort:{ "id": 1, "name": "PYTHON IN A NUT SHELL", "author_name": "Alex Martelli" }
Zu Frage 2. Was ist in der serialisierten Variablen enthalten?
serialized
ist ein Objekt, das die Modellinstanz als serialisierbares Objekt umschließt. und Sie können diese serialisierte verwenden, um eine einfache JSON-Zeichenfolge mit zu generierenserialized.data
.Zu Frage 3. Wie würde man die Implementierung hier beenden?
Ich denke, Sie können sich selbst antworten, wenn Sie die obige Antwort gelesen haben, und Sie sollten wissen, wann
update
und wann Sie sie verwenden müssenpartial_update
.Wenn Sie noch Fragen haben, können Sie diese gerne stellen. Ich habe gerade einen Teil der Quell-Oden des Ruhe-Frameworks gelesen und habe einige Begriffe möglicherweise nicht sehr gut verstanden. Bitte weisen Sie darauf hin, wenn es falsch ist ...
quelle
update_fields
Parameter? Es sollten nur die zu aktualisierenden Felder enthalten sein.Für teilweise Aktualisierung - PATCH http-Methode
Für die vollständige Aktualisierung - PUT http-Methode
Wenn Sie ein Update mit DRF durchführen, sollten Sie Anforderungsdaten senden, die Werte für alle (erforderlichen) Felder enthalten. Dies ist zumindest dann der Fall, wenn die Anforderung über die PUT-http-Methode erfolgt. Soweit ich weiß, möchten Sie ein oder zumindest nicht alle Modellinstanzfelder aktualisieren. In diesem Fall stellen Sie eine Anfrage mit der PATCH http-Methode. Das Django Rest Framework (DRF) kümmert sich sofort darum.
Beispiel (mit Token-Authentifizierung):
curl -i -X PATCH -d '{"name":"my favorite banana"}' -H "Content-Type: application/json" -H 'Authorization: Token <some token>' http://localhost:8000/bananas/
quelle
Nur eine kurze Anmerkung, da anscheinend noch niemand darauf hingewiesen hat:
serialized = DemoSerializer(request.user, data=request.data, partial=True)
Das erste Argument von DemoSerializer sollte eine Demo-Instanz sein, kein Benutzer (zumindest wenn Sie DRF 3.6.2 wie ich verwenden).
Ich weiß nicht, was Sie versuchen, aber dies ist ein funktionierendes Beispiel:
def partial_update(self, request, *args, **kwargs): response_with_updated_instance = super(DemoViewSet, self).partial_update(request, *args, **kwargs) Demo.objects.my_func(request.user, self.get_object()) return response_with_updated_instance
Ich mache die teilweise Aktualisierung und dann andere Dinge, die my_func aufrufen und den aktuellen Benutzer und die bereits aktualisierte Demo-Instanz übergeben.
Hoffe das hilft.
quelle
So einfach, überschreiben Sie einfach die Init- Methode Ihres Serializers wie folgt:
def __init__(self, *args, **kwargs): kwargs['partial'] = True super(DemoSerializer, self).__init__(*args, **kwargs)
quelle
Ich hatte ein Problem, bei dem meine Multi-Attribut- / Feldvalidierung in einem rest_framework-Serializer mit einem POST / resources / request arbeitete, aber mit einem PATCH / resources / request fehlschlug. Im PATCH-Fall ist dies fehlgeschlagen, da nur nach Werten im angegebenen Diktat gesucht wurde
attrs
und nicht auf Werte in zurückgegriffen wurdeself.instance
. Das Hinzufügen einer Methodeget_attr_or_default
, um diesen Fallback durchzuführen, scheint funktioniert zu haben:class EmailSerializer(serializers.ModelSerializer): def get_attr_or_default(self, attr, attrs, default=''): """Return the value of key ``attr`` in the dict ``attrs``; if that is not present, return the value of the attribute ``attr`` in ``self.instance``; otherwise return ``default``. """ return attrs.get(attr, getattr(self.instance, attr, '')) def validate(self, attrs): """Ensure that either a) there is a body or b) there is a valid template reference and template context. """ existing_body = self.get_attr_or_default('body', attrs).strip() if existing_body: return attrs template = self.get_attr_or_default('template', attrs) templatecontext = self.get_attr_or_default('templatecontext', attrs) if template and templatecontext: try: render_template(template.data, templatecontext) return attrs except TemplateRendererException as err: raise serializers.ValidationError(str(err)) raise serializers.ValidationError(NO_BODY_OR_TEMPLATE_ERROR_MSG)
quelle
Du hast vergessen
serializer.save()
Sie können es folgendermaßen beenden. . .
class DemoViewSet(viewsets.ModelViewSet): serializer_class = DemoSerializer def partial_update(self, request, pk=None): serializer = DemoSerializer(request.user, data=request.data, partial=True) serializer.save() serializer.is_valid(raise_exception=True) return Response(serializer.data)
Außerdem sollten Sie die Aktualisierungsmethode im Serializer nicht überschreiben müssen.
quelle