78 votes

Django Repos Cadre de la mise à jour partielle

Je suis en train de mettre en oeuvre partial_update avec Django Reste du Cadre , mais j'ai besoin de quelques précisions car je suis bloqué.

  1. Pourquoi avons-nous besoin de préciser partielle=True?
    Dans ma compréhension, nous avons pu facilement mettre à jour la Démo de l'objet à l'intérieur de l' partial_update méthode. Quel est le but de tout cela?

  2. Ce qui est à l'intérieur de sérialisé variable?
    Ce qui est à l'intérieur de l' serialized variable partial_update méthode? C'est qu'une Démo objet? Quelle fonction est appelée en coulisses?

  3. Comment pourrait-on terminer la mise en œuvre ici?

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)

Sérialiseur

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

125voto

Enix Points 1993

J'ai les mêmes questions que le vôtre avant, mais quand j'ai creuser dans le code source de rest_framework, j'ai obtenu les résultats suivants, espérons que cela permettrait de:

Pour la question 1)

Cette question est liée à des verbes HTTP.

METTRE: La méthode PUT remplace toutes les représentations actuelles de la ressource cible, à la demande de la charge utile.

PATCH: Le PATCH méthode est utilisée pour appliquer des modifications partielles à une ressource.

Généralement parlant, partial est utilisé pour vérifier si les champs du modèle est nécessaire pour la validation de champ lorsque le client de la soumission des données à la vue.

Par exemple, nous avons un Book modèle comme celui-là, pls note à la fois de l' name et author_name champs sont obligatoires (pas de valeur nulle et non vide).

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

Pour certains cas, Nous pouvons seulement besoin de mettre à jour une partie des champs dans le modèle, par exemple, nous avons seulement besoin de mettre à jour name champ dans l' Book. Donc, pour ce cas, le client ne soumettre l' name domaine avec une nouvelle valeur à la vue. Les données de soumettre le client peut ressembler à ceci:

{"pk": 1, name: "PYTHON IN A NUT SHELL"}

Mais vous pouvez avoir d'avis que notre définition du modèle ne permet pas l' author_name à être vide. Donc, il faut utiliser partial_update au lieu de update. Donc, le reste du cadre ne sera pas effectuer la validation des champs de case pour les champs qui manque dans les données de la demande.

Pour fins de test, vous pouvez créer deux points de vue pour les deux update et partial_update, et vous obtiendrez une plus grande compréhension de ce que je viens de dire.

Exemple:

views.py
from 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)
urls.py
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'),
)

Données à soumettre

{"pk": 1, name: "PYTHON IN A NUT SHELL"}

Lorsque vous envoyez le au-dessus de json à l' /book/update/1/, vous aurez obtenu l'erreur suivante avec HTTP_STATUS_CODE=400:

{
  "author_name": [
    "This field is required."
  ]
}

Mais quand vous soumettre ci-dessus json d' /book/update-partial/1/, vous aurez obtenu HTTP_STATUS_CODE=200 avec la réponse suivante,

{
  "id": 1,
  "name": "PYTHON IN A NUT SHELL",
  "author_name": "Alex Martelli"
}

Pour la question 2)

serialized est un objet encapsulant l'instance du modèle comme un serialisable objet. et vous pouvez utiliser cette sérialisé pour générer une plaine chaîne JSON avec serialized.data .

Pour la question 3)

Je pense que vous pouvez répondre vous-même lorsque vous avez lu la réponse ci-dessus, et vous devriez savoir quand utiliser update et quand utilisé partial_update.

Si vous avez encore des question, n'hésitez pas à demander. Je viens de lire une partie de la source des odes de repos cadre, et peut-être pas comprendre très profondément pour certains termes, et merci de nous le signaler quand c'est mal...

41voto

Gooshan Points 59

Pour la mise à jour partielle - PATCH méthode http

Pour la mise à jour complète - MIS méthode http

Lorsque vous faites une mise à jour avec DRF, vous êtes censé envoyer la demande de données qui inclut des valeurs pour tous (obligatoire) des champs. C'est du moins le cas lorsque la demande se fait via le MIS méthode http. Ce que je comprends, vous voulez mettre à jour un ou au moins pas tous instance du modèle de champs. Dans ce cas, faire une demande avec le PATCH méthode http. Django rest framework (DRF) prendra en charge hors de la boîte.

Exemple (avec un jeton d'authentification):

curl -i -X PATCH -d '{"name":"my favorite banana"}' -H "Content-Type: application/json" -H 'Authorization: Token <some token>'  http://localhost:8000/bananas/

5voto

Juste une petite remarque car il semble que personne ne l'a déjà fait remarquer ceci:

serialized = DemoSerializer(request.user, data=request.data, partial=True)

Le premier argument de DemoSerializer devrait être une Démo exemple, un utilisateur (au moins si vous utilisez des DRF 3.6.2 comme moi).

Je ne sais pas ce que vous essayez de faire, mais c'est un exemple de travail:

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

Je fais la mise à jour partielle puis-je faire d'autres choses appelant my_func et en passant de l'utilisateur actuel et la démo exemple déjà mis à jour.

Espérons que cette aide.

0voto

jrwdunham Points 23

J'ai eu un problème où mon multi-attribut/validation sur le terrain dans un rest_framework sérialiseur a été de travailler avec un POST /ressources/ demande, mais à défaut avec un PATCH /ressources/ demande. Il a échoué dans le PATCH cas parce que c'était seulement à la recherche de valeurs dans la attrs dict et pas de revenir à des valeurs en self.instance. Ajout d'une méthode get_attr_or_default faire de secours semble avoir fonctionné:

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)

-5voto

Jam Risser Points 601

Vous avez oublié serializer.save()

Vous pouvez terminer la manière suivante . . .

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)

Aussi, vous ne devriez pas besoin de surcharger la méthode de mise à jour dans le sérialiseur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X