Efficient way to implement newsfeed - python

I am trying to build a simple social network.
Say I have two models: Status and my custom UserProfile model to implement followers/followings feature:
from django.contrib.auth.models import User
class Status(models.Model):
user = models.ForeignKey(User, related_name='statuses')
title = models.CharField(max_length=50)
status = models.TextField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Status"
verbose_name_plural = "Statuses"
ordering = ('-created',)
get_latest_by = 'created'
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
followings = models.ManyToManyField(
'self', related_name='followers', symmetrical=False, blank=True)
What is the most efficient way to access newsfeed i.e. recent statuses of all of my(User) followings?
I am new to Django. Any help will be much appreciated.

Simply filter Status queryset by users that you are following. Query above will show all statuses for all users followed by user.
Status.objects.filter(user__followers=user)

Related

How to get a list of objects using several model relationships in Django?

I would like to get a list of UserProfile of a user's followers
I have the following models :
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=16, unique=True, db_index=True)
# ...
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE)
# ...
class UserFollow(models.Model):
follower = models.ForeignKey(User, related_name="follow_follower", on_delete=models.CASCADE)
following = models.ForeignKey(User, related_name="follow_following", on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True, editable=False)
# ...
How can I accomplish this while optimizing database queries ?
I use rest framework.
If I understand correctly, given a username of a user (say user1), you want to retrieve all the userprofiles from the users following user1, right?
Whereas I do not think this is possible with a one-liner, I think the following should to the trick:
followers = UserFollow.objects.filter(following__username=username).values('follower')
follower_profiles = UserProfile.objects.filter(user__in=followers)
I saw your message, you want : follower_profiles = User.objects.get(username=username).follow_following.all().follower.profile
You should want this.
query_set = User.objects.get(username='username').follow_follower.select_related('follower__profile').all().follower.profile
for query in query_set.all():
print(query.follower.user) # Here is the model for UserProfile.

How to make a serializer for multiple users (student & teacher)?

Hello I am very new to Django Rest Framework and I am having a hard time with the serializer. I extended the User Model using Abstract User. I inserted two new fields which are is_student and is_teacher then I set both of the values to false as default. I then put them in there own model then just applied a one-to-one relation for each of them to the user model. My problem is with the serializer. How do I make a serializer out of this. I want the student and teacher have relation with the user model as well as having the ability to do http actions such as get, post, put, etc.
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.conf import settings
# Create your models here.
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class Course(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
price = models.FloatField()
def __str__(self):
return self.name
class Student(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
age = models.IntegerField()
address = models.CharField(max_length=200)
def __str__(self):
return self.user.username
class Teacher(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
description = models.TextField()
course_teaching = models.ForeignKey(Course, on_delete=models.CASCADE)
students = models.ManyToManyField(Student)
def __str__(self):
return self.user.username
Check out an example of this type of serializer here: https://github.com/imagineai/create-django-app/blob/master/todoapp/serializers.py

Django: Making a value in a model unique specific to a user

I have a model for a project:
class Project(models.Model):
name = models.CharField(max_length=200, unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
I want to make the project name a unique value per user but at the moment if user 1 creates a name of "project 1" then user 2 is unable use that project name.
What is the best way to go about this?
Thanks!
unique_together is probably what you are looking for.
class Project(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
unique_together = (('name', 'user'),)

filter by is_active boolean field in django

I want to have an is_active field for all the models in my application and when ever I create an api, I want to filter only the active ones and send the response. Is there a generic way to do this? As of now I am keeping a boolean field is_active and every time I retrieve the objects, I am writing a filter. below is the code :
My models.py
class Crew(models.Model):
crew_id = models.AutoField(primary_key=True)
crew_code = models.CharField(max_length=200, null=False, unique=True)
crew_name = models.CharField(max_length=200, null=False)
crew_password = models.CharField(max_length=200, null=False)
is_active = models.BooleanField(default=True)
My views.py :
#api_view(['GET'])
def get_crews(request):
c = Crew.objects.filter(is_active=True)
serializer = CrewSerializer(c, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
You can write custom model manager:
class IsActiveManager(models.Manager):
def get_queryset(self):
return super(IsActiveManager, self).get_queryset().filter(is_active=True)
class Crew(models.Model):
...
objects = IsActiveManager()
Now Crew.objects.all() will return only is_active record.
You can write a mixin in mixin.py file something like this
class TimeFieldsMixin(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True, db_index=True)
class Meta:
abstract = True
And Import this in your models like this:
class User(TimeFieldsMixin):
// model fields
This will add this fields by default wherever you use this mixin.
Let me know if this is not clear.
Please note that if you have additional Model Managers:
The first manager listed in the model class definition is the one that is used for the admin site and a number of other operations.

Django REST Framework: change field names

My Django application provides readonly api access to the users of the site. I created a user profile model and use it in the serializer of the user model:
Model:
# + standard User Model
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
display_name = models.CharField(max_length=20, blank=True)
Serializer:
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserProfile
fields = ('display_name',)
class UserSerializer(serializers.HyperlinkedModelSerializer):
userprofile_set = UserProfileSerializer(many=False, label='userprofile')
class Meta:
model = User
fields = ('id', 'username', 'userprofile_set')
This works but the field userprofile_set looks ugly. Is it possible to change the field name?
To complement your answer, you can also make use of relationships' related names:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profiles')
display_name = models.CharField(max_length=20, blank=True)
that way you can also use this in your code:
user = User.objects.last() #some user
user.profiles.all() #UserProfiles related to this user, in a queryset
user.profiles.last() #the last UserProfile instance related to this user.
May I recommend that you turn that ForeignKey into a OneToOneField? that way an user can have one and just one user profile, and you don't need to establish uniqueness:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
display_name = models.CharField(max_length=20, blank=True)
Oh, I can name the variable userprofile_set as I like. First I tested the name userprofile which conflicted. If I name the field profile it works. :)
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = UserProfileSerializer(many=False, label='userprofile')
class Meta:
model = User
fields = ('id', 'username', 'profile')

Categories