Django models: Parent model accessing child model field - django

I have the following models
from django.contrib.auth.models import User
User = settings.AUTH_USER_MODEL
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
class Tutor(UserProfile):
# tutor_fields here
From User object how can I access Tutor? is it with user.profile?
user.profile.select_related('tutor') does not seem to work.

OneToOneField work like ForeignKey except unique=True and you don't need to specify the related_name (you can specify if you want to change it).
For you example:
from django.contrib.auth.models import User
User = settings.AUTH_USER_MODEL
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
class Tutor(UserProfile):
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='tutor')
details = models.CharField(max_length=100)
NB: Use a ForeignKey if you want/need one Tutor for many UserProfile, else if you want one (and only one) Tutor for one UserProfile
And you can access to the Tutor bu UserProfile by UserProfile.tutor.details.

As described in the django docs, you should be able to access it with user.user_profile.

Related

Can't use the extended User model

I want to add a department field on my User model. I am using sql server as my db. I did the following in models.py
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, db_column='user')
department = models.CharField(max_length=20, blank=True)
class Meta:
db_table = 'Employee'
Then, using stored procedure I can fill all the fields of User easily, but when I want to fill the extra field department, I get the error
RelatedObjectDoesNotExist at /fetched
User has no employee.
in views.py, where I retrieve the data from procedure:
q = User(id=result_set[i][0], username=result_set[i][1], is_staff=False,
first_name=result_set[i][4], last_name=result_set[i][3], email=result_set[i][8])
q.set_password(result_set[i][2])
q.employee.department = 'something'
q.save()
You can extend the AbstractUser to your model
In models.py
from django.contrib.auth.models import AbstractUser
class Employee(AbstractUser):
department = models.CharField(max_length=20, blank=True)

Django order queryset by OnetoOneField

I have a two models UserProfile and User. The UserProfile model has a onetoone filed with the user. I figured out how to order the UserProfile by a variable it contains. However, I do not know how to order the items in UserProfile by their related User models
class User(AbstractBaseUser):
full_name = models.CharField(max_length=255, blank=True, null=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
lunch_price = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
I can run this query just fine:
from myapp.models import UserProfiles
print(UserProfile.objects.all().order_by('lunch_price')
I thought i'd run something like this to order by full_name, but it doesn't work
from myapp.models import UserProfiles
print(UserProfile.objects.all().order_by('user.full_name')
How do I make that jump to the user model?
You can follow OneToOneFields and other foreign key relations by using a double underscore (__):
UserProfile.objects.all().order_by('user__full_name')
This acts a bit similar to how in Python one usually obtains (chains of) attributes. For example if the User has a OneToOneField to (for example) an Office model, then we can for instance query with user__office__floor to sort the users by the floor where their office is located.
Mind that this only works given we are working with fields. So if you would for instance have a User class with a first_name and a last_name, and you use a #property for the full_name (in other words, the full_name is determined when needed), then this will not work, and you will have to sort at Python level. This is logical, since the database of course does not know anything about the Django ORM layer and hence it can not interpret what this property is doing.

Django: User Profile in 1.9

RELATED: get user profile in django
The above shows how to get user profile but i read that the accepted answer method is deprecated.
How would I create/get/use user profile in django 1.9?
models.py
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
address = models.TextField()
......
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
The above code will create a UserProfile record whenever a new user is created on User table. Then you can access the profile details like,
address = request.user.profile.address
get_profile() method returned additional informations about User. Currently, these informations can be stored in Custom User Model or in a seperate model which is related to User Model. You can do that by simply adding one2one relation with User model to your custom User model, or by subclassing the AbstructUserBase model.
Subclassing User Model example:
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
...
One2One Relation with User model example:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)

How do I save two models related with OneToOne in Django?

Here is my code:
from django.db import models
from django.contrib.auth.models import User
class Person(models.Model):
user = models.OneToOneField(User, primary_key=True)
title = models.CharField(max_length=3, choices=PERSON_TITLE_CHOICES)
first_name = models.CharField(max_length=100)
Basically, what I want to do, is when I am registering a new user, I'd like to save a Person model, already with the relation to the User.
You have two options here. You can either register a post-save hook for User and create your Person there, or you can create them together. I do the latter. Just make sure you wrap them in a transaction so if one fails, the other does also:
with django.db.transaction.commit_on_success():
user = User(...)
user.save()
person = Person(user = user, ...)
person.save()

Get all objects defined by a Django ManyToManyField relationship

The site I'm building allows users to create "posts" and has a Twitter-like concept of followed users. For a given user, I'd like to show all of the posts from the users that they follow.
Here are my simplified models:
class User
# a standard django.contrib.auth user model
class UserProfile(models.Model):
# my AUTH_PROFILE_MODULE for django-profiles
user = models.ForeignKey(User, unique=True)
following = models.ManyToManyField('self', symmetrical=False, related_name="followed_by")
class Posts(models.Model):
user = models.ForeignKey(User)
post = models.TextField()
Question: How do you create a queryset of all Post objects from the Users that a given User is following?
I think I've made it more complicated by creating the "follow" relationship on UserProfile, which is not the model with the ForeignKey relationship with Posts.
UPDATE! Here's the answer:
Posts.objects.filter(user__userprofile__in=UserProfile.objects.get(user=your_user_object).following.all())
Posts.objects.filter(user__in=UserProfile.objects.get(user=your_user_object).following)