Привет всем У меня проблема с сортировкой наборов запросов в Django

Итак, я изучаю Django и пытаюсь сделать сайт, похожий на AirBNB. У меня есть модель под названием lisitngs, в которой широта и долгота хранятся в CharField. Моя модель выглядит следующим образом:

class Listing(models.Model):

    class BathRoomType(models.TextChoices):
        ATTACHED = 'Attached Bathroom'
        COMMON   = 'Shared Bathroom'
    
    class RoomVentType(models.TextChoices):
        AC      = 'Air Conditioner'
        NO_AC   = 'No Air Conditioner'

    class LisitngType(models.TextChoices):
        ROOM        = 'Room'
        APARTEMENT  = 'Apartement'
        HOUSE       = 'Full House'
    
    user                = models.ForeignKey(User, on_delete=models.CASCADE)
    title               = models.CharField(max_length=255)
    city                = models.ForeignKey(RoomLocation, on_delete=models.CASCADE)
    exact_address       = models.CharField(max_length=255)
    lat                 = models.CharField(max_length=300, blank=False, null=False, default="0")
    lng                 = models.CharField(max_length=300, blank=False, null=False, default="0")
    description         = models.TextField()
    price               = models.IntegerField()
    listing_type        = models.CharField(max_length=20, choices=LisitngType.choices, default=LisitngType.ROOM)
    kitchen_available   = models.BooleanField(default=False)
    kitchen_description = models.TextField(null=True, blank=True)
    bedrooms            = models.IntegerField()
    max_acomodation     = models.IntegerField()
    bathroom_type       = models.CharField(max_length=20, choices=BathRoomType.choices, default=BathRoomType.ATTACHED)
    no_bathrooms        = models.IntegerField()
    room_type           = models.CharField(max_length=30, choices=RoomVentType.choices, default=RoomVentType.AC)
    main_photo          = models.ImageField(upload_to='room_images', default='default_room.jpg')
    photo_1             = models.ImageField(upload_to='room_images', default='default_room.jpg')
    photo_2             = models.ImageField(upload_to='room_images', default='default_room.jpg')
    photo_3             = models.ImageField(upload_to='room_images', default='default_room.jpg')
    is_published        = models.BooleanField(default=False)
    date_created        = models.DateTimeField(default=timezone.now, editable=False)
    slug                = AutoSlugField(populate_from=['title', 'listing_type', 'bathroom_type', 'room_type'])
    rating              = models.IntegerField(default=5)
    approved            = models.BooleanField(default=False)
    total_bookings      = models.IntegerField(default=0)

    def __str__(self):
        return self.title

На моей домашней странице я хочу показать объявления, которые находятся рядом со мной. Для этого у меня есть функция near_places. Эта функция near_place берет широту и долготу после запроса через модель Listing и возвращает расстояние между объявлением и текущим пользователем, заходящим на домашнюю страницу:

import geocoder
from haversine import haversine

def near_places(dest_lat, dest_lng):
    g = geocoder.ip('me')
    origin = tuple(g.latlng)

    destination = (dest_lat, dest_lng)

    distance    = haversine(origin, destination)

    return distance

Моя функция домашней страницы в файле views.py выглядит следующим образом:

def home(request):

    objects = Listing.objects.filter(is_published=True, approved=True)
    
    for object in objects:
        lat, lng = float(object.lat), float(object.lng)
        object.distance = near_places(lat, lng)


    return render(request, 'listings/home.html')

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

Я пытался использовать object = objects.order_by('-distance')[:10], но он выдает ошибку as

FieldError at /
Cannot resolve keyword 'distance' into field. Choices are: The_room_booked, approved, bathroom_type, bedrooms, city, city_id, date_created, description, exact_address, id, is_published, kitchen_available, kitchen_description, lat, listing_type, lng, main_photo, max_acomodation, no_bathrooms, photo_1, photo_2, photo_3, price, rating, reviewsandrating, room_type, slug, title, total_bookings, user, user_id

Есть ли способ решить эту проблему? Также требуется довольно много времени для вычисления текущего расстояния с помощью функции near_places(), как описано выше. Любые предложения будут полезны. Спасибо

Вы не можете этого сделать, потому что в вашей модели нет поля distance и такого столбца в БД тоже нет.

Что вы можете сделать, это либо

  1. добавьте такое поле в вашу модель - я не рекомендую с вашей текущей логикой, так как вы будете перебирать каждый экземпляр и посылать sql запрос для обновления каждой строки.

    .
  2. Получите ваш queryest, преобразуйте его в список dicts и затем выполните итерацию по списку dicts с помощью вашей функции, добавляющей к нему ключ distance. Затем вы можете отсортировать список с помощью функции python sort и передать его в шаблон.

Нравится:

objects = Listing.objects.filter(is_published=True, approved=True).values('lat', 'lng') # add fields that you need
for obj in objects:
    obj['distance'] = near_places(obj['lat'], obj['lng'])

my_sorted_list = sorted(objects, key=lambda k: k['distance'])

Передайте my_sorted_list в ваш шаблон. Вы можете добавить аргумент reverse=True к функции sorted, если вам нужно другое направление сортировки.

Вернуться на верх