Django maintain order of internal query in external query? - python

I have a profile model which refers to the default User model of Django. I want a list of users with increasing points.
My Profile Model:
class Profile(models.Model):
username = models.ForeignKey(User, on_delete=None, primary_key=True)
image = models.CharField(max_length=255, default="")
points = models.IntegerField(default=0)
views = models.IntegerField(default=0)
def __str__(self):
return self.username.username
I am firing this query:
users = User.objects.filter(username__in=Profile.objects.filter().order_by('-points').values('username__username'))
print(users,Profile.objects.filter().order_by('-points').values_list('username__username'))
And my output is
<QuerySet [<User: aplha>, <User: baqir>, <User: beta>]> <QuerySet [{'username__username': 'beta'}, {'username__username': 'baqir'}, {'username__username': 'aplha'}]>
Now here we see, Profile model is giving the usernames in the same order that I want to, but the user model is not maintain that order. How to I make it maintain the same order as the Profile returns.

How about this:
from django.db.models import Sum
users = User.objects.annotate(points=Sum('profile__points')).order_by('-points')
This is untested but I hope it helps!

When you use _in, there is not guarantee of the order of the results.
You could fetch the list of users by looping through the profiles. If you use select_related() then you will avoid extra queries to fetch each user.
profiles = Profile.objects.filter().order_by('-points').select_related('username')
users = [p.username for p in profiles]
Note that it might be better to rename the foreign username foreign key to user, since following the foreign key returns a User instance, not the username string.

Related

get person id through authenticated user id

I try to get person id of my Person model, connected with User model
from django.db import models
from django.contrib.auth.models import User
class Person(models.Model):
user = models.ForeignKey(User, blank=False, null=False, on_delete=models.CASCADE)
middle_name = models.CharField(max_length=30)
def __str__(self):
return '%s %s %s' % (self.user.last_name, self.user.first_name, self.middle_name)
from template-generated page, but I only can get user id who authenticated right now
{{ user.id }}
but not Person id.
How can I get Person id through user id on the page?
django automatic reverse lookup foreign key (user field) from an model, if you want to get person id try this {{user.person.id}}
I suggest OneToOneField for this kind of relation.
user = models.OneToOneField(User, blank=False, null=False, on_delete=models.CASCADE)
then you can use user.person
I think you are having logical issue with your model. One person generally should have connected with one user so you should user OneToOneField instead of ForeignKey. Let's think you are correct then you can follow the code below, if you are not then it will work too.
You can get it through context variable
Suppose your person=Person.obejcts.get(id=1)
Then pass it through context in view like
def view(request):
person=Person.obejcts.get(id=1)
context = { 'person':person}
return render(request, 'your.html', context}
And in template you can use {{person.id}}
You can simply do {{ user.person_set.get(pk=1) }} . This assumes you know the pk...if you only actually store 1 person with 1 user, then substitute the .get() with a .first() ...you can access your foreign key model using the main_obj.fk_obj_set.all() and do things just like any other queryset. This obviously assumes you have multiple users for 1 person..otherwise things get easier with a 1:1 field.

How to retrieve value from one to one field tables in Django?

I have used two models and a django built in User model.
class UserInfo(models.Model):
user = models.OneToOneField(User)
user_contact = models.CharField()
age = models.IntegerField()
class Review(models.Model):
user = models.ForeignKey('exam.UserInfo')
is_reviewed= models.BooleanField()
The UserInfo field is one to one with the User model. User model have the 'username' field that I want to retrieve. But I can't get through how to get the username of those users who have is_reviewed field is 0. So far what I was trying but failed to retrieve:
result=Review.objects.select_related('user_id__id').filter(is_reviewed=0)
You don't necessarily need select_related, that's a performance tuning tool. If you want Review model instances, just make your query and retrieve related values from that as normal:
result = Review.objects.filter(is_reviewed=False)
Then the name is available with dotted lookups, eg:
result[0].user.user.username
These will make further queries - select_related helps you tune whether or not to prefetch those.
If you just want the usernames, you can use a values or values_list query, eg:
usernames = Review.objects.filter(is_reviewed=False).values_list('user__user__username', flat=True)

