So I have a social media app, where users can like the posts of other users. Now I want to fetch the top 20 users who have received the most number of likes. I am pretty much confused how to query my Likes Model
My LIKES MODEL
class PostLike(models.Model):
user_who_liked = models.ForeignKey(User, on_delete=models.CASCADE)
post_liked = models.ForeignKey(Post, on_delete=models.CASCADE)
liked_on = models.DateTimeField(default=timezone.now)
SIMPLIFIED POST MODEL
class Post(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
caption = models.TextField()
date = models.DateTimeField(default=timezone.now)
likes = models.ManyToManyField(
User, blank=True, through=PostLike)
image = models.TextField()
class Meta:
ordering = ['-id']
SIMPLIFIED USER MODEL
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
user_name = models.CharField(max_length=100, unique=True)
date = models.DateTimeField(default=timezone.now)
profile_picture = models.TextField(
default="https://www.kindpng.com/picc/m/24-248253_user-profile-default-image-png-clipart-png-download.png")
bio = models.CharField(max_length=200, default="")
objects = CustomManger()
def __str__(self):
return self.user_name
** My View **
#api_view(["GET"])
#permission_classes([IsAuthenticated])
def leaderboard(request):
# I dont know how to query the PostLike model now to get the most liked users
pass
First I changed the user attribute in your Post model, I added related_name because otherwise the related names were clashing. This is the definition I used, otherwise your models are unchanged.
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
I.e. the posts by a user are accessible on User via the author attribute.
The following query gives you the top 20 users by number of likes they received:
User.objects.annotate(num_likes=Count('author__likes')).order_by('-num_likes')[:20]
Explanation:
Query User model and
annotate each user by doing a count:
author leads to the posts by the user
likes follows to PostLike and counts all likes which are associated with a post by the user
then order by number of likes descending,
and limit the number of retrieved objects to 20.
Related
I'm doing a cookbook app, which help users find meal thay can do with their ingridients. I'm using Django RestFramework, and i need to return list of avaliable meals that user can do, but don't know how to do search by ingridients
My models.py:
#models.py
class Meal(models.Model):
name = models.CharField(max_length=250)
description = models.TextField(blank=True, null=True)
recipe = models.TextField()
is_published = models.BooleanField(default=False)
category = ForeignKey('Category', on_delete=models.CASCADE, null=True)
user = ForeignKey(User, verbose_name='User', on_delete= models.CASCADE)
difficulty = ForeignKey('Difficulty', on_delete=models.PROTECT, null=True)
ingridients = models.ManyToManyField('Ingridient')
class Ingridient(models.Model):
name = models.CharField(max_length=100, db_index=True)
ico = models.ImageField(upload_to="photos/%Y/%m/%d/", blank=True, null=True)
category = ForeignKey('CategoryIngridients', on_delete=models.CASCADE, null=True)
def __str__(self):
return self.name
class CookBookUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
ingridients = models.ManyToManyField('Ingridient')
serializer.py
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = Meal
fields = "__all__"
views.py
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
return Meal.objects.filter(ingridients=CookBookUser.objects.filter(user_id = self.request.user.id).ingridients)
CraftWithUsersIngridientsListAPIView isn't working and I get AttributeError 'QuerySet' object has no attribute 'ingridients', can someone help fix this?
I tried building different serializer but it doesn't help
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
user_ingredients = CookBookUser.objects.get(user=self.request.user).ingredients.all()
return Meal.objects.filter(ingredients__in=user_ingredients)
This way, you first get the CookBookUser instance for the current user, then get all of their ingredients, and finally, filter the Meal objects that contain those ingredients. The __in query lookup is used to check if the meal ingredients are in the user's ingredients.
This is what message_user_id contains:
message_user_id = Message.objects.all()
This is my context dictionary in admin.py:
'msg' : message_user_id,
This is my Message class in models.py:
class Message(models.Model):
message_text = fields.EncryptedTextField(blank=True, null=True)
conversation_id = models.ForeignKey(Conversation, on_delete=models.CASCADE)
origin_user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, blank=False, default=None)
timestamp = models.DateTimeField(default=datetime.now, blank=True)
This is UserInfo class:
class UserInfo(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
is_buyer = models.BooleanField(default=False)
is_seller = models.BooleanField(default=False)
is_professional = models.BooleanField(default=False)
There are different roles for users that they can choose from while sign up. That information stays in UserInfo table which I'm referencing to as a foreign key in origin_user field in Message class. origin_user in Message contains the same information as id in UserInfo.
I want to display the number of messages sent by each category of users. How do I achieve this?.
As there are not many types you can do a search for each type and count how many messages there are, e.g. for Buyer:
messages_of_buyers = Message.objects.select_related(
'user_info'
).filter(
user_info__is_buyer=True
).count()
I have two class model, the User and Money Request. I am trying to access the data I entered in the User class so that whenever I requested money using the MoneyRequest class, I can also input my entered email, first and last name together with the withdraw_money.
I really need the data from the User class so that whenever I look at the admin page, I can see the name of the user who sent the money request.
Here is my models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=100, unique=True)
first_name = models.CharField(max_length=100, blank=True, null=True)
last_name = models.CharField(max_length=100, blank=True, null=True)
class MoneyRequest(models.Model):
date_requested = models.DateTimeField(auto_now_add=True)
withdraw_money = models.DecimalField(null=True, blank=True, max_digits=8, decimal_places=2, help_text='Minimum withdrawal is ₱300.00.', validators=[minimum_money])
Here is my views for my MoneyRequest class
class UserAccountsView(CreateView):
model = MoneyRequest
fields = ['withdraw_money',] # Keep listing whatever fields
template_name = 'users/accounts.html'
def form_valid(self, form):
user = form.save()
user.save()
return redirect('users:user_account', self.request.user.username)
What should I put in my MoneyRequest class in order to get the data entered in the User class? Thank you!
In your moneyrequest model add
user = models.ForeignKey(User, on_delete=models.CASCADE)
Then you can get all User model data.
I have models of Exercise, Training and Workout.
Training contains some exercises (Exercise)
Workout contains trainings (Training).
Snippet of my models.py:
class Exercise(models.Model):
user = models.ForeignKey(User, related_name='exercises',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.TextField(max_length=300)
details = models.ManyToManyField(ExerciseDetail, blank=True)
...
class Training(models.Model):
user = models.ForeignKey(User, related_name='trainings',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.CharField(max_length=250)
exercises = models.ManyToManyField(Exercise, related_name='trainings',
blank=True)
...
class Workout(models.Model):
user = models.ForeignKey(User, related_name='workouts',
on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=200)
description = models.TextField(max_length=400, blank=True)
trainings = models.ManyToManyField(Training, related_name='workouts',
blank=True)
...
I would like to have possibility to use something like Workout.objects.get(name='workout').exercises.objects.all() to get a list/set of all exercises included in trainings of chosen Workout.
I would also like to have possibility to use exercises`` field with Django Rest Framework to list all exercises, possibly with link to particularExercise``` model serializer.
Can someone give a hint how can I do that?
You can query this with:
Exercise.objects.filter(
trainings__workouts__name='workout'
)
With the consecutive underscores (__), you thus can look "through" relations.
This will thus return the Exercises that belong to Trainings that belong to Workouts with as name 'Workout'.
So i basically have a model called Designations that derives foreign keys from 3 other models (curricula, role and staff) and i am trying to save a new record into the Designations model, the code below shows the Designations and Staffs model. However, for the Curriculum and role models i will not be showing as you can assume PK 1 in Curriula and role models will be used as data in the curriculum and role fields in Designation model
class Designations(models.Model):
designation_id = models.AutoField(primary_key=True)
curriculum = models.ForeignKey(Curricula, on_delete=models.CASCADE)
role = models.ForeignKey(Roles, on_delete=models.CASCADE)
staff = models.ForeignKey(Staffs, on_delete=models.CASCADE)
class Meta:
db_table = "arc_designations"
unique_together = ('curriculum', 'role', 'staff')
verbose_name_plural = "Designations"
ordering = ['designation_id']
def __str__(self):
return '%s of %s %s (%s)' % (self.role.role_name,
self.curriculum.course_period.course.course_abbreviation,
self.curriculum.module_period.module.module_abbreviation,
self.staff.staff_full_name)
class Staffs(models.Model):
staff_id = models.AutoField(primary_key=True)
admission_number = models.CharField(max_length=5,
unique=True,
help_text="Enter 5 digits",
validators=[numeric_only, MinLengthValidator(5)])
staff_full_name = models.CharField(max_length=70,
help_text="Enter staff's full name",
validators=[letters_only])
created_by = UserForeignKey(auto_user_add=True,
editable=False,
related_name="staff_created_by",
db_column="created_by")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_by = UserForeignKey(auto_user=True,
editable=False,
related_name="staff_updated_by",
db_column="updated_by")
updated_at = models.DateTimeField(auto_now=True,
editable=False)
roles = models.ManyToManyField(Roles, through='Designations')
class Meta:
db_table = "arc_staffs"
verbose_name_plural = "Staffs"
ordering = ['staff_id']
def __str__(self):
return '%s (S%s)' % (self.staff_full_name, self.admission_number)
I have made a forms.py to get the admission_number(field in Staffs model)
class AssignRolesForm(forms.Form):
admission_no = forms.CharField(max_length=40,
widget=forms.TextInput(
attrs={'class': 'form-control', 'aria-describedby': 'add-btn'}))
Assuming that when i submit the form i would like for the admission_number entered in the form to reference into the Staffs model then get its PK to be saved into the staff field in Designations then as i said above, for the curriculum and role fields to referece PK 1 of their respective models. How would i write my function in views.py
**edit
I've tried writing out the view as suggested, heres the code below, currently i cant test my project so let me now if its correct
#require_POST
def setStaff(request):
form = AssignRolesForm(request.POST)
if form.is_valid():
Designations.staff = Staffs.objects.filter(admission_number=form.cleaned_data['admission_no'])
Designations.role = Roles.objects.get(pk=1)
Designations.curriculum = Curricula.objects.get(pk=1)
Designations.save()
return redirect('index')
Overriding the clean function on forms is probably where you want to put your logic. The django docs have a good example:
https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other