1

Right now I'm using Django's built in admin system to manage users, to which I've attached a profile to contain additional data using the following:

class Profile(models.Model):
    user = models.OneToOneField(User, editable = False)
    # Data fields here...

As it stands the User and Profile pk (and accordingly id number) will be the same if and only if the profile is created right after the user is created. I could guarantee that this would be the case during the registration process, and while that would cover most uses, creating users with the admin interface could cause mismatched ids to occur. Thus this does not seem like a very robust way to solve this problem and I'd like to hardcode the pk's to be the same. I'm not sure how to do this.

I thought the following would work:

profile_id = models.IntegerField(default=user.pk, editable = False, 
                                 primary_key = True)

But it gives me the error:

AttributeError: 'OneToOneField' has no attribute 'pk'

What's the best way to guarantee that the profile and user have the same pk? Note: I'd really rather not deal with extending the base user model as using the OneToOneField to link the two seems to be sufficient for all my needs.

Thanks!

[edit]

My reasoning for asking the question:

My immediate problem was that I wanted a dictionary of values of the User's Profile, which I was retrieving usingprofile_values = Profile.objects.filter(pk=user.id).values()[0]. This highlighted the bug, and I "hacked" around it last night using pk=user.profile.id instead. In the light of the morning this does not seem like such a terrible hack. However, it seems like having pk discrepancies could lead to quiet and hard to catch bugs down the line, and thus forcing them to match up would be a Good Idea. But I'm new to Django so I'd entirely accept that it is, in fact, never a problem if you're writing your code correctly. That said, for almost academic reasons, I'd be curious to see how this might be solved.

[/edit]

John Lucas
  • 588
  • 5
  • 20
  • Why do you think you need the pks to be the same? The whole point of the OneToOneField is that it gives you the relationship without having to worry about the pk value. – Daniel Roseman Jun 15 '13 at 09:28
  • @DanielRoseman updated the question with my reasoning. If you think the best answer is that there's no reason to attempt to make them be the same, I'd be happy to accept that if you could elaborate a wee bit. Though, as I said, I am still curious _if_ it is possible even if it's not advisable. – John Lucas Jun 15 '13 at 14:55
  • Here's how another person solved it: http://stackoverflow.com/a/13460819/584846 – Brent Washburne Jun 15 '13 at 17:35

2 Answers2

0

pk is a parameter in a filter() query, but not a field name. You probably want to use user.id.

Brent Washburne
  • 12,904
  • 4
  • 60
  • 82
  • No dice. When I replace user.pk with user.id it give me the same error, with 'id' in place of 'pk'. – John Lucas Jun 14 '13 at 21:59
  • Please show more code. In particular, where 'user' is defined. – Brent Washburne Jun 15 '13 at 05:58
  • I'm using django's built in User model, so I don't define it at all. It's imported from django.contrib.auth.models. I'm not sure how to access that. How should I access that, or would there be other code that would be more helpful? The only other stuff in my Profile model are project specific data fields. – John Lucas Jun 15 '13 at 14:59
0

Like you already agree that it was never a problem because we have a OneToOne mapping between the two models. So when you need to get the profile obj corresponding to a User:

profile_values = Profile.objects.get(user_id=user)

assuming,

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

If your column name is not user, then use the corresponding name in get query.

Still if you are curious as to how to achieve same pk for both models, then we can set a signal on every save of User model. See the documentation.

def create_profile(sender, **kwargs):
    if kwargs["created"]:
        p = Profile(user=kwargs["instance"], ...)
        p.save()
django.db.models.signals.post_save.connect(create_profile, sender=User)

create_profile() will be called every time any User object is saved. In this function, we create Profile object only if a new User instance has been created.

If we start from blank slate, then I think this will always make sure that a Profile exists for every User and is created right after User was created; which in turn will give same pk for both models.

Sudipta
  • 4,773
  • 2
  • 27
  • 42
  • Thanks for the thorough answer. I was aware of signals as a possible solution, but was hoping for something a bit more tightly coupled. However, it looks like signalling is the best solution both because its not really a problem and its tightly coupled enough. – John Lucas Jun 18 '13 at 13:33