#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:
Наконец, мне удалось вернуть пользовательское поле. В мое представление и сериализатор были внесены следующие изменения.
- Передача 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)
- Доступ к пинкоду осуществляется через переданный контекст в функции расстояния, определенной в serialzer:-
pincode = self.контекст[‘query_params’][‘pincode’]
PS — Спасибо Решаб Дас за то, что дал некоторые указания