Упорядочение набора запросов на основе связанных полей M2M - PullRequest
1 голос
/ 07 мая 2019

В настоящее время я пытаюсь вернуть набор запросов, основанный на трех моделях.

Модель местоположения

class Location(models.Model):
    ...
    lat = models.FloatField()
    lng = models.FloatField()

Модель пользователя (расширенная от пользователя Django)

class UserProfile(models.Model):
    ...
    user = OneToOneField(User)
    locations = ManyToManyField(Location)

Модель кейса

class Case(models.Model):
    ...
    owner = models.ForeignKey(User)
    completed = models.BooleanField()

Я использую geopy, чтобы вернуть местоположения, близкие к введенному лат / долг

def get_locations_nearby_coords(latitude, longitude, max_distance=None):
    """
    Return objects sorted by distance to specified coordinates
    which distance is less than max_distance given in kilometers
    """
    # Great circle distance formula
    gcd_formula = "6371 * acos(cos(radians(%s)) * cos(radians(lat)) * cos(radians(long) - radians(%s)) + sin(radians(%s)) * sin(radians(lat)))"
    distance_raw_sql = RawSQL(
        gcd_formula,
        (latitude, longitude, latitude)
    )
    qs = Location.objects.all().annotate(
        distance=distance_raw_sql).order_by('distance')
    if max_distance is not None:
        qs = qs.filter(distance__lt=max_distance)
    return qs

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

У пользователя может быть много местоположений, и местоположение может быть связано со многими пользователями, поэтому я выбрал поле m2m.

У меня не может быть дубликатов, однако местоположение может отображаться дважды в списке, ЕСЛИ в этом месте есть несколько пользователей, но окончательный список должен быть нарезан на 10.

РЕДАКТИРОВАТЬ:

Попытка уточнить, что должно быть возвращено.

Допустим, у меня есть 3 местоположения, которые находятся рядом со мной (это уже известные данные)

1. Location 1 (Closest)
2. Location 2 
3. Location 3 (Furthest)

Location 1 Имеет 1 пользователя, который завершил 3 дела.Location 2 имеет двух пользователей, пользователь 1 завершил 10 дел, а пользователь 2 завершил 2. Location 3 имеет 1 пользователя с 4 завершенными делами.Что должно быть возвращено следующим образом

1. Location 2 - User 1 - 10 Cases
2. Location 3 - User 1 - 4 Cases
3. Location 1 - User 1 - 3 Cases
4. Location 2 - User 2 - 2 Cases

1 Ответ

1 голос
/ 07 мая 2019

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

Чтобы добавить число завершенных дел в ваш набор запросов, вы можете использовать это:

qs = qs.annotate(completed_cases=Count('user__case', filter=Q(user__case__completed=True))

, и окончательная нарезка так же тривиальна, как [:10]

qs = qs.order_by('distance', '-completed_cases`, 'id', )[:10]

id -чтобы избежать случайности при одинаковом расстоянии и числе случаев.

UPD

# finding locations
...
qs = qs.order_by('distance', 'id', )[:10]

# finding users with completed cases
final_qs = User.objects.filter(locations__in=qs, ).\
    annotate(
        completed_cases=Count('case', filter=Q(case__completed=True),
        location_id=F('locations__id'),
    ).order_by('-completed_cases', 'id')[:10]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...