DasUnicorn / WordWeave

Reddit style news site
0 stars 1 forks source link

User Story: Implement Vote Model #28

Closed DasUnicorn closed 9 months ago

DasUnicorn commented 9 months ago

Dependencies: none

Description Of Service Or Screen: Implement Vote Model. By just having a counter that counts up and down, there is no way to determine which votes have to be deleted when a user deletes their account. So a model that connects users, votes and posts is needed.

* Fallback option: Just count up and down on a button.

User Objective: As a user, I want to vote on posts, so that

Acceptance Criteria:

DasUnicorn commented 9 months ago

So... Here's the deal. The current Version deals with votes for threads and comment separately, which results in a lot of duplicate code. I tried my hands on a VoteMixin, but run into "TypeError: Cannot create a consistent method resolution order (MRO) for bases Model, VoteMixin", I wasn't able to solve. It would be create to maybe try this again later, if I have time.

Leaving my mixin code here for future-me:


from django.db import models
from django.contrib.auth.models import User
from django.db.models import F
from taggit.managers import TaggableManager
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.utils.text import slugify

STATUS = ((0, "Draft"), (1, "Published"))

class VoteMixin(models.Model):
    votes = models.IntegerField(default=0)

    def up_vote(self, user):
        # Check if the user has already voted for the thread or comment
        if not self.vote_set.filter(user=user).exists():
            self.votes = F('votes') + 1
            self.save()
            self.vote_set.create(user=user, value=1)

    def down_vote(self, user):
        # Check if the user has already voted for the thread or comment
        if not self.vote_set.filter(user=user).exists():
            self.votes = F('votes') - 1
            self.save()
            self.vote_set.create(user=user, value=-1)

    class Meta:
        abstract = True  # This ensures that VoteMixin is not a model itself

class Thread(models.Model, VoteMixin):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE, related_name="posts")
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    tags = TaggableManager()

    class Meta:
        ordering = ["-created_on"]

    def __str__(self):
        return f"The title of this thread is {self.title}"

    # Creating the slug
    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super().save(*args, **kwargs)

class Comment(models.Model, VoteMixin):
    thread = models.ForeignKey(Thread, on_delete=models.CASCADE, related_name="comments")
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE, related_name="commenter")
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["created_on"]

    def __str__(self):
        return f"Comment {self.body} by {self.author}"

class Vote(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now_add=True)
    value = models.SmallIntegerField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
DasUnicorn commented 9 months ago

Testing:

DasUnicorn commented 9 months ago

Possible future updates: