首页 > 解决方案 > Django Queryset 而不是 view.py 中的 for 循环和 if 语句

问题描述

我有以下型号:

class Post(models.Model):
    description = models.TextField()
    post_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created_on = models.DateField(auto_now_add=True, verbose_name=_("created on"))
    liked_users = models.ManyToManyField(User, blank=True, related_name='liked_post')
    disliked_users = models.ManyToManyField(User, blank=True, related_name='disliked_post')

   `def get_tag_weight(self):
        tag_set = Tag.objects.filter(post=self)
        tag_weight = 0
        for tag in tag_set:
           tag_weight += tag.weight
        return tag_weight`

class Image(models.Model):
    post = models.ForeignKey(Post, null=True, default=None, on_delete=models.CASCADE, related_name='parent_post')
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    images = models.ImageField(upload_to = 'images/')

class Tag(models.Model):
    name = models.CharField(max_length=100)
    weight = models.IntegerField(default=0)
    post = models.ForeignKey(Post, null=True, default=None, on_delete=models.CASCADE,related_name='post')
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

并在帐户中

class User(AbstractUser):
    user_id = models.UUIDField(
    default=uuid.uuid4,
    editable=False,
    primary_key=True
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
liked_posts = models.ManyToManyField('post.Post',  blank=True, related_name='user_liked')
disliked_posts = models.ManyToManyField('post.Post',  blank=True, related_name='user_disliked')
liked_tags = models.ManyToManyField('post.Tag' , blank=True, related_name='user_liked')
disliked_tags = models.ManyToManyField('post.Tag', blank=True, related_name='user_disliked')

这是我在views.py 中的get_queryset 方法

class PostListView(generics.ListCreateAPIView): 
serializer_class = GetUserIDSerializer
serializer_class_post = PostSerializer
permission_classes = [IsAuthenticated]
queryset = ''
context_object_name = "post_list"

def get_queryset_Post(self, user):
    liked_tags = user.liked_tags.all()
    disliked_tags = user.disliked_tags.all()
    posts = Post.objects.all()
    sorted_posts = []
    liked_posts = []
    disliked_posts = []
    normal_posts = []
    for post in posts:
        is_break = False
        is_added = False
        post_tags = Tag.objects.filter(post=post)
        for tag in post_tags:
            if is_break:
                break
            for liked_tag in liked_tags:
                if tag.name == liked_tag.name:
                    liked_posts.append(post)
                    is_break = True
                    is_added = True
                    break
            else:
                for disliked_tag in disliked_tags:
                    if tag.name == disliked_tag.name:
                        disliked_posts.append(post)
                        is_added = True
                        is_break = True
                        break
        if is_added == False:
            normal_posts.append(post)
            continue
    for i in range(len(liked_posts)):
        for j in range(i + 1, len(liked_posts)):
            if liked_posts[i].get_tag_weight() < liked_posts[j].get_tag_weight():
                liked_posts[i], liked_posts[j] = liked_posts[j], liked_posts[i]
    for i in range(len(disliked_posts)):
        for j in range(i + 1, len(disliked_posts)):
            if disliked_posts[i].get_tag_weight() > disliked_posts[j].get_tag_weight():
                disliked_posts[i], disliked_posts[j] = disliked_posts[j], disliked_posts[i]
    sorted_posts = liked_posts  + normal_posts + disliked_posts
    return sorted_posts

我想从视图中删除循环(所有 for 循环和 if 语句)并希望 queryset 进行计算。我想编写查询来过滤标签类似于用户喜欢的标签的帖子。我知道这很长。看看有没有人可以帮忙谢谢

标签: python-3.xdjangodjango-modelsdjango-rest-frameworkdjango-views

解决方案


首先,您ForeignKey从标签到帖子的方法是有问题的。据我了解,帖子可以有类似的标签。AManyToManyField更适合这种情况:

class Tag(models.Model):
    # Other fields
    post = models.ManyToManyField(Post, related_name='tags')
    # Other fields

现在转到视图,我们将使用标签过滤并按最大重量排序:

from django.db.models import Max

    liked_posts = Post.objects.filter(tags__in=user.liked_tags.all()).annotate(max_weight=Max('tags__weight')).order_by('-max_weight')
    normal_posts = Post.objects.exclude(tags__in=user.liked_tags.all()).exclude(tags__in=user.disliked_tags.all()).annotate(max_weight=Max('tags__weight')) # Might just need to annotate for union to work.
    disliked_posts = Post.objects.filter(tags__in=user.disliked_tags.all()).annotate(max_weight=Max('tags__weight')).order_by('max_weight')
    sorted_posts = liked_posts | normal_posts | disliked_posts

推荐阅读