জ্যাঙ্গো বিশ্রাম ফ্রেমওয়ার্ক: ক্ষেত্রগুলির গতিপথের সাবসেটটি ফেরত দিন


104

সমস্যা

প্রাগমেটিক রিস্টালফুল এপিআই ডিজাইন করার জন্য ব্লগপোস্টের সেরা অনুশীলনগুলিতে সুপারিশ অনুসারে , আমি fieldsজ্যাঙ্গো রেস্ট ফ্রেমওয়ার্ক ভিত্তিক এপিআইতে একটি কোয়েরি প্যারামিটার যুক্ত করতে চাই যা ব্যবহারকারীকে সংস্থান অনুসারে ক্ষেত্রগুলির কেবলমাত্র একটি উপসেট নির্বাচন করতে সক্ষম করে।

উদাহরণ

সিরিয়ালাইজার:

class IdentitySerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.Identity
        fields = ('id', 'url', 'type', 'data')

একটি নিয়মিত ক্যোয়ারী সমস্ত ক্ষেত্র ফিরে আসবে।

GET /identities/

[
  {
    "id": 1,
    "url": "http://localhost:8000/api/identities/1/",
    "type": 5,
    "data": "John Doe"
  },
  ...
]

fieldsপ্যারামিটার সহ একটি ক্যোয়ারী কেবলমাত্র ক্ষেত্রগুলির একটি উপসেট ফেরত পাঠাতে হবে:

GET /identities/?fields=id,data

[
  {
    "id": 1,
    "data": "John Doe"
  },
  ...
]

অবৈধ ক্ষেত্রগুলির সাথে একটি ক্যোয়ারীটি হয় অবৈধ ক্ষেত্রগুলি উপেক্ষা করুন বা ক্লায়েন্ট ত্রুটি নিক্ষেপ করা উচিত।

লক্ষ্য

এটি কি কোনওভাবে বক্সের বাইরে রাখা সম্ভব? যদি তা না হয় তবে এটি বাস্তবায়নের সহজ উপায় কী? চারপাশে কোনও তৃতীয় পক্ষের প্যাকেজ রয়েছে যা ইতিমধ্যে এটি করে?

উত্তর:


126

আপনি ক্রিয়ালাইজার __init__পদ্ধতিটি ওভাররাইড করতে পারেন এবং fieldsক্যোয়ারী প্যারামগুলির উপর ভিত্তি করে গতিযুক্ত বৈশিষ্ট্যটি সেট করতে পারেন । requestসিরিয়ালাইজারে প্রেরণ করে আপনি প্রসঙ্গটি জুড়ে অবজেক্টটি অ্যাক্সেস করতে পারেন ।

বিষয়টি সম্পর্কে জ্যাঙ্গো রেস্ট ফ্রেমওয়ার্ক ডকুমেন্টেশনের উদাহরণ থেকে একটি অনুলিপি এবং পেস্ট করুন:

from rest_framework import serializers

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        fields = self.context['request'].query_params.get('fields')
        if fields:
            fields = fields.split(',')
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)


class UserSerializer(DynamicFieldsModelSerializer, serializers.HyperlinkedModelSerializer):

    class Meta:
        model = User
        fields = ('url', 'username', 'email')

4
অবশেষে আমি এটি বাস্তবায়নের জন্য প্রায় এসেছি, এবং এটি পুরোপুরি কাজ করে! ধন্যবাদ আমি এর জন্য একটি মিশ্রিন লিখে শেষ করেছি, সংমিশ্রণটি সাবক্লাসিংয়ের চেয়ে কিছুটা নমনীয় :) gist.github.com/dbrgn/4e6fc1fe5922598592d6
ড্যানিলো

8
জ্যাঙ্গোর সাম্প্রতিক সংস্করণগুলিতে আপনাকে পরিবর্তন QUERY_PARAMSকরতে হবে query_params, তবে এগুলি ছাড়া এটি মোহনগুলির মতো কাজ করে।
মাইক উইলিস

4
আপনার সম্ভবত requestsএটির সদস্য হিসাবে উপস্থিত থাকা উচিত context। এটি উত্পাদনের সময় এমনটি হয় না যখন ইউনিট পরীক্ষা চালায় যা বস্তুগুলিকে ম্যানুয়ালি তৈরি করে।
স্মিটেক

