[英]Vote only once in Django to posts and comments
我有兩個模型,稱為Post
和Comment
,還有一個User
可以支持或反對該帖子或評論。 但是,我想限制每個用戶只能對某個Post
或Comment
投票一次。
我可以在 model 級別上做一些事情來Post
和Comment
,而不是計算特定帖子或評論的總票數。 但是,我認為創建單獨的Vote
model 更具可擴展性,其中:
SELECT count(*) FROM votes where user_id=
等...)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 將投票分開到PostVote
和CommentVote
,而是想要一個更通用的Vote
model ,我可以在其中指定投票是針對Post
或Comment
。
我不想要的是Vote
model 同時具有post_id
和comment_id
這將使得任何一個總是 null,因為一個投票總是要么是Comment
要么是Post
。
有什么幫助嗎?
這可以通過使用Generic Relations
更好地解決。 這篇https://simpleisbetterthancomplex.com/tutorial/2016/10/13/how-to-use-generic-relations.html是一篇很好的文章來理解這個概念,這里的例子與您的要求相似。
我相信,在你的例子中,一個重要的缺失是投票不知道它屬於哪個Post
或Comment
。
正如您在使用泛型關系的問題中已經猜到的那樣,您可以有一個單一的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.