Проверка наличия связи с запросом - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь проверить, существуют ли следующие отношения с помощью запроса.Сначала я получаю всех подписчиков, которые есть у пользователя, а затем проверяю, следует ли пользователь за этими подписчиками.Вот мои модели:

class Following(models.Model):
    target = models.ForeignKey('User', related_name='followers', on_delete=models.CASCADE, null=True)
    follower = models.ForeignKey('User', related_name='targets', on_delete=models.CASCADE, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return '{} is followed by {}'.format(self.target, self.follower)

class User(AbstractBaseUser):
    username    = models.CharField(max_length=15, unique=True)

    email       = models.EmailField(max_length=100, unique=True)

Я использую Django Rest-Framework, поэтому я иду по конкретному URL, чтобы получить необходимую информацию.После перехода по URL, ожидается выход.Я получаю всех подписчиков, которые есть у пользователя.

views.py

class GetFollowersView(ListAPIView):
    serializer_class = FollowingSerializer

    def get_queryset(self):
        requested_user = get_requested_user(self)
        return User.objects.filter(targets__target=requested_user).order_by('-targets__created_at'). \
            annotate(is_following=Count('followers__follower', filter=Q(followers__follower=requested_user), distinct=True))

def get_requested_user(self):
    filter_kwargs = {'username': self.kwargs['username']}
    return get_object_or_404(User.objects.all(), **filter_kwargs)

serializers.py

class FollowingSerializer(serializers.ModelSerializer):
    is_following = serializers.IntegerField()
    class Meta:
        model = User
        fields = ('id', 'username', 'follower_count', 'following_count', 'is_following')

Однако проблема заключается в is_following аннотация.Я хотел бы видеть, следует ли пользователь за каждым конкретным подписчиком.Если они следуют за этим подписчиком, тогда is_following должно быть 1, если нет, то это 0. Я получаю неверные результаты в is_following Есть ли способ проверить, следует ли пользователь за каждым конкретным подписчиком?

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

Почему бы не использовать отношения M2M?Кажется, это может быть просто:

from django.db import models


class User(models.Model):
    name = models.CharField(max_length=200)
    followers = models.ManyToManyField('User')

    @property
    def follower_count(self):
        # How many people follow me
        return len(self.followers)

    @property
    def followee_count(self):
        # How many people I follow
        return len(self.user_set.all())

И вы можете изменить get_queryset(), чтобы найти только подписчиков:

User.objects.filter(followers__contains=self.request.user)

Помогает ли это?

0 голосов
/ 28 августа 2018

Если у вас установлена ​​Django Debug Toolbar и вы проверяете запрос для вашего текущего фильтра / аннотации, это то, что он показывает (для одного пользователя)

SELECT "user"."id", "user"."username", "user"."email", 
COUNT(DISTINCT T4."follower_id") AS "is_following" FROM "user" 
INNER JOIN "following" ON ( "user"."id" = "following"."follower_id" ) 
LEFT OUTER JOIN "following" T4 ON ( "user"."id" = T4."target_id" ) 
WHERE "following"."target_id" = 4 GROUP BY "user"."id", "user"."username", 
"user"."email", "following"."created_at" ORDER BY "following"."created_at" 
DESC

Однако дляполучить количество пользователей, за которыми следует выбранный пользователь, вы действительно хотите что-то вроде этого

SELECT ue."id", ue."username", ue."email", COUNT(DISTINCT fe."target_id") AS 
"is_following" FROM "user" u inner JOIN "following" fe ON ( u."id" = 
fe."follower_id" ) inner join user ue on fe.target_id = ue.id and u.id = 4
GROUP BY ue."id", ue."username", ue."email"

Я не думаю, что возможно объединить и подписчиков, и подписчиков в одном запросе, как вы сделали,Возможно, вы могли бы найти пересечение, а затем продолжить оттуда ... Как-то так ...

    def get_queryset(self):
        username = self.request.query_params.get('username', None)
        requested_user = models.User.objects.get(username=username)
        following_me = models.User.objects.filter(targets__target=requested_user).order_by('-targets__created_at')
        i_follow = models.User.objects.filter(followers__follower=requested_user).order_by('-followers__created_at')
        common = following_me & i_follow
        ### Set is_following for common as 1, all others as 0.
        #......
        #......
        return following_me
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...