Foreign Key Relations between 2 apps and User model - django

I have one app in which a model extends the User mode.
class ExtendedUser (models.Model):
user = models.ForeignKey(User)
favorite_color = models.CharField(...
#...
I have another app that also has a foreignkey with the user model.
I wanted to know how can I access all the information related to a particular user?
My problem comes when I try to make inverse relationships (I think), here is what I try:
>>from django.contrib.auth.models import User
>>from firstapp.models import ExtendedUser
>>a = User.objects.get(pk=1)
>>a
<User: username1>
>>b = a.favorite_color
AttributeError: 'User' object has no attribute 'favorite_color'
>>c = ExtendedUser.objects.get(pk=1)
>>c
<User: username1>
>>c.favorite_color
<Favorite_color: blue>
The problem is when I am on "a" I cannot access the extended model information on the user, such as "favorite_color", and when I am on "c" I cannot access the User model native info such as email or perms. Is there a way to do this?
And also,
Is there a way where I can pick one user id and see all the fields (from all models and apps) that are related to that object?

But this isn't "extending the user model" at all. You have a reference to a completely different model, via a ForeignKey. I don't know why you'd expect favorite_color to suddenly become an attribute on the User model.
Instead of a ForeignKey (which implies many ExtendedUsers for each User), use a OneToOneField. Then you can follow the relationship directly:
user = User.objects.get(pk=1)
print user.extendeduser.favorite_color

Related

How do I set a default user for blog posts in Django?

My Blog model has a User field like following:
from django.contrib.auth.models import User
class Blog:
author = models.ForeignKey(User, on_delete = models.CASCADE, related_name='blog', default=User('monty'))
This works as in I can see 'monty' set as a default user in the admin interface when I create a blog post. However, when I make migrations, I get the following error:
ValueError: Cannot serialize: <User: >
There are some values Django cannot serialize into migration files.
I also tried this:
default=User.objects.filter(username='monty'))
and that returns a slightly different error when I make migrations:
ValueError: Cannot serialize: <User: monty>
There are some values Django cannot serialize into migration files.
Does anyone know how to get past this error?
You can make a callable that determines the User object, so:
from django.conf import settings
from django.contrib.auth import get_user_model
def get_monty():
if get_monty.user:
return user
user, __ = get_user_model().get_or_create(username='monty')
get_monty.user = user
return user
get_monty.user = None
class Blog(models.Model):
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='blog',
default=get_monty
)
That being said, I think it makes no sense to specify a default here. Your views can determine the logged in user and set that as the author. By using a default you likely will eventually end up with some Posts for which the view did not implement the logic, and are thus all assigned to monty, it
thus will silence an error that probably should not be silenced.
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.

Django getting superuser to use in a model class

I want to get all users information to set up user profiles including superuser, but somehow my code doesn't get superuser data . Please have a look
from django.contrib.auth.models import User
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
as per the docs, Instead of referring to User directly, you should reference the user model using django.contrib.auth.get_user_model(). This method will return the currently active user model – the custom user model if one is specified, or User otherwise. So use User = get_user_model() or settings.AUTH_USER_MODEL if you a custom user

Difference between get_user_model() and importing User from auth

When I need to use the current user in a model.
lets say I have a model with a current_user field, something like:
class MyModel(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,default=None)
my understanding is User can be fetched either:
1)by importing the current user:
from django.contrib.auth.models import User
or
2) setting User to:
from django.contrib.auth import get_user_model
User = get_user_model()
I understand both will work if I am not wrong!!
So What is the main difference between those two methods if there is any?
Thanks
If you are using the default User model, both approaches will work.
However if you are using a custom user model (or are writing a reusable app), then you should use get_user_model() to ensure you get the correct model.
Note that the docs suggest you use settings.AUTH_USER_MODEL in foreign keys.
class MyModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default=None)

Django models: database design for user and follower

In Django model I am making a table 'followers', which has:
user's id. (this is followed by)
user's id (this is follower)
that's simple a user can follow other users.
How should I define the model in Django?
I tried this, but does not work:
user = models.ForeignKey('self')
follower_id = models.ForeignKey('self')
How should this be done?
thanks
The 'self' argument won't work unless you have a model called self.
Assuming that your assignment model is called Following, and you're using the built in User model then you can do:
class Following(models.Model):
target = models.ForeignKey('User', related_name='followers')
follower = models.ForeignKey('User', related_name='targets')
This will likely need some further uniqueness and validation logic.
Note the related_name attribute, see https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_name. This means that for a given user object you can do user.targets.all() to get users they follow, and user.followers.all() to get users who follow them.
Note also that Django returns target model instances, not IDs, in the ORM. This means that even though the underlying table may be called follower_id, in the python code following.follower will return an actual User object.
Seeing as Following is actually the through table for the many-to-many relationship between Users. I would create a Profile model which extends the Django User model, and then declare the many-to-many relationship (using ManyToManyField).
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
following = models.ManyToManyField(User, related_name='followers')
Use the many to many field.
followers = models.ManyToManyField('self', symmetrical=False)

Django get the value of foreignId from django.contrib.auth.models User

I have created a model which has foreign key to the django.contrib.auth.models User model. I need to retrieve the value the foreign key is referring to. But how to do that?
E.g. my model is
from django.contrib.auth.models import User
def FooModel(models.Model):
user = models.ForeignKey(User)
then I know I can either use:
FooModel.objects.get() or FooModel.objects.filter() but as far as I know they will only return entries from the FooModel only. So how do I retrieve from the User model?
m = FooModel.objects.get(id=123434)
m.user.username
You can use ..That wxample will return you the username of the related user. Also you can create joins using __ on the query filtering. Like:
FooModel.objects.get(user__username='Foo')
But, since you are building your query on FooModel, you will always get FooModel results. So you have you use . to use foreignkey relations to get to the required User field.
EDIT:
Django also allows you to use reverse relations on querysets, so even though User model do not have a foreignkey to FooModel on its model structure, you can use reverse relation of Foomodel.user foreignkey like:
def FooModel(models.Model):
user = models.ForeignKey(User)
foofield = Models.CharField(...)
User.objects.get(foomodel__foofield='Beatles')
will return you the user which have FooModel record with a foreign key to his User record and foofield value of Beatles
You can access foreign key ids by referencing the property name + _id. For example: yourmodel.user_id