marwan h-sleiman
marwan h-sleiman

Reputation: 505

Access field from a related UserProfile model

I am having some trouble in selecting data in Django.

models.py

class Location(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    my_location = models.CharField(max_length=120, choices=LOCATION_CHOICES)
    update_date = models.DateField(auto_now=True, null=True)
    date = models.DateField()


def __str__(self):
    return self.my_location

class UserProfile(models.Model):
    user = models.ForeignKey(User)
    user_base = models.CharField(max_length=120, choices=LOCATION_CHOICES)
    user_position = models.CharField(max_length=120)
    user_phone = models.PositiveIntegerField()
    slug = models.SlugField()

def save(self, *args, **kwargs):
    self.slug = slugify(self.user)
    super(UserProfile, self).save(*args, **kwargs)

def __unicode__(self):
    return self.user.username

views.py

def index(request):
    locations = Location.objects.order_by('-update_date')
    context = {'locations': locations}
    return render(request, 'index.html', context)

I was able to show the email from User module but what I really want to show is the data from UserProfile.

Please, any advice.

Thank you.

Upvotes: 1

Views: 66

Answers (2)

bakkal
bakkal

Reputation: 55448

Use a OneToOneField

To make it more direct, I'd make the UserProfile have a OneToOneField relationship with User, instead of a ForeignKey. Because this will mean that a given user can only have one profile.

class Location(models.Model):
    user = models.OneToOneField(User)

In which case you can access it easier with location.user.userprofile.your_field

Using a custom MyUser model

If you want to make this even more direct, you could make a custom MyUser model that will contain both the fields from User and UserProfile.

It would go roughly like this:

from django.contrib.auth.models import AbstractBaseUser
class MyUser(AbstractBaseUser):
    # Adding your custom fields
    user_base = models.CharField(max_length=120, choices=LOCATION_CHOICES)
    user_position = models.CharField(max_length=120)
    user_phone = models.CharField(max_length=120)
    slug = models.SlugField()

class Location(models.Model)
    user = OneToOneField(MyUser) # Using your custom MyUser model

This allows a more direct access, e.g. location.user.user_phone instead of location.user.userprofile.user_phone

I've only provided pseudocode, please refer to Django documentation

Using a ForeignKey means you may have multiple profiles

In the other case where a user may have multiple user profiles, you then have the burden on you to select which profile to use to pull the relevant data from, because then the relationship would be user.userprofile_set, a set that you will have to filter/index to choose from.

Upvotes: 0

Andrea Corbellini
Andrea Corbellini

Reputation: 17761

Instead of using

user = models.ForeignKey(User)

use:

user = models.OneToOneField(User)

One-to-one relationships suit better your case. If you use them, your User model will automatically get a userprofile attribute that you can use like this:

>>> user = User.objects.get(...)
>>> user.userprofile.user_phone
12345

You can also consider writing a custom User model, so that you can get rid of UserProfile.


Bonus tip: PositiveIntegerField is not the right field for a phone number. Leading zeroes have a meaning. Also, PositiveIntegerField have a maximum value. Use CharField instead.

Upvotes: 1

Related Questions