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

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)

Related

how to get a column value of foreign key in the form of object?

There is 2 models Registration and RegistrationCompletedByUser, I want Registration queryset from RegistrationCompletedByUser with filters(user=request.user, registration__in=some_value, is_completed=True) over RegistrationCompletedByUser. Hence result should be like <QuerySet [<Registration: No name>, <Registration: p2>, <Registration: p-1>]>.
Now what I tried is
Registration.objects.prefetch_related('registrationcompletedbyuser_set') but filters() not working. Another way I tried is model Managers but don't pass parameters for custom filtering.
models.py
class Registration(models.Model):
name=models.CharField(max_length=255)
number=models.SmallIntegerField(null=True, blank=True)
class RegistrationCompletedByUser(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
registration= models.ForeignKey(Registration, on_delete=models.CASCADE)
points = models.SmallIntegerField(default=100)
is_completed = models.BooleanField(default=False)
If I understood this properly, you want to get all Registrations that related to a query instead of a single object.
qs_1 = RegistrationCompletedByUser.objects.filter(user=request.user, is_completed=True).values_list("registration__id", flat=True)
qs_2 = Registration.objects.filter(id__in=qs_1)
As I understood your question is related to django. So actually there is common way to get related query set from another. When you specify ForeignKey to another model actually django automatically creates 'Related Model' + '_set' relation.
I actually didn't get from you question what you are intended to do. In your situation there are many RegistrationCompletedByUser related to one Registration. So what you can do it's to receive all RegistrationCompletedByUser instances from Registration instance by related name for ForeignKey registration of RegistrationCompletedByUser which in your case registration_set. Actually better to specify in RegistrationCompletedByUser model related name as attribute like this:
models.ForeignKey(Registration, on_delete=models.CASCADE,
related_name='registrations')
And after this let's say you have instance of Registration reg1. So to receive queryset of RegistrationCompletedByUser:
reg1.registrations.all()
And you can use filter on it with attributes from Registration model.
And if you want to receive Registration from RegistrationCompletedByUser, again in your case it's just one Registration to many RegistrationCompletedByUser, so let's say we have reg_completed_1, to receive it's only one registration:
reg = reg_completed_1.registration

It is impossible to add a non-nullable field Error when extending Abstract User

I want to extend the Base Abstract User Model and this is the extended model:
class Student(AbstractUser):
birth = models.DateField(default=datetime.date.today)
street = models.CharField(max_length=25)
street_number = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(99)])
city = models.CharField(max_length=20)
province = models.CharField(max_length=20)
code = models.IntegerField(validators=[MinValueValidator(0, MaxValueValidator(9999))])
address = str(street) + str(street_number) + str(city) + str(code) + str(province)
But I get this message popup:
It is impossible to add a non-nullable field 'password' to student without specifying a default. This is because the database needs something to populate existing rows.
However I haven't added a new password field and all the existing password fields (for the superuser) already have a value. What should I do?
When I add a default value and try to migrate it, it complains that there is no such table as 'mainApp_student'.
You don't want to do that. You want a User model (you already have one that Django provides, no need to extend it for now), and a Student model that has a OneToOne relationship with the User model.
Conceptually:
User: models a user of your application and its authentication and permissions
Student: the representation of a person attending classes, with a name, a birthday etc..., also has a user to access your application which is unique to them.
In code:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE))
# ... other fields: birth address etc...
This page of the docs explains it well, especially the Employee example given:
If you wish to store information related to User, you can use a OneToOneField to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user.

Django maintain order of internal query in external query?

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.

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