J'ai un modèle 'MyModel' avec plusieurs champs et j'aimerais mettre à jour un champ 'status' en utilisant la méthode PATCH J'utilise des vues basées sur les classes. Est-il possible d'implémenter PATCH?
Les sérialiseurs autorisent les mises à jour partielles en spécifiant partial=True
lors de l'initialisation du série. C’est ainsi que les requêtes PATCH
sont traitées par défaut dans les vues génériques .
serializer = CommentSerializer(comment, data=request.data, partial=True)
Cela vous permettra de mettre à jour des champs individuels d'un sérialiseur, ou tous les champs si vous le souhaitez, sans aucune des restrictions d'une requête PUT
standard.
Comme Kevin Brown a déclaré que vous pouvez utiliser le partial=True
, qui chefarov a bien précisé.
Je voudrais juste les corriger et dire que vous pouvez utiliser les génériques librement, en fonction de la méthode HTTP que vous utilisez:
Si vous utilisez la méthode PATCH HTTP comme demandé, vous la récupérez. Vous pouvez voir le code UpdateModelMixin
pour partial_update
:
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
Pour toute méthode HTTP différente de PATCH, ceci peut être accompli en remplaçant simplement la méthode get_serializer
comme suit:
def get_serializer(self, *args, **kwargs):
kwargs['partial'] = True
return super(YOUR_CLASS, self).get_serializer(*args, **kwargs)
Cela va créer le sérialiseur comme partiel, et le reste des génériques fonctionnera comme un charme sans aucune intervention manuelle dans le mécanisme update/partial_update.
Sous la capuche
J'ai utilisé le générique: generics.UpdateAPIView
qui utilise la UpdateModelMixin
qui a ce code:
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)
…
Ainsi, si vous remplacez la fonction get_serializer
, vous pouvez en réalité remplacer l’argument partiel et le forcer à la valeur true.
Veuillez noter que si vous ne voulez utiliser que partiellement certaines méthodes HTTP, cela rend cette approche plus difficile.
J'utilise djangorestframework == 3.5.3
Il semble être pris en charge hors de la boîte. Dans l'API de votre navigateur, accédez à une page de détail du modèle. En bas de l'onglet HTML Form
, cliquez sur Raw data
, supprimez tout ce qui se trouve dans la chaîne JSON, à l'exception du champ ID et du champ que vous souhaitez modifier, puis cliquez sur PATCH
. Une mise à jour partielle PATCH
est effectuée.
J'utilise djangorestframework==3.2.4
et je n'ai rien à faire avec mes ViewSets et mes sérialiseurs pour l'activer.
Dans cet exemple, nous mettons à jour le champ bool status_field
du modèle et j’utilise jquery 2.2.1. Ajoutez ce qui suit au <head>
:
<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>
Puis dans un <form>
:
<input type="checkbox" id="status_field" {% if your_rendering_context.status_field %}
checked {% endif %} >
J'ai choisi de permettre à la case à cocher de changer, puis de la retourner en cas d'échec. Mais vous pouvez remplacer click
par mousedown
pour ne mettre à jour la valeur de case à cocher qu'une fois l'appel AJAX réussi. Je pense que cela incitera cependant les gens à cliquer plusieurs fois sur la case à cocher pour les connexions lentes.
Si quelqu'un envisage toujours de trouver une solution simple en utilisant ModelSerializer
sans modifier la plupart de vos points de vue, vous pouvez sous-classer ModelSerializer
et en faire hériter tous vos ModelSerializer
s.
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
J'ai eu du mal avec celui-ci pendant un moment, mais c'est une implémentation très simple qui utilise des vues génériques ou une combinaison de vues génériques et de mixins.
Si vous utilisez une vue de mise à jour générique (generics.UpdateAPIView), utilisez simplement le code suivant, en vous assurant que le type de demande est PATCH:
class UpdateUser(generics.UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
Il n'y a rien d'autre à cela!
Si vous utilisez un mix de mise à jour (mixins.UpdateModelMixin) associé à une vue générique (generics.GenericAPIView), utilisez le code suivant, en vous assurant que le type de demande est PATCH:
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)
Le deuxième exemple est plus complexe et montre comment remplacer le champ queryset et le champ de recherche, mais le code auquel vous devez faire attention est la fonction patch.