wake-up-neo.com

Wie kann man mit Django Rest Framework ein einzelnes Feld PATCHIEREN?

Ich habe ein Modell 'MyModel' mit vielen Feldern und möchte ein Feld 'Status' mit der Methode PATCH aktualisieren. Ich verwende klassenbasierte Ansichten. Gibt es eine Möglichkeit, PATCH zu implementieren? 

31
pnhegde

Serialisierer erlauben Teilaktualisierungen durch Angabe von partial=True beim Initialisieren des Serialzers. So werden PATCH-Anforderungen behandelt standardmäßig in den generischen Ansichten .

serializer = CommentSerializer(comment, data=request.data, partial=True)

Auf diese Weise können Sie einzelne Felder in einem Serialisierer oder, falls gewünscht, alle Felder aktualisieren, ohne die Einschränkungen einer Standardanforderung PUT.

28
Kevin Brown

Wie Kevin Brown Sie angegeben haben, können Sie den partial=True verwenden, der chefarov schön klärt.

Ich möchte sie nur korrigieren und sagen, dass Sie Generics je nach verwendeter HTTP-Methode frei verwenden könnten:

  • Wenn Sie die PATCH-HTTP-Methode wie gewünscht verwenden, erhalten Sie sie aus der Box. Sie können UpdateModelMixin-Code für partial_update sehen:

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)
    
  • Für jede HTTP-Methode, die sich von PATCH unterscheidet, kann dies durch einfaches Überschreiben der get_serializer-Methode wie folgt erreicht werden:

    def get_serializer(self, *args, **kwargs):
        kwargs['partial'] = True
        return super(YOUR_CLASS, self).get_serializer(*args, **kwargs)
    

Dadurch wird der Serialisierer als unvollständig erstellt, und der Rest der Generika funktioniert wie ein Zauber, ohne dass der Mechanismus update/partial_update manuell eingreifen muss.

Unter der Haube

Ich habe das generische verwendet: generics.UpdateAPIView, das die UpdateModelMixin verwendet, die diesen Code hat:

def update(self, request, *args, **kwargs):
    partial = kwargs.pop('partial', False)
    instance = self.get_object()
    serializer = self.get_serializer(instance, data=request.data, partial=partial)
    …

Wenn Sie also die get_serializer-Funktion überschreiben, können Sie das partielle Argument tatsächlich überschreiben und erzwingen, dass es wahr ist.

Bitte beachten Sie, dass dieser Ansatz schwieriger wird, wenn Sie ihn nur für einige der HTTP-Methoden verwenden möchten.

Ich verwende djangorestframework == 3.5.3

12
Uri Shalit

Es scheint aus dem Kasten heraus unterstützt zu werden. Navigieren Sie in Ihrer Browser-API zu einer Modelldetailseite. Klicken Sie unten neben der Registerkarte HTML Form auf Raw data, löschen Sie alles aus der JSON-Zeichenfolge außer dem ID-Feld und dem Feld, das Sie ändern möchten, und klicken Sie auf PATCH. Eine teilweise PATCH-Aktualisierung wird durchgeführt.

Ich verwende djangorestframework==3.2.4 und musste meine ViewSets und Serializer nicht aktivieren, um dies zu ermöglichen.

In diesem Beispiel aktualisieren wir das bool status_field-Feld des Modells, und ich verwende Jquery 2.2.1. Fügen Sie dem <head> Folgendes hinzu:

<script src="{% static 'my_app/jquery.min.js' %}"></script>
<script>
$(document).ready(function(){
    var chk_status_field = $('#status_field');
    chk_status_field.click(function(){
        $.ajax({url: "{% url 'model-detail' your_rendering_context.id %}",
            type: 'PATCH', timeout: 3000, data: { status_field: this.checked }
        })
        .fail(function(){
            alert('Error updating this model instance.');
            chk_status_field.prop('checked', !chk_status_field.prop('checked'));
        });
    });
});
</script>

Dann in einem <form>:

<input type="checkbox" id="status_field" {% if your_rendering_context.status_field %} 
    checked {% endif %} >

Ich habe mich dazu entschieden, das Kontrollkästchen zu ändern, und es im Fehlerfall wieder herzustellen. Sie können jedoch click durch mousedown ersetzen, um den Wert des Kontrollkästchens erst zu aktualisieren, wenn der Aufruf von AJAX erfolgreich war. Ich denke, dass dies dazu führen wird, dass die Leute das Kontrollkästchen für langsame Verbindungen wiederholt anklicken.

5
Chris

Wenn noch jemand eine einfache Lösung mit ModelSerializer suchen möchte, ohne einen Großteil Ihrer Ansichten zu ändern, können Sie die ModelSerializer subclassieren und alle Ihre ModelSerializers davon erben.

class PatchModelSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        kwargs['partial'] = True
        super(PatchModelSerializer, self).__init__(*args, **kwargs)

class ArticleSerializer(PatchModelSerializer):
    class Meta:
        model = Article
3
firecast

Ich habe eine Weile mit diesem gekämpft, aber es ist eine sehr unkomplizierte Implementierung mit generischen Ansichten oder einer Kombination aus generischen Ansichten und Mixins.

Wenn Sie eine generische Aktualisierungsansicht (generics.UpdateAPIView) verwenden, verwenden Sie einfach den folgenden Code, um sicherzustellen, dass der Anfragetyp PATCH lautet:

class UpdateUser(generics.UpdateAPIView):

    queryset = User.objects.all()
    serializer_class = UserSerializer

Da ist nichts anderes dran!

Wenn Sie ein Update-Mixin (mixins.UpdateModelMixin) in Kombination mit einer generischen Ansicht (generics.GenericAPIView) verwenden, verwenden Sie den folgenden Code, um sicherzustellen, dass der Anfragetyp PATCH lautet:

class ActivateUser(mixins.UpdateModelMixin, generics.GenericAPIView):

    serializer_class = UserSerializer
    model = User
    lookup_field = 'email'

    def get_queryset(self):
        queryset = self.model.objects.filter(active=False)
        return queryset

    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

Das zweite Beispiel ist komplexer und zeigt Ihnen, wie Sie das Queryset- und das Lookup-Feld überschreiben. Der Code, den Sie jedoch beachten sollten, ist die Patch-Funktion.

0
user2583728