Building a django queryset over foreign key and onetoone

I have some two models (in different apps/models.py files) related with User:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=False)
...
class CourseStudent(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
semester = models.ForeignKey(Semester)
...
I am trying to get a queryset of all profiles that have at least one course in the current semester.
How can I generate a queryset of profiles, where profile.user has at least one CourseStudent instance, and filtered so that coursestudent.semester=current_semester?
Since a student may have multiple courses in the semester, the duplicates also need to be removed (unique profiles only in the queryset)
EDIT: I am using postgresql and trying to figure out if I need to use distinct with an argument.
Not tested. Maybe you should try
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=False)
...
class CourseStudent(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="course_student")
semester = models.ForeignKey(Semester)
Profile.objects.filter("what_you_want").exclude(user__courser_student=None).distinct()

Filtering Django admin console rows based on the logged-in user

I want to restrict which rows appear in the Django admin console based on the user that is logged in. Using the AuthUser model, I have created the following Account model which links Django user accounts to specific businesses in my database:
class Account(models.Model):
id = models.AutoField(primary_key=True, editable=False)
username_id = models.ForeignKey('AuthUser', db_column='username_id')
business_id = models.ForeignKey('Business', db_column='business_id')
Here is my Business model:
class Business(models.Model):
id = models.AutoField(primary_key=True, editable=False)
name = models.CharField(max_length=45)
address = models.CharField(max_length=45)
When the user logs in, I want to restrict the user so they can only add/view/delete entries into/from my database (through the Django admin console) for their respective business. Here is my Entry model:
class Entry(models.Model):
id = models.AutoField(primary_key=True, editable=False)
business = models.ForeignKey('Business')
entry_text = models.CharField(max_length=300)
created = models.DateField(auto_now=True)
Is there an easy way to get this accomplished?
In your model admin, you could override the method get_queryset().
So you could do something like,
class EntryAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(EntryAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(business__in=request.user.account_set.all().values_list('business_id', flat=True))
The last line, qs.filter(business__in=request.user.account_set.all().values_list('business_id', flat=True)), filters the initial queryset(which defaults to all entries).
request.user.account_set.all() returns all the Account objects associated with the user. Yes, the way you design your Account model will allow multiple objects to be associated to a User. If you want to limit it to one, you should consider using OneToOneField.
Appending .values_list('business_id', flat=True) to the queryset is telling Django that you only want specific columns to be returned, in this case just the business_id column. values_list returns a list of tuples but if you only need one column from the queryset, you can pass the keyword argument flat=True which will return a flat list.

Django Rest Framework not saving foreign key for a small number of requests

I am using Django Rest Framework to provide API to a mobile app. I have two models, Order and User. Order has a foreign key relation to User.
For about 1% or so of all my order objects, the User field is null. I've been testing this behavior using cURL.
If I do a cURL without a user object, it tells me "This field is required".
If done with a wrong user object, it tells me that the object does not exist. Both of these are the intended and expected behaviors.
I'm trying to figure out how it is possible for some of the Order objects to be saved without a user field. Is there something I'm not taking into account?
My views:
class OrderList (generics.ListCreateAPIView):
model = Order
serializer_class = OrderSerializer
And serializer:
class OrderSerializer (serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field = 'user')
partial = True
class Meta:
model = Order
Models:
class User (models.Model):
uid = models.CharField(max_length =200, unique=True)
class Order (models.Model):
uid = models.ForeignKey (User, related_name = "orders", verbose_name = "User",blank=True, null=True)
You could use two different ModelSerializer classes, one for creation, that makes sure, that an Order object can't be created without a related User and one for updating orders, that passes required=False to the related field's constructor, so that you still can save existing orders that haven't a related User.
Try adding default=None to your models.ForeignKey declaration. You could also just create an anonymous user in the users table and when the user isn't specified it could set the anonymous user instead.

Categories