21
এফওয়াইআই: এই উদাহরণটি এখানে পাওয়া ডিআরএফ ডকুমেন্টেশনের একটি ভারব্যাটিক অনুলিপি: django-rest-framework.org/api-guide/serialization/#example মূল লেখকদের লিঙ্ক না দেওয়ার জন্য এটি একটি খারাপ ফর্ম
অ্যালেক্স বাউস্ক

4
DRF ভর্তি ডকুমেন্টেশন , যা থেকে এই উত্তর কপি করা হয়েছে, উন্নত করা হয়েছে যেহেতু এই উত্তর পোস্ট করা হয়েছে।
ক্রিস

51

এই কার্যকারিতাটি তৃতীয় পক্ষের প্যাকেজ থেকে পাওয়া যায় ।

pip install djangorestframework-queryfields

আপনার সিরিয়ালাইজারটি এভাবে ঘোষণা করুন:

from rest_framework.serializers import ModelSerializer
from drf_queryfields import QueryFieldsMixin

class MyModelSerializer(QueryFieldsMixin, ModelSerializer):
    ...

তারপরে ক্ষেত্রগুলি এখন ক্যোয়ারী আর্গুমেন্টগুলি ব্যবহার করে (ক্লায়েন্ট-পাশ) নির্দিষ্ট করা যেতে পারে:

GET /identities/?fields=id,data

বর্জনীয় ফিল্টারিংও সম্ভব, যেমন আইডি ব্যতীত প্রতিটি ক্ষেত্রকে ফিরিয়ে দেওয়া :

GET /identities/?fields!=id

দাবি অস্বীকার: আমি লেখক / রক্ষণাবেক্ষণকারী।


4
ওহে. এই এবং github.com/dbrgn/drf-dynamic-fields (নির্বাচিত উত্তরের মন্তব্যে লিঙ্কযুক্ত) এর মধ্যে পার্থক্য কী ?
ড্যানিলো বার্গেন

4
ধন্যবাদ, আমি সেই বাস্তবায়নটি দেখেছি এবং দেখে মনে হচ্ছে এটি একই বুনিয়াদি ধারণা। তবে dbrgnবাস্তবায়নের কিছু পার্থক্য রয়েছে: 1. বাদ দিয়ে সমর্থন করে না fields!=key1,key2। ২. জিইটি অনুরোধ প্রসঙ্গে বাইরের সিরিয়ালাইজগুলিও সংশোধন করে, যা কিছু পুট / পোস্ট অনুরোধগুলি ভেঙে ফেলতে পারে এবং করবে। ৩. উদাহরণস্বরূপ ক্ষেত্রগুলি জমে না fields=key1&fields=key2, যা এজাক্স অ্যাপ্লিকেশনগুলির জন্য একটি দুর্দান্ত। এটির শূন্য পরীক্ষার কভারেজও রয়েছে যা ওএসএসে কিছুটা অস্বাভাবিক।
wim

4
@ উইম ডিআরএফ এবং জ্যাঙ্গোর কোন সংস্করণ আপনার লাইব্রেরি সমর্থন করে? আমি ডক্সে কিছু পাইনি।
পাভেলসুইকি

4
জ্যাঙ্গো 1.7-1.11 +, মূলত ডিআরএফ সমর্থন করে এমন কোনও কনফিগারেশন। এই মন্তব্যটি পুরানো হতে পারে, সুতরাং সিআইয়ের জন্য পরীক্ষা ম্যাট্রিক্সটি এখানে দেখুন
ওয়াইম

4
আমার জন্য দুর্দান্ত কাজ করেছে: জ্যাঙ্গো == ২.২. d, জাঙ্গোরেস্টফ্রেমওয়ার্ক == ৩.১০.৩, জ্যাঙ্গোরস্টফ্রেমওয়ার্ক-ক্যোয়ারিফিল্ডস == 1.0.0
নীরজ কাশ্যপ

7

সিরিয়ালাইজার.পি

class DynamicFieldsSerializerMixin(object):

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsSerializerMixin, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)


class UserSerializer(DynamicFieldsSerializerMixin, serializers.HyperlinkedModelSerializer):

    password = serializers.CharField(
        style={'input_type': 'password'}, write_only=True
    )

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'email', 'first_name', 'last_name')


    def create(self, validated_data):
        user = User.objects.create(
            username=validated_data['username'],
            email=validated_data['email'],
            first_name=validated_data['first_name'],
            last_name=validated_data['last_name']
        )

        user.set_password(validated_data['password'])
        user.save()

        return user

ভিউ.পি

class DynamicFieldsViewMixin(object):

 def get_serializer(self, *args, **kwargs):

    serializer_class = self.get_serializer_class()

    fields = None
    if self.request.method == 'GET':
        query_fields = self.request.QUERY_PARAMS.get("fields", None)

        if query_fields:
            fields = tuple(query_fields.split(','))


    kwargs['context'] = self.get_serializer_context()
    kwargs['fields'] = fields

    return serializer_class(*args, **kwargs)



class UserList(DynamicFieldsViewMixin, ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

3

নতুন পৃষ্ঠাগুলি সিরিয়ালাইজার শ্রেণি কনফিগার করুন

from rest_framework import pagination, serializers

class DynamicFieldsPaginationSerializer(pagination.BasePaginationSerializer):
    """
    A dynamic fields implementation of a pagination serializer.
    """
    count = serializers.Field(source='paginator.count')
    next = pagination.NextPageField(source='*')
    previous = pagination.PreviousPageField(source='*')

    def __init__(self, *args, **kwargs):
        """
        Override init to add in the object serializer field on-the-fly.
        """
        fields = kwargs.pop('fields', None)
        super(pagination.BasePaginationSerializer, self).__init__(*args, **kwargs)
        results_field = self.results_field
        object_serializer = self.opts.object_serializer_class

        if 'context' in kwargs:
            context_kwarg = {'context': kwargs['context']}
        else:
            context_kwarg = {}

        if fields:
            context_kwarg.update({'fields': fields})

        self.fields[results_field] = object_serializer(source='object_list',
                                                       many=True,
                                                       **context_kwarg)


# Set the pagination serializer setting
REST_FRAMEWORK = {
    # [...]
    'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'DynamicFieldsPaginationSerializer',
}

গতিশীল সিরিয়ালাইজার তৈরি করুন

from rest_framework import serializers

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.

    See:
        http://tomchristie.github.io/rest-framework-2-docs/api-guide/serializers
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)
# Use it
class MyPonySerializer(DynamicFieldsModelSerializer):
    # [...]

সর্বশেষে, আপনার এপিআইভিউগুলির জন্য একটি হোমমেজ মিক্সিন ব্যবহার করুন

class DynamicFields(object):
    """A mixins that allows the query builder to display certain fields"""

    def get_fields_to_display(self):
        fields = self.request.GET.get('fields', None)
        return fields.split(',') if fields else None

    def get_serializer(self, instance=None, data=None, files=None, many=False,
                       partial=False, allow_add_remove=False):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        context = self.get_serializer_context()
        fields = self.get_fields_to_display()
        return serializer_class(instance, data=data, files=files,
                                many=many, partial=partial,
                                allow_add_remove=allow_add_remove,
                                context=context, fields=fields)

    def get_pagination_serializer(self, page):
        """
        Return a serializer instance to use with paginated data.
        """
        class SerializerClass(self.pagination_serializer_class):
            class Meta:
                object_serializer_class = self.get_serializer_class()

        pagination_serializer_class = SerializerClass
        context = self.get_serializer_context()
        fields = self.get_fields_to_display()
        return pagination_serializer_class(instance=page, context=context, fields=fields)

class MyPonyList(DynamicFields, generics.ListAPIView):
    # [...]

অনুরোধ

এখন, আপনি যখন কোনও সংস্থার অনুরোধ করবেন, আপনি fieldsকেবলমাত্র url এ নির্দিষ্ট ক্ষেত্রগুলি দেখানোর জন্য একটি পরামিতি যুক্ত করতে পারেন । /?fields=field1,field2

আপনি এখানে একটি অনুস্মারক খুঁজে পেতে পারেন: https://gist.github.com/Kmaschta/e28cf21fb3f0b90c597a


2

এই জাতীয় কার্যকারিতা আমরা drf_tweaks / নিয়ন্ত্রণ-ওভার-সিরিয়ালাইজড ক্ষেত্রগুলিতে সরবরাহ করেছি

আপনি যদি আমাদের সিরিয়ালাইজারগুলি ব্যবহার করেন তবে আপনার যা দরকার তা হল ?fields=x,y,zক্যোয়ারীতে প্যারামিটারটি পাস করা।


2

আপনি ডায়নামিক রিস্টের চেষ্টা করতে পারেন , এতে ডায়নামিক ফিল্ডস (অন্তর্ভুক্তি, বর্জন), এমবেডড / সাইডেলোয়েড অবজেক্টস, ফিল্টারিং, অর্ডারিং, পৃষ্ঠাবদ্ধকরণ এবং আরও অনেক কিছুর জন্য সমর্থন রয়েছে।


2

নেস্টেড ডেটার জন্য, আমি ডক্স , ড্রাফ-ফ্লেক্সফিল্ডে প্রস্তাবিত প্যাকেজটির সাথে জ্যাঙ্গো রেস্ট ফ্রেমওয়ার্ক ব্যবহার করছি

এটি আপনাকে পিতা বা মাতা এবং শিশু উভয় বস্তুতে ফিরিয়ে দেওয়া ক্ষেত্রগুলিকে সীমাবদ্ধ করতে দেয়। রিডমের নির্দেশাবলী ভাল, কেবলমাত্র কয়েকটি বিষয় লক্ষ্য রাখতে হবে:

ইউআরএলটির / এর মতো '/ ব্যক্তি /? সম্প্রসারণ = দেশ ও ক্ষেত্রগুলি = আইডি, নাম, দেশ' প্রয়োজন বলে মনে হচ্ছে রিডমে / ব্যক্তিতে লেখা না হয়ে? প্রসারিত = দেশ ও ক্ষেত্রসমূহ = আইডি, নাম, দেশ '

নেস্টেড অবজেক্টের নামকরণ এবং এর সম্পর্কিত নাম পুরোপুরি সামঞ্জস্যপূর্ণ হওয়া দরকার, যা অন্যথায় প্রয়োজন হয় না।

আপনার যদি 'অনেকগুলি' থাকে যেমন একটি দেশে অনেকগুলি রাজ্য থাকতে পারে তবে আপনাকে 'অনেকগুলি' সেট করতে হবে: ডক্সে বর্ণিত সিরিয়ালাইজারে সত্য।


1

আপনি যদি গ্রাফকিউএল এর মতো নমনীয় কিছু চান তবে আপনি জ্যাঙ্গো-রেষ্টকিএল ব্যবহার করতে পারেন । এটি নেস্টেড ডেটা (উভয় সমতল এবং পুনরাবৃত্ত) সমর্থন করে।

উদাহরণ

from rest_framework import serializers
from django.contrib.auth.models import User
from django_restql.mixins import DynamicFieldsMixin

class UserSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'groups')

একটি নিয়মিত অনুরোধ সমস্ত ক্ষেত্র ফেরত দেয়।

GET /users

    [
      {
        "id": 1,
        "username": "yezyilomo",
        "email": "yezileliilomo@hotmail.com",
        "groups": [1,2]
      },
      ...
    ]

queryঅন্যদিকে প্যারামিটারের সাথে একটি অনুরোধ ক্ষেত্রগুলির কেবলমাত্র একটি উপসেট প্রদান করে:

GET /users/?query={id, username}

    [
      {
        "id": 1,
        "username": "yezyilomo"
      },
      ...
    ]

সঙ্গে জ্যাঙ্গো-restql যদি আপনি কোন স্তরের নেস্টেড ক্ষেত্র অ্যাক্সেস করতে পারেন। যেমন

GET /users/?query={id, username, date_joined{year}}

    [
      {
        "id": 1,
        "username": "yezyilomo",
        "date_joined": {
            "year": 2018
        }
      },
      ...
    ]

পুনরাবৃত্তিযোগ্য নেস্টেড ক্ষেত্রগুলির জন্য, ব্যবহারকারীর জন্য ডিম গ্রুপ।

GET /users/?query={id, username, groups{id, name}}

    [
      {
        "id": 1,
        "username": "yezyilomo",
        "groups": [
            {
                "id": 2,
                "name": "Auth_User"
            }
        ]
      },
      ...
    ]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.