Автоматическое вычисление и возврат поля на основе запроса в среде Django rest

#python #django #django-rest-framework

Вопрос:

У меня есть список книг с пинкодом местоположения, из которого они были добавлены. Я получаю запрос на публикацию с пинкодом пользователя, который хочет получить такой список. Список необходимо отсортировать в соответствии с расстоянием от пользователя.

Хотя у меня есть функция для вычисления расстояния, я хочу вернуть динамическое поле с именем «расстояние» в ответ.

Мои книжные модели похожи:-

 class Book(TimestampedModel):
user = models.ForeignKey(
    settings.AUTH_USER_MODEL,
    on_delete=models.SET_NULL,
    null=True
)
name = models.CharField(max_length=20, blank=True)
desc = models.CharField(max_length=140, blank=True)
is_active = models.BooleanField(default=True, blank=False)
price = models.IntegerField(null=True)
pincode = models.IntegerField(null=False)
 

Мой сериализатор похож на:-

 class BookSerializer(serializers.ModelSerializer):
"""Serializer for book object"""

class Meta:
    model = Book
    fields = ('id', 'user', 'name', 'desc', 'is_active', 'sold_to', 'is_sold',
              'age', 'price', 'created_at', 'updated_at', 'pincode')
 

и мой взгляд выглядит так:-

 class BookViewSet(viewsets.ModelViewSet):
serializer_class = serializers.BookSerializer
queryset = Book.objects.all()

query_params = self.request.query_params

def get_queryset(self):
    queryset = Book.objects.all()
    
    if('pincode' in query_params):
        pincode = query_params['pincode']
        try:
            for counter, instance in enumerate(queryset):
                instance.distance = dist.query_postal_code(
                    pincode, instance.pincode)
            queryset = sorted(queryset, key=attrgetter('distance'))
        except Exception as ex:
            print(ex)

    return queryset
 

Как вы можете видеть, я могу рассчитать расстояние в представлении, я не уверен, как отправить это в ответ.

Пожалуйста, помогите мне, я обязательно помогу вам когда-нибудь 😛

Комментарии:

1. Не могли бы вы поделиться тем, как вы рассчитываете расстояние, пожалуйста?

2. Я использую библиотеку с именем «pgeocode» и использую функцию — dist. query_postal_code(пинкод, экземпляр.пинкод), на мой взгляд

Ответ №1:

Используйте этот код в сериализаторе:

 class BookSerializer(serializers.ModelSerializer):
    distance = serializers. SerializerMethodField()

    @property
    def get_query_pincode(self):
        return self.context['request'].query_params.get('pincode', None)

    def get_distance(self, obj):
        if self.get_query_pincode:
            # Your distance calcualting code here
            return distance
        return None
 

Следующий в Meta классе:

 class Meta:
    model = Book
    fields = ('id', 'user', 'name', 'desc', 'is_active', 'sold_to', 'is_sold',
              'age', 'price', 'created_at', 'updated_at', 'pincode', 'distance')
 

Вам нужно будет добавить новое поле в fields атрибут, и, поскольку оно не является полем фактической модели, SerializerMethodField оно доступно только для чтения.

Надеюсь, это поможет!

Комментарии:

1. Но как бы я передал значение пинкода из моего представления в модель? И что такое метод пользовательской модели? До сих пор я пытался @property вычислять поля

2. @ShubhamGupta Просто пропустил это, внес необходимые правки. Пожалуйста, проверьте сейчас, работает ли это.

3. Не уверен, что это сработает. Видите, у меня есть два PIN-кода, один уже в моей модели книги, а другой от пользователя, отправляющего запрос. В моем сериализаторе я могу получить доступ к пинкоду книги, но не к пинкоду пользователя. Все еще нужна ясность. Конечно, некоторые изменения кода также необходимы в представлениях, чтобы передать пинкод пользователя.

4. Прямо в представлениях переопределите list функцию ModelViewSet и используйте свой пользовательский поисковик непосредственно для каждого объекта в queryset like, BookSerializer(obj, pincode)

5. Пожалуйста, попробуйте внести вышеуказанные изменения, сохраните представление таким, как оно есть, просто удалите код расчета расстояния из представлений.

Ответ №2:

Наконец, мне удалось вернуть пользовательское поле. В мое представление и сериализатор были внесены следующие изменения.

  1. Передача pin-кода пользователя (контекстной информации запроса) в мой сериализатор через контекст в сериализаторе
      def list(self, request):
             queryset = self.get_queryset()
    
             serializer = serializers.BookDetailSerializer(
                 queryset, context={'query_params': request.query_params}, many=True)
    
             return Response(serializer.data)
     
  2. Доступ к пинкоду осуществляется через переданный контекст в функции расстояния, определенной в serialzer:-

    pincode = self.контекст[‘query_params’][‘pincode’]

PS — Спасибо Решаб Дас за то, что дал некоторые указания