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.
Related
What i want:
Store information about running of group of people.
What i did:
from django.db import models
from django.contrib.auth.models import User
from datetime import timedelta
class Route(models.Model):
name = models.CharField(max_length=50)
class Run(models.Model):
date = models.DateField()
type = models.ForeignKey(Route, on_delete=models.PROTECT)
runners = models.ManyToManyField(User, through='RunnerResult', through_fields=["user", "run"])
class RunnerResult(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
run = models.ForeignKey('Run', on_delete=models.PROTECT)
result = models.DurationField(default=timedelta())
Problem:
When i do makemigrations i have the following error:
SystemCheckError: System check identified some issues:
ERRORS:
run.Run.runners: (fields.E339) 'RunnerResult.run' is not a foreign key to 'User'.
HINT: Did you mean one of the following foreign keys to 'User': user?
run.Run.runners: (fields.E339) 'RunnerResult.user' is not a foreign key to 'Run'.
HINT: Did you mean one of the following foreign keys to 'Run': run?
Tried to swap through_fields and models between each other and some other actions. I'm starting to think of my misunderstanding of M2M relationship.
You specified the through_fields in the wrong order. You first should specify the relation that refers to the source, and then then one to the target, so:
class Run(models.Model):
date = models.DateField()
type = models.ForeignKey(Route, on_delete=models.PROTECT)
runners = models.ManyToManyField(
User,
through='RunnerResult',
through_fields=('run', 'user')
)
Since there is however only one ForeignKey to Run, and one to User, you do not need to specify the through_fields=… parameter [Django-doc]. So you can implement this as:
class Run(models.Model):
date = models.DateField()
type = models.ForeignKey(Route, on_delete=models.PROTECT)
runners = models.ManyToManyField(
User,
through='RunnerResult'
# no through_fields
)
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
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.
I have two objects, Company and Account, in different packages.
They have a many-to-many relation through employee, which has an additional field is_admin.
In Company I define the relation, and reading online, it seems that I don't have to redifine the relation in Account (this will result in a circular import).
Retrieving all the Accounts from the CompanySerializer is no problem,
but I need to be able to get all the Companies registered to an account as well.
This is my thinking:
Account Model:
class Account(AbstractBaseUser):
current_jobs = models.ManyToManyField(
Company, through='Employee') // I need to define current_jobs in some way
//,but this results in circular import
Company Model:
class Company(models.Model):
employees = models.ManyToManyField(
settings.AUTH_USER_MODEL, through='Employee')
Employee Model:
class Employee(models.Model):
class Meta:
unique_together = ('user', 'company')
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
is_admin = models.BooleanField()
The problem is, how will I now define how to get each of the lists in the serializers of the two.
So the Company Serializer, and the Account Serializer...
If i do not define current_jobs, I get an error stating that current_jobs is not defined, which it ofcourse is not.
I don't understand why you think you need to define current_jobs on Account. That is automatically provided for you via the reverse relationship as company_set; if you need it to be current_jobs you can set the related_name attribute.
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()
I have a django model as follows:
class Subscription(models.Model):
Transaction = models.ManyToManyField(Transaction, blank=True, null=True)
User = models.ForeignKey(User)
...etc...
I am trying to add a ManyToMany field to the User model as follows:
SubUsers = models.ManyToManyField(User, blank=True, null=True)
but I get this error when I run syncdb:
AssertionError: ManyToManyField(<django.db.models.fields.related.ForeignKey object at 0x19ddfd0>) is invalid. First parameter to ManyToManyField must be either a model, a model name, or the string 'self'
If I encase User in quotes, I get instead:
sales.subscription: 'User' has a relation with model User, which has either not been installed or is abstract.
I know the User model is imported correctly. Any ideas why having 2 fields pointing to the User model causes problems? Thanks in advance...
The reason why it fails is because the name of your field is the same as the class name (User). Use lowercase field names, it the standard convention in Django and Python. See Django Coding style
Also, you need to add a related_nameparameter to your relationship:
class Subscription(models.Model):
user = models.ForeignKey(User)
sub_users = models.ManyToManyField(User, blank=True, null=True, related_name="subscriptions")