Monitoring User Activity in Django - python

I am creating a book app where users can sign up and start reading.
This is the model.py for the book:
from django.db import models
from django.urls import reverse
from django.conf import settings
class Chapter(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(unique=True)
date_completed = models.DateTimeField(blank=True, null=True)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("course:subchapter_list", kwargs={"pk": self.pk})
class SubChapter(models.Model):
chapter = models.ForeignKey(Chapter, on_delete=models.CASCADE)
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(unique=True)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
class SubSection(models.Model):
sub_chapter = models.ForeignKey(SubChapter, on_delete=models.CASCADE)
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(unique=True)
text = models.TextField(null=True, blank=False)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("course:detail",
kwargs={"slug": self.sub_chapter.slug,
"slug2": self.slug,
"pk": self.sub_chapter.chapter.pk,
}
)
How can I monitor each user's progress such that when a subsection/subchapter/chapter is viewed/read, that model instance's completed attribute is set to True just for that user? My current implementation sets completed to True for everyone.
I would appreciate code snippets demonstrating how you might implement it.

If you want to monitor the reading progress for every user, you can't have the completed fields on the Chapter, SubChapter and SubSection models, you need a new one related to the user. I would do something like this:
class ReadingProgress(models.Model):
user = models.ForeignKey(User)
completed_chapter = models.ForeignKey(Chapter)
completed_subchapter = models.ForeignKey(SubChapter)
completed_subsection = models.ForeignKey(SubSection)
If you have different books, you should add foreign keys to the book model as well.
Then in the views that fetch the chapters, sections and so on, you can get the ReadingProgress object for the specific user (and book?) and set the corresponding values.

Related

Saving value of one model field count to another field of the same model during save

I am working on a pool app and want to add the total_likes attribute to the model which will allow me to count the number of users who liked the question, just like Youtube community question allows.
I just tried to override the save(*args, **kwargs) but got many errors.
What should I do now?
from django.db import models
from django.contrib.auth.models import User
class Question(models.Model):
text = models.TextField()
voters = models.ManyToManyField(to=User, blank=True, related_name='voters')
impression = models.CharField(max_length=30, choices=impression_choices, blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
likes = models.ManyToManyField(to=User, related_name='likes', blank=True)
total_likes = models.IntegerField(default=0)
def __str__(self):
return self.text
def save(self, *args, **kwargs):
self.total_likes = self.likes_set.count()
super().save(*args, **kwargs)
The Model below works totally fine. In the model above I tried to override the save() method but I don't know how?
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.CharField(max_length=20)
votes = models.IntegerField(blank=True, default=0)
def __str__(self):
return self.text

Accessing other model field when validating model field in Django

So I have a Django auctions app, which has 4 models: Users, Listings, Bids, Comments.
When a user tries to place a bid on some listing, I want to check whether bid_amount field in Bid model is smaller than start starting_bid field in Listing model. Also, I wanted to ask, what is the best practice for this kinda stuff? AFAIK, you can validate a form field in forms.py. Thanks!
models.py
class Listing(models.Model):
"""Auction listing"""
user = models.ForeignKey(User, verbose_name='user owner', on_delete=models.CASCADE, related_name="usr_listings")
title = models.CharField(max_length=64)
description = models.TextField(max_length=160)
starting_bid = models.PositiveIntegerField()
bids_number = models.PositiveIntegerField(default=1)
img_url = models.URLField("Image URL", max_length=200, blank=True)
category = models.CharField(max_length=64, blank=True)
date_listed = models.DateTimeField(default=timezone.now)
class Meta:
verbose_name = 'auction listing'
ordering = ['-date_listed']
def __str__(self):
return self.title
def get_absolute_url(self):
print('loading... get_absolute_url')
return reverse('listing_detail', kwargs={'pk': self.pk})
class Bid(models.Model):
"""Bids made on auction listing"""
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="listing_bids")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_bidder")
bid_amount = models.PositiveIntegerField(default=None)
class Meta:
verbose_name = 'Bid'
def __str__(self):
return f'{self.bid_amount} by {self.user} on {self.listing}'
def clean(self):
super().clean()
# do something to access Listing.starting bid, and Listing.user
adding this to the clean method of Bid solve the problem for you.
from django.core.exceptions import ValidationError
...
if self.bid_amount < self.listing.starting_bid:
raise ValidationError("bid_amount must be greater than or equal to starting_bid of the listing")

How can I check whether a person is included in a model to make a Job/Post

I have created a School System-like system, that creates a job and sends them to employees/users. I'm almost done making this system however I can't seem to know what do to check if the user is included in the manager model that I created to create a job.
Also, how can a user just see all their job that was assigned to them. All I know is to use objects.allbut that might only seem to show all of the jobs that was posted, I just want the user to see the job included to them.
Here is my model.py:
from django.db import models
from profiles.models import User
# Create your models here.
class Points (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}Profile'
class Manager (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Member (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Job (models.Model):
manager = models.OneToOneField(Manager, on_delete=models.CASCADE)
member = models.OneToOneField(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField (auto_now = True)
file = models.FileField(null=True, blank=True,upload_to='job_files')
def __str__(self):
return self.title
And Views.py:
from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import Job
from profiles.models import User
# Create your views here.
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
class createjob (CreateView):
model = Job
fields = ['member','title', 'description', 'file']
How can I proceed?
Use get_queryset to filter job by user
Ex:
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
def get_queryset(self):
return Job.objects.filter(member__member=self.request.user)

Python Django - Count objects based on owner that is the user

I have users who listed their textbook.
I need to count objects in Textbook model and display total count in the side menu.
Here is my Model
from django.db import models
from django.http import HttpResponse
from django.urls import reverse
from django.contrib.auth.models import User
from django.utils.functional import cached_property
class Textbooks(models.Model):
owner = models.ForeignKey(User, on_delete=models.PROTECT, null=True, blank=True)
title = models.CharField(max_length=1000)
isbn = models.CharField(max_length=20)
author = models.CharField(max_length=250)
edition = models.CharField(max_length=50)
rrp = models.CharField(max_length=30)
about = models.TextField(max_length=1000, null=True)
textbook_image = models.FileField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def get_absolute_url(self):
return reverse('textbooks:detail', kwargs={'pk': self.pk})
def __str__(self):
return self.title
I used Custom template tag
class CustomTag(template.Node):
def render(self, context):
context['my_custom_tag_context'] = Textbooks.objects.filter(owner=self.user.request).count()
return ''
#register.tag(name='get_custom_tag')
def get_custom_tag(parser, token):
return CustomTag()
enter image description here
AttributeError at /
'CustomTag' object has no attribute 'user'. It seems that i cant use filter in template tag.
is there any other way i can filter them and show the count by owner who is logged in?
Here is what i intend to have.
enter image description here
You have to change below line in...
user = context['request'].user
context['my_custom_tag_context'] = Textbooks.objects.filter(owner=user).count()
instead of
context['my_custom_tag_context'] = Textbooks.objects.filter(owner=self.user.request).count()
You can get user from request.

Django ModelForm ForeignKey query

I want to have a form which only offers the user to post a question for a project he is participating in.
models.py:
class Project(models.Model):
project_name = models.CharField(max_length=255, unique=True, blank=False)
def __str__(self):
return str(self.project_name)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
project = models.ManyToManyField(Project)
def __str__(self):
return str(self.user)
class Question(models.Model):
title = models.CharField(max_length=255, blank=False)
content = tinymce_models.HTMLField(blank=False)
author = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
...
def __str__(self):
return str(self.title)
class QuestionForm(ModelForm):
class Meta:
model = Question
fields = ['title', 'content', 'project']
in views.py:
form = QuestionForm()
form.fields["project"].queryset = Project.objects.filter(project_name__in=request.user.profile.project.all())
But somehow the result of the query always stays empty.
Does somebody maybe have an idea what I am missing?
Your query is over complicated. You should just use the user's projects directly:
form.fields["project"].queryset = request.user.profile.project.all())

Categories