Skip to content
Advertisement

(django) Showing posts according to interests of users

I am pretty new to Django and still learning it, but I have to create something like medium.com. I want to show posts to users according to their interests. I added an interests field with a checkbox in a sign-up form. And of course, I added a category to the Post model. So, how can I show (to logged-in users only) publications that they interested in? Here is my models.py file in posts app

from django.db import models
from django.utils import timezone
from django.urls import reverse
# Create your models here.
class Post(models.Model):
    CATEGORY = (
        ('sport', 'Sport'),
        ('science', 'Science'),
        ('it', 'IT'),
        ('art', "Art"),
    )

    
    title = models.CharField(verbose_name="Title for publication", max_length=50)
    category = models.CharField(verbose_name="Category", choices=CATEGORY, max_length=50)
    author = models.ForeignKey("accounts.User", verbose_name="Author:", on_delete=models.CASCADE)
    body = models.TextField(verbose_name="Body for publication")
    pub_date = models.DateTimeField(verbose_name="Date:", auto_now_add=True)
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)


    def get_absolute_url(self):
        return reverse("post_detail", kwargs={"pk": self.pk})
    

    def __str__(self):
        return self.title

And here is my vies.py file in posts app

from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .models import Post
from django.urls import reverse_lazy

class PostListView(ListView):
    model = Post
    template_name = "index.html"    
    def get_queryset(self):
        return Post.objects.order_by('-pub_date')


class PostDetailView(DetailView):
    model = Post
    template_name = "./posts/post_detail.html"

class PostCreateView(CreateView):
    model = Post
    template_name = "./posts/new_post.html"
    fields = '__all__'

class PostUpdateView(UpdateView):
    model = Post
    template_name = "./posts/update_post.html"
    fields = ['body', 'title', 'category']

class PostDeleteView(DeleteView):
    model = Post
    template_name = "./posts/delete_post.html"
    success_url = reverse_lazy('index')


class SportPostListView(ListView):
    model = Post
    template_name = "./posts/sports.html"

class ITPostListView(ListView):
    model = Post
    template_name = "./posts/it.html"

class SciencePostListView(ListView):
    model = Post
    template_name = "./posts/ilm-fan.html"

class ArtPostListView(ListView):
    model = Post
    template_name = "./posts/sanat.html"

Here is my index.html file

{% extends 'base.html' %}
{% block content %}
{% if object_list %}
    {% for post in object_list %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.pub_date }}</p>
        <p>{{ post.author }}</p>
        <p>{{ post.body }}</p>
        <p>{{ post.category }}</p>
    {% endfor %}
{% else %}
    <p>No posts are available.</p>
{% endif %}
{% endblock content %}

This is my forms.py file in accounts app

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.db import models
from django import forms
class SignUpForm(UserCreationForm):
    INTERESTS = (
        ('sport', 'Sport'),
        ('science', 'Science'),
        ('it', 'IT'),
        ('art', "Art"),
        )
    username = forms.CharField(max_length=128, required=True)
    email = models.EmailField(verbose_name='emailingiz', unique=True, default='')
    first_name = forms.CharField(max_length=128, required=True)
    last_name = forms.CharField(max_length=128, required=True)
    interests = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple, choices=INTERESTS)
    USERNAME_FIELD = 'email'

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'username', 'email', 'interests', 'password1', 'password2')
    

And lastly this views.py file in accounts app

from django.urls import reverse_lazy
from django.views.generic import CreateView
from .forms import SignUpForm

class SignUpView(CreateView):
    form_class = SignUpForm
    success_url = reverse_lazy('login')
    template_name = 'signup.html'

I have no idea how to do this, but I know that I have to do something in the views.py file in the posts app, however, I do not know what to do. Will be really grateful if you could help me.

Advertisement

Answer

I would make another model Category. Since it will be its own model, you will be able to add future categories on the fly if needed, rather than having those hardcoded choices.

class Category(models.Model):
    name = models.CharField(default=None, blank=True, null=True)

Then your User and Post model will each have a ManytoMany field related to category. Posts can be tagged as certain categories when they are created, and Users will be able to select a number of categories that they are interested in and have them stored in this field:

class User(AbstractBaseUser):
     interests = models.ManytoManyField(Category, default=None, blank=True)
class Post(models.Model):
     categories = models.ManytoManyField(Category, default=None, blank=True)

You can make use of a forms.modelChoiceField which will enable your user to select a category.

In your PostListView, all you need to do is change the get_queryset method to filter for posts that the user likes.

class PostListView(ListView):
    model = Post
    template_name = "index.html" 
   
    def get_queryset(self):
        user_interests = self.request.user.interests
        return Post.objects.filter(
        categories__in=user_interests).order_by('pub_date')

Then, you should get the posts that share categories with the user’s interests.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement