簡體   English   中英

在 Django 中只對帖子和評論投票一次

[英]Vote only once in Django to posts and comments

我有兩個模型,稱為PostComment ,還有一個User可以支持或反對該帖子或評論。 但是,我想限制每個用戶只能對某個PostComment投票一次。

我可以在 model 級別上做一些事情來PostComment ,而不是計算特定帖子或評論的總票數。 但是,我認為創建單獨的Vote model 更具可擴展性,其中:

  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"]

我只知道這是一個糟糕的 model 將投票分開到PostVoteCommentVote ,而是想要一個更通用的Vote model ,我可以在其中指定投票是針對PostComment

我不想要的是Vote model 同時具有post_idcomment_id這將使得任何一個總是 null,因為一個投票總是要么是Comment要么是Post

有什么幫助嗎?

這可以通過使用Generic Relations更好地解決。 這篇https://simpleisbetterthancomplex.com/tutorial/2016/10/13/how-to-use-generic-relations.html是一篇很好的文章來理解這個概念,這里的例子與您的要求相似。

我相信,在你的例子中,一個重要的缺失是投票不知道它屬於哪個PostComment

一般關系

正如您在使用泛型關系的問題中已經猜到的那樣,您可以有一個單一的Vote model 。 在實踐中,這是一個可以指向不同模型的外鍵。

一個例子可能是:

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')

在您的Post和您的Comment中,為了能夠通過查詢訪問“投票對象”的投票(不會自動生成通用外鍵的反向關系):

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 = 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)>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM