I have these models in my models.py
User Model
class User(AbstractBaseUser, PermissionsMixin): """Custom user model""" email = models.EmailField(max_length=255, unique=True) first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) def __str__(self): return '{}'.format(self.email)
UserInfo Model
class UserInfo(models.Model): """User's Info""" user = models.OneToOneField(User, related_name="parent_user", on_delete=models.CASCADE) image = models.ImageField(upload_to=user_image_file_path) age = models.IntegerField() bio = models.CharField(max_length=400) def __str__(self): return '{}'.format(self.user)
My-template
In my template i am passing some filtered User Profiles
(let’s say filtering by age, if age > 25
) now i need to show the name of the user(first_name
) as well but i don’t know how to call a OneToOnefield reversely. Help is really appreciated :).
{% for p in profiles %} <div class="profile-container" style="position: relative"> <div class ="left-div"> <div class="mySlides fade"> <img src="media/{{p.image}}" style="width:100%" id="user-media-img"> <div class="text"> User First Name is : {{`What to type here?`}} </div> </div> </div> <div class="right-div"> <div class="details"> <h1>BIO</h1> <p>{{p.bio}}</p> <h1>Age:</h1> <p>{{p.age}}</p> </div> </div> </div> {% endfor %}
EDIT :
My views.py
:
I am passing a list named profiles which have filtered profiles based on 2-3 different type of filters so the code will be too much to paste here with all the references,
I am pasting short version here:
start =18 end=25 matching = UserInfo.objects.filter( age__gte=start, age__lte=end ).values() for z in matching: if z['user_id'] not in rec_ids: profiles.append(z) print('profiles====', profiles) context = { 'profiles' : profiles, } return render(request, 'home/news.html', context)
Pasting the output here
profiles==== [{'id': 18, 'user_id': 8, 'image': 'uploads/user/image/9d096190-73a0-4885-b4cd-ef6c7229b9eb.png', 'age': 23, 'bio': 'cool'}..etc]
Thanks :)
Advertisement
Answer
As @khadim hussen wrote in the comment you should use the following syntax:
p.user.first_name
Where p
is your UserInfo
model and p.user
is the reference to the OneToOne realationship.
Note that when you don’t have a related user with p -> user the value you will return is None
.
If you want to show different info than None
in your template just can do the following validation:
{% if p.user is not None %} {{p.user}} {% else %} Without User {% endif %}
But in your views yo will get a RelatedObjectDoesNotExists
to ensure in your views that the relationship exists you can make the following validation:
p = UserInfo.objects.first() if hasattr(p, 'user'): user = p.user
Other thing that is important is when you have a related_name property as in your example:
user = models.OneToOneField(User, related_name="parent_user", on_delete=models.CASCADE)
So in this case you need to refer to the user
property with the related_name
.
In a more concrete way you have to do as following:
{{ p.parent_user.first_name }}
One important thing is that if you ar using queryset.filter(...).values()
so if you want to load values from other model you can use the following:
queryset.filter(...).values('image','age','bio','user','parent_user__first_name',...) `` And in your template: ```python {% p.parent_user__first_name %}
That’s it.