{"id":5890,"date":"2022-04-03T13:16:12","date_gmt":"2022-04-03T05:16:12","guid":{"rendered":"https:\/\/egonlin.com\/?p=5890"},"modified":"2022-04-03T13:16:12","modified_gmt":"2022-04-03T05:16:12","slug":"03-03-listmodelserializer%e7%bb%84%e4%bb%b6","status":"publish","type":"post","link":"https:\/\/egonlin.com\/?p=5890","title":{"rendered":"03-03 ListModelSerializer\u7ec4\u4ef6"},"content":{"rendered":"<h1>ListModelSerializer\u6a21\u5757<\/h1>\n<h2>\u81ea\u5b9a\u4e49\u53cd\u5e8f\u5217\u5316\u5b57\u6bb5<\/h2>\n<pre><code class=\"language-python\"># \u4e00\u4e9b\u53ea\u53c2\u4e0e\u53cd\u5e8f\u5217\u5316\u7684\u5b57\u6bb5\uff0c\u4f46\u662f\u4e0d\u662f\u4e0e\u6570\u636e\u5e93\u5173\u8054\u7684\n# \u5728\u5e8f\u5217\u5316\u7c7b\u4e2d\u89c4\u5b9a\uff0c\u5e76\u5728\u6821\u9a8c\u5b57\u6bb5\u65f6\u4ece\u6821\u9a8c\u7684\u53c2\u6570\u5b57\u5178\u4e2d\u5254\u9664\nclass PublishModelSerializer(serializers.ModelSerializer):\n    # \u81ea\u5b9a\u4e49\u4e0d\u5165\u5e93\u7684 \u53cd\u5e8f\u5217\u5316 \u5b57\u6bb5\n    re_name = serializers.CharField(write_only=True)\n    class Meta:\n        model = models.Publish\n        fields = (&#039;name&#039;, &#039;re_name&#039;, &#039;address&#039;)\n    def validate(self, attrs):\n        name = attrs.get(&#039;name&#039;)\n        re_name = attrs.pop(&#039;re_name&#039;)  # \u5254\u9664\n        if name != re_name:\n            raise serializers.ValidationError({&#039;re_name&#039;: &#039;\u786e\u8ba4\u540d\u5b57\u6709\u8bef&#039;})\n        return attrs<\/code><\/pre>\n<h2>2\u3001\u6a21\u578b\u7c7b\u4e2d\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u6df1\u5ea6<\/h2>\n<pre><code class=\"language-python\"># model\u7c7b\u4e2d\u81ea\u5b9a\u4e49\u63d2\u62d4\u7684\u5916\u952e\u5e8f\u5217\u5316\u5b57\u6bb5\uff0c\u53ef\u4ee5\u91c7\u7528\u5916\u952e\u5173\u8054\u8868\u7684\u5e8f\u5217\u5316\u7c7b\u6765\u5b8c\u6210\u6df1\u5ea6\u67e5\u8be2\nclass Book(BaseModel):\n    # ...\n    @property\n    def publish_detail(self):\n        from . import serializers\n        data = serializers.PublishModelSerializer(self.publish).data\n        return data<\/code><\/pre>\n<h2>3\u3001\u63a5\u53e3\u64cd\u4f5c\u603b\u7ed3<\/h2>\n<pre><code class=\"language-python\"># \u5355\u67e5\u7fa4\u67e5\u3001\u5355\u5220\u7fa4\u5220\u3001\u5355\u589e\u7fa4\u589e\u3001\u5355\u6539\u7fa4\u6539<\/code><\/pre>\n<h5>\u8def\u7531\u5c42\uff1aapi\/url.py<\/h5>\n<pre><code class=\"language-python\">from django.conf.urls import url\nfrom . import views\nurlpatterns = [\n    # ...\n    url(r&#039;^v3\/books\/$&#039;, views.BookV3APIView.as_view()),\n    url(r&#039;^v3\/books\/(?P&lt;pk&gt;.*)\/$&#039;, views.BookV3APIView.as_view()),\n]<\/code><\/pre>\n<h5>\u6a21\u578b\u5c42\uff1aapi\/models.py<\/h5>\n<pre><code class=\"language-python\"># \u4fee\u6539\u90e8\u5206\uff1a\u53d6\u6d88book\u7c7b name \u4e0e publish \u8054\u5408\u552f\u4e00\uff0c\nfrom django.db import models\nfrom utils.model import BaseModel\nclass Book(BaseModel):\n    name = models.CharField(max_length=64)\n    price = models.DecimalField(max_digits=5, decimal_places=2)\n    img = models.ImageField(upload_to=&#039;img&#039;, default=&#039;img\/default.png&#039;)\n    publish = models.ForeignKey(to=&#039;Publish&#039;, null=True,\n                                related_name=&#039;books&#039;,\n                                db_constraint=False,\n                                on_delete=models.DO_NOTHING,\n                                )\n    authors = models.ManyToManyField(to=&#039;Author&#039;, null=True,\n                                     related_name=&#039;books&#039;,\n                                     db_constraint=False,\n                                     )\n\n    @property\n    def publish_name(self):\n        return self.publish.name\n\n    @property\n    def authors_info(self):\n        author_list = []\n        for author in self.authors.all():\n            author_list.append({\n                &#039;name&#039;: author.name,\n                &#039;age&#039;: author.age,\n                &#039;mobile&#039;: author.detail.mobile\n            })\n        return author_list\n\n    @property\n    def publish_bac(self):\n        from . import serializers\n        data = serializers.PublishModelSerializer(self.publish).data\n        return data\n\n    class Meta:\n        db_table = &#039;old_boy_book&#039;\n        verbose_name = &#039;\u4e66\u7c4d&#039;\n        verbose_name_plural = verbose_name\n        # \u8054\u5408\u552f\u4e00\n        # unique_together = (&#039;name&#039;, &#039;publish&#039;)\n\n    def __str__(self):\n        return self.name\n\nclass Publish(BaseModel):\n    name = models.CharField(max_length=64)\n    address = models.CharField(max_length=64)\n\n    class Meta:\n        db_table = &#039;old_boy_publish&#039;\n        verbose_name = &#039;\u51fa\u7248\u793e&#039;\n        verbose_name_plural = verbose_name\n\n    def __str__(self):\n        return self.name\n\nclass Author(BaseModel):\n    name = models.CharField(max_length=64)\n    age = models.IntegerField()\n\n    @property\n    def mobile(self):\n        return self.detail.mobile\n\n    class Meta:\n        db_table = &#039;old_boy_author&#039;\n        verbose_name = &#039;\u4f5c\u8005&#039;\n        verbose_name_plural = verbose_name\n\n    def __str__(self):\n        return self.name\n\nclass AuthorDetail(BaseModel):\n    mobile = models.CharField(max_length=11)\n\n    author = models.OneToOneField(to=&#039;Author&#039;, null=True,\n                                  related_name=&#039;detail&#039;,\n                                  db_constraint=False,\n                                  on_delete=models.CASCADE\n                                  )\n\n    class Meta:\n        db_table = &#039;old_boy_author_detail&#039;\n        verbose_name = &#039;\u4f5c\u8005\u8be6\u60c5&#039;\n        verbose_name_plural = verbose_name\n\n    def __str__(self):\n        return &#039;%s\u7684\u8be6\u60c5&#039; % self.author.name<\/code><\/pre>\n<h5>\u5e8f\u5217\u5316\u5c42\uff1aapi\/serializers.py<\/h5>\n<pre><code class=\"language-python\"># \u7fa4\u589e\u4e0e\u7fa4\u6539\u53cd\u5e8f\u5217\u5316\u5b9e\u73b0\n# 1\uff09ModelSerializer\u9ed8\u8ba4\u4e0d\u901a\u8fc7\u7fa4\u6539\u529f\u80fd\uff0c\u9700\u8981\u5728Meta\u4e2d\u8bbe\u7f6e list_serializer_class\n# 2\uff09\u81ea\u5b9a\u4e49ListSerializer\u5b50\u7c7b\uff0c\u91cd\u5199update\u65b9\u6cd5\uff0c\u5c06\u5b50\u7c7b\u7ed1\u5b9a\u7ed9 list_serializer_class\n# 3\uff09\u91cd\u5199update\u65b9\u6cd5\u4e2d\u901a\u8fc7 \u4ee3\u8868\u8981\u66f4\u65b0\u7684\u5bf9\u8c61\u4eecinstance \u53ca \u63d0\u4f9b\u7684\u66f4\u65b0\u6570\u636e\u4eecvalidated_data\n#       \u5f97\u5230 \u66f4\u65b0\u540e\u7684\u5bf9\u8c61\u4eecinstance \u8fd4\u56de\nclass BookV3ListSerializer(serializers.ListSerializer):\n    def update(self, instance, validated_data):\n        &#039;&#039;&#039;\n        :param instance: [book_obj1, ..., book_obj2]\n        :param validated_data: [{\u66f4\u65b0\u6570\u636e\u7684\u5b57\u6bb5}, ..., {\u66f4\u65b0\u6570\u636e\u7684\u5b57\u6bb5}]\n        :return: [book_new_obj1, ..., book_new_obj2]\n        &#039;&#039;&#039;\n        for index, obj in enumerate(instance):  # type: int, models.Book\n            # \u5355\u4e2a\u5bf9\u8c61\u6570\u636e\u66f4\u65b0 - \u4e00\u4e2a\u4e2a\u5c5e\u6027\u66f4\u65b0\u503c\n            for attr, value in validated_data[index].items():\n                # \u5bf9\u8c61\u6709\u66f4\u65b0\u6570\u636e\u5b57\u5178\u7684key\u5bf9\u5e94\u7684\u5c5e\u6027\uff0c\u624d\u5b8c\u6210\u8be5\u5c5e\u6027\u7684\u503c\u66f4\u65b0\n                if hasattr(obj, attr):\n                    setattr(obj, attr, value)\n            # \u4fe1\u606f\u540c\u6b65\u5230\u6570\u636e\u5e93\n            obj.save()\n        return instance\n\nclass BookV3ModelSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = models.Book\n        fields = (&#039;name&#039;, &#039;price&#039;, &#039;publish&#039;, &#039;authors&#039;, &#039;img&#039;, &#039;publish_name&#039;, &#039;authors_info&#039;)\n        list_serializer_class = BookV3ListSerializer\n        extra_kwargs = {\n            &#039;publish&#039;: {\n                &#039;required&#039;: True,\n                &#039;write_only&#039;: True\n            },\n            &#039;authors&#039;: {\n                &#039;required&#039;: True,\n                &#039;write_only&#039;: True\n            },\n            &#039;img&#039;: {\n                &#039;read_only&#039;: True\n            }\n        }\n    def validate_name(self, value):\n        if &#039;sb&#039; in value:\n            raise serializers.ValidationError(&#039;\u4e66\u540d\u6709\u654f\u611f\u8bcd\u6c47&#039;)\n        return value\n    def validate(self, attrs):\n        name = attrs.get(&#039;name&#039;)\n        publish = attrs.get(&#039;publish&#039;)\n        if models.Book.objects.filter(name=name, publish=publish):\n            raise serializers.ValidationError({&#039;book&#039;: &#039;\u4e66\u7c4d\u4ee5\u5b58\u5728&#039;})\n        return attrs<\/code><\/pre>\n<h5>\u89c6\u56fe\u5c42\uff1aapi\/views.py<\/h5>\n<pre><code class=\"language-python\">class BookV3APIView(APIView):\n    # \u5355\u67e5\u7fa4\u67e5\n    def get(self, request, *args, **kwargs):\n        pk = kwargs.get(&#039;pk&#039;)\n        if pk:\n            book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()\n            if not book_obj:\n                return APIResponse(1, &#039;pk error&#039;)\n            book_ser = serializers.BookV3ModelSerializer(book_obj)\n            return APIResponse(0, &#039;ok&#039;, results=book_ser.data)\n        book_query = models.Book.objects.filter(is_delete=False).all().order_by(&#039;-id&#039;)\n        book_ser = serializers.BookV3ModelSerializer(book_query, many=True)\n        return APIResponse(0, &#039;ok&#039;, results=book_ser.data)\n\n    # \u5355\u589e\u7fa4\u589e\n    def post(self, request, *args, **kwargs):\n        # \u5355\u589e \/books\/  data  {}\n        # \u7fa4\u589e \/books\/  data  [{}, ..., {}]\n        request_data = request.data\n        if isinstance(request_data, dict):\n            data = [request_data, ]\n        elif isinstance(request_data, list):\n            data = request_data\n        else:\n            return APIResponse(1, &#039;\u6570\u636e\u683c\u5f0f\u6709\u8bef&#039;)\n        book_ser = serializers.BookV3ModelSerializer(data=data, many=True)\n        if book_ser.is_valid():\n            book_obj_list = book_ser.save()\n            return APIResponse(0, &#039;ok&#039;,\n                results=serializers.BookV3ModelSerializer(book_obj_list, many=True).data\n            )\n        else:\n            return APIResponse(1, &#039;\u6dfb\u52a0\u5931\u8d25&#039;, results=book_ser.errors)\n\n    &quot;&quot;&quot;\n    1\uff09\u5148\u786e\u5b9a\u8981\u66f4\u65b0\u7684\u5bf9\u8c61 \u4e3b\u952e\u4eec \u4e0e \u6570\u636e\u4eec\n    2\uff09\u901a\u8fc7\u6821\u9a8c\u6570\u636e\u5e93\u5254\u9664 \u5df2\u5220\u9664\u7684\u5bf9\u8c61 \u4e0e \u4e0d\u5b58\u5728\u7684\u5bf9\u8c61\n        \u4e3b\u952e\u4eec =&gt; \u5254\u9664\u8fc7\u7a0b =&gt; \u53ef\u4ee5\u4fee\u6539\u7684\u5bf9\u8c61\u4eec\n        \u6570\u636e\u4eec =&gt; \u5254\u9664\u8fc7\u7a0b =&gt; \u53ef\u4ee5\u4fee\u6539\u7684\u5bf9\u8c61\u4eec\u5bf9\u5e94\u7684\u6570\u636e\u4eec\n    3\uff09\u53cd\u5e8f\u5217\u5316\u53ca\u6821\u9a8c\u8fc7\u7a0b\n        \u901a\u8fc7 =&gt; save() \u5b8c\u6210\u66f4\u65b0\n        \u5931\u8d25 =&gt; ser_obj.errors \u8fd4\u56de\n    &quot;&quot;&quot;\n    # \u5355\u6539\u7fa4\u6539\n    def patch(self, request, *args, **kwargs):\n        # \u5355\u6539 \/books\/(pk)\/  data  {&quot;name&quot;: &quot;new_name&quot;, ...}\n        # \u7fa4\u6539 \/books\/  data  [{&quot;pk&quot;: 1, &quot;name&quot;: &quot;new_name&quot;, ...}, ...,{&quot;pk&quot;: n, &quot;name&quot;: &quot;new_name&quot;, ...}]\n        # \u7ed3\u679c\uff1a\n        # pks = [1, ..., n] =&gt; book_query =&gt; instance\n        # data = [{&quot;name&quot;: &quot;new_name&quot;, ...}, ..., {&quot;name&quot;: &quot;new_name&quot;, ...}] =&gt; data\n\n        # \u6570\u636e\u9884\u5904\u7406\n        pk = kwargs.get(&#039;pk&#039;)\n        request_data = request.data\n        if pk:\n            if not isinstance(request_data, dict):\n                return APIResponse(1, &#039;\u5355\u6539\u6570\u636e\u6709\u8bef&#039;)\n            pks = [pk, ]\n            data = [request_data, ]\n        elif isinstance(request_data, list):\n            try:\n                pks = []\n                for dic in request_data:\n                    pks.append(dic.pop(&#039;pk&#039;))\n                data = request_data\n            except:\n                return APIResponse(1, &#039;\u7fa4\u6539\u6570\u636e\u6709\u8bef&#039;)\n        else:\n            return APIResponse(1, &#039;\u6570\u636e\u683c\u5f0f\u6709\u8bef&#039;)\n\n        # \u5c06 \u5df2\u5220\u9664\u7684\u4e66\u7c4d \u4e0e \u4e0d\u5b58\u5728\u7684\u4e66\u7c4d \u5254\u9664 (\u63d0\u4f9b\u4fee\u6539\u7684\u6570\u636e\u76f8\u5bf9\u5e94\u4e5f\u5254\u9664)\n        book_query = []\n        filter_data = []\n        for index, pk in enumerate(pks):\n            book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()\n            if book_obj:\n                book_query.append(book_obj)\n                filter_data.append(data[index])\n        # \u53cd\u5e8f\u5217\u5316\u5b8c\u6210\u6570\u636e\u7684\u4fee\u6539\n        book_ser = serializers.BookV3ModelSerializer(instance=book_query, data=filter_data, many=True, partial=True)\n        if book_ser.is_valid():\n            book_obj_list = book_ser.save()\n            return APIResponse(1, &#039;ok&#039;,\n                results=serializers.BookV3ModelSerializer(book_obj_list, many=True).data\n            )\n        else:\n            return APIResponse(1, &#039;\u66f4\u65b0\u5931\u8d25&#039;, results=book_ser.errors)\n\n    # \u5355\u5220\u7fa4\u5220  \n    def delete(self, request, *args, **kwargs):\n        # \u5355\u5220 \/books\/(pk)\/\n        # \u7fa4\u5220 \/books\/  \u6570\u636e\u5305\u643a\u5e26 pks =&gt; request.data\n        pk = kwargs.get(&#039;pk&#039;)\n        if pk:\n            pks = [pk]\n        else:\n            pks = request.data.get(&#039;pks&#039;)\n        if not pks:\n            return APIResponse(1, &#039;\u5220\u9664\u5931\u8d25&#039;)\n        book_query = models.Book.objects.filter(is_delete=False, pk__in=pks)\n        if not book_query.update(is_delete=True):  # \u64cd\u4f5c\u7684\u8bb0\u5f55\u5927\u4e8e0\u5c31\u8bb0\u5f55\u5220\u9664\u6210\u529f\n            return APIResponse(1, &#039;\u5220\u9664\u5931\u8d25&#039;)\n        return APIResponse(0, &#039;\u5220\u9664\u6210\u529f&#039;)<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>ListModelSerializer\u6a21\u5757 \u81ea\u5b9a\u4e49\u53cd\u5e8f\u5217\u5316\u5b57\u6bb5 # \u4e00\u4e9b\u53ea\u53c2\u4e0e\u53cd\u5e8f\u5217\u5316\u7684\u5b57\u6bb5\uff0c\u4f46\u662f\u4e0d\u662f\u4e0e\u6570\u636e\u5e93 [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[394,399],"tags":[],"_links":{"self":[{"href":"https:\/\/egonlin.com\/index.php?rest_route=\/wp\/v2\/posts\/5890"}],"collection":[{"href":"https:\/\/egonlin.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/egonlin.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/egonlin.com\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/egonlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5890"}],"version-history":[{"count":0,"href":"https:\/\/egonlin.com\/index.php?rest_route=\/wp\/v2\/posts\/5890\/revisions"}],"wp:attachment":[{"href":"https:\/\/egonlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/egonlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/egonlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}