'Django: How do I check if a User has already read/seen an article?
I am building a web-application for my senior design project with Python and Django. I have a user model that is able to read/write articles to display on the website. I have some tasks I want to accomplish.
I want to make it so that if an article is accessed (read) by a user, it is indicated for only that user that the article has been previously accessed. If I were to log into a brand new user account, the same article wouldn't be indicated as "accessed" for the new account.
How would I be able to present on the front-end side that the article has been viewed by the user logged in? (ie: make the article title bolded or a different color to indicate its been already visited)
Below are my models and views:
User model
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
email = models.EmailField(unique=True, max_length=255, blank=False)
university = models.CharField(max_length=200, null=True, blank=True)
newsletter_subscriber = models.BooleanField(default=False)
is_email_verified = models.BooleanField(default=False)
is_staff = models.BooleanField(
default=False,
help_text=(
'Designates whether the user can log into '
'this admin site.'
),
)
is_active = models.BooleanField(
default=True,
help_text=(
'Designates whether this user should be '
'treated as active. Unselect this instead '
'of deleting accounts.'
),
)
date_joined = models.DateTimeField(default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
Article model
class Article(models.Model):
user = models.ForeignKey(
User, on_delete=models.DO_NOTHING, null=True, blank=True)
title = models.CharField(max_length=200, null=True, blank=False)
author = models.CharField(max_length=200, null=True, blank=False)
year = models.CharField(max_length=200, null=True, blank=False)
journal = models.CharField(max_length=200, null=True, blank=False)
description = models.TextField(null=True, blank=True)
URL = models.CharField(max_length=200, null=True, blank=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class MetaData:
ordering = ['-created']
Article detail view
class ArticleDetail(LoginRequiredMixin, DetailView):
model = Article
context_object_name = 'articles'
template_name = 'home/article_detail.html'
Thank you!
Solution 1:[1]
You could create an extra table.
class ArticleSeenRecord(models.Model):
user = models.ForeignKey("django.contrib.auth.models.User", on_delete=models.CASCADE)
article = models.ForeignKey(Article, on_delete=models.CASCADE)
And then in your article view, create a new record when one doesn't exist, for that article combined with the authenticated user.
class ArticleDetail(LoginRequiredMixin, DetailView):
model = Article
context_object_name = 'articles'
template_name = 'home/article_detail.html'
def get_object(self, queryset=None):
obj = super().get_object(queryset)
record, created = ArticleSeenRecord.objects.get_or_create(user=self.request.user, article=obj)
return obj
class Article(models.Model):
...
def seen_by_user(self, user):
return self.atricleseenrecord_set.objects.filter(user=user).exists()
I added the extra function here. You will also need to add a template tag which you can ideally copy from this example
@register.simple_tag
def article_seen_by_user(article, user):
return article.seen_by_user(user)
For further guidance on how to use and register custom template tags, please refer to this page of the documentation:
https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/
Specifically this section:
https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#django.template.Library.simple_tag
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |