[Answered ]-Sort feed by engagement count django

1👍

I would propose to remodel this, to:

from django.conf import settings


class Post(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    image = models.ImageField(upload_to='post_images')
    caption = models.TextField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.caption


class LikeDislikePost(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    LIKE_DISLIKES = ((1, 'like'), (-1, 'dislike'))
    like_type = models.IntegerField(choices=LIKE_DISLIKES, default=1)

    def __str__(self):
        return self.username

You thus create a like with like_type = 1 and a dislike with like_dislike = -1. The like method then thus looks like:

from django.contrib.auth.decorators import login_required


@login_required
def like_post(request):
    username = request.user.username
    post_id = request.GET.get('post_id')
    new_like = LikePost.objects.create(post_id=post_id, user=request.user)
    return redirect('/')

Then you sort the Posts with:

from django.db.models import Count

Post.objects.alias(engagement=Count('likedislikepost')).order_by('-engagement')

There is no need to store the number of likes and dislikes in the post. This will only make it harder to keep it in sync properly.


Note: You can limit views to a view to authenticated users with the
@login_required decorator [Django-doc].


Note: Section 9 of the HTTP protocol
specifies that requests like GET and HEAD should not have side-effects, so you
should not change entities with such requests. Normally POST, PUT, PATCH, and
DELETE requests are used for this. In that case you make a small <form> that
will trigger a POST request, or you use some AJAX calls.


Note: Django’s DateTimeField [Django-doc]
has a auto_now_add=… parameter [Django-doc]
to work with timestamps. This will automatically assign the current datetime
when creating the object, and mark it as non-editable (editable=False), such
that it does not appear in ModelForms by default.

0👍

Out of some other reasons I need the interaction stored in each post. But the solution was in the answer before. I mixed that approach with mine.

def index(request):
posts = Post.objects.all().order_by('interaction_count')
count_posts = Post.objects.count()
return render(request, 'index.html', {'posts': posts, 'count_posts':count_posts})



def like_post(request):
post_id = request.GET.get('post_id')
post = Post.objects.get(id=post_id)
new_like = LikePost.objects.create(post_id=post_id)
new_like.save()
post.number_of_likes = post.number_of_likes+1

new_interaction = InteractionPost.objects.create(post_id=post_id)
new_interaction.save()
post.interaction_count = post.interaction_count + 1

post.save()
return redirect('/')


class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
num_post = models.IntegerField(default=0)
image = models.ImageField(upload_to=post_images)
caption = models.TextField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True)
number_of_likes = models.IntegerField(default=0)
number_of_dislikes = models.IntegerField(default=0)
interaction_count = models.IntegerField(default=0)

def __str__(self):
    return self.caption
👤amber

Leave a comment