在Django中仅投票一次,以发布和评论

问题描述 投票:1回答:2

我有两个分别称为PostComment的模型,以及一个可以对该文章或评论进行增票或减票的User模型。我想限制每个用户只能对某个PostComment进行一次投票。

我可以在模型级别上对PostComment做些事情,取而代之的是对特定帖子或评论进行总投票。但是,我认为创建一个单独的Vote模型具有更大的可扩展性,其中:

  1. 可以用一个查询(SELECT count(*) FROM votes where user_id=,等等...)来计算总投票数
  2. 可以使用unique_together对每个用户投票一次

目前我已经弄清楚了类似的东西:

import uuid
from django.db import models
from django.contrib.auth import get_user_model
from django.db import models

# Create your models here.


class Post(models.Model):
    LINK = "link"
    VIDEO = "video"
    IMAGE = "image"
    POST_TYPE_CHOICES = ((LINK, "Link"), (VIDEO, "Video"), (IMAGE, "Image"))

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=300)
    url = models.URLField(max_length=300)
    category = models.CharField(max_length=50)
    score = models.DecimalField(default=0, max_digits=20, decimal_places=2)
    votes = models.IntegerField(default=0)
    views = models.IntegerField(default=0)
    post_type = models.CharField(max_length=5, choices=POST_TYPE_CHOICES, default=LINK)
    text = models.CharField(max_length=40000)
    owner = models.ForeignKey('users.User', related_name='posts', on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ["-created"]


class PostVote(models.Model):
    DOWNVOTE = -1
    UPVOTE = 1
    UNVOTE = 0
    VOTE_TYPE_CHOICES = ((DOWNVOTE, "Downvote"), (UPVOTE, "Upvote"), (UNVOTE, "Unvote"))

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    score = models.IntegerField(choices=VOTE_TYPE_CHOICES, default=UPVOTE)
    voter = models.ForeignKey('users.User', related_name='post_votes', on_delete=models.CASCADE)


class Comment(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    body = models.CharField(max_length=10000)
    post = models.ForeignKey('Post', related_name='comments', on_delete=models.CASCADE)
    owner = models.ForeignKey('users.User', related_name='comments', on_delete=models.CASCADE)

    class Meta:
        ordering = ["-created"]

class CommentVote(models.Model):
    DOWNVOTE = -1
    UPVOTE = 1
    UNVOTE = 0
    VOTE_TYPE_CHOICES = ((DOWNVOTE, "Downvote"), (UPVOTE, "Upvote"), (UNVOTE, "Unvote"))

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    score = models.IntegerField(choices=VOTE_TYPE_CHOICES, default=UPVOTE)
    voter = models.ForeignKey('users.User', related_name='comment_votes', on_delete=models.CASCADE)

    def __str__(self):
        return self.score

    class Meta:
        ordering = ["-created"]

[我只知道这是将投票分为PostVoteCommentVote的糟糕模型,而是想要一个更通用的Vote模型,在该模型中我可以将投票指定为PostComment ]。

[我不想要的是同时具有Votepost_idcomment_id模型,使得其中一个始终为null,因为对于Comment始终是一票或一个Post

有帮助吗?

python django
2个回答
0
投票

这可以通过使用Generic Relations更好地解决。这篇https://simpleisbetterthancomplex.com/tutorial/2016/10/13/how-to-use-generic-relations.html是一篇不错的文章,可以理解这个概念,这里的示例与您的要求类似。


1
投票

[我相信,在您的示例中,一个重要的缺失之处是投票不知道投票属于哪个PostComment

一般关系

您可以使用Vote拥有单个generic relation模型,就像您在问题中已经猜到的那样。实际上,这是一个外键,可以指向不同的模型。

一个例子可能是:

from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models

class Vote(models.Model):
   # ...
   # your model stuff
   # ...
   content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
   voted_object_id = models.UUIDField(default=uuid.uuid4)
   voted_object = models.GenericForeignKey('content_type', 'voted_object_id')

并且在PostComment中,为了能够通过查询访问“投票对象”的票(不会自动生成通用外键的反向关系:]]

from django.db import models
from django.contrib.contenttypes.fields import GenericRelation

class Post(models.Model):
   # ...
   # other stuff
   # ...
   votes = GenericRelation(Vote, related_query_name='post')

class Comment(models.Model):
   # ...
   # other stuff
   # ...
   votes = GenericRelation(Vote, related_query_name='comment')

通过这种方式,您可以通过以下方式访问“投票的对象”(因此是Post或Comment):

post = Post.objects.all()[0]
vote_to_post = Vote.objects.create(**vote_data, voted_object=post)
print(vote_to_post.voted_object)  # <Post: (0)>

print(post.votes)  # <QuerySet [<Vote: 0>]>

我相信,但是我没有机会测试,也可以这样做:

print(vote_to_post.post)  # <Post: (0)>
    
© www.soinside.com 2019 - 2024. All rights reserved.