0

I want access User model's first_name, last_name and email fields from UserProfile as if they were UserProfile's own fields.

class Person(models.Model):
    user = models.OneToOneField(User)
    name = #ModelField which refers to user.first_name
    surname = #ModelField which refers to user.last_name
    email = #ModelField which refers to user.email
    birth_date = models.DateField(null=True, blank=True)
    #and other fields

I could use independent name, surname, email, fields but it would have caused data duplication with User fields.

upd

I want name, surname and email to be of some Field type (as birth_date) and modification of these fields to equal modification of corresponding User fields (property behavior shown below). I need this because I want these three fields to be edible in admin interface or to be prcocessed equally with "native" fields in ModelForm for example.

upd solution. Not very fancy, but here how it worked for me:

class Person(models.Model):
    user = models.OneToOneField(User)
    #and also some char, text fields

    @property
    def name(self):
        return self.user.first_name
    @name.setter
    def name(self, value):
        self.user.first_name = value

    #and by analogy surname and email properties


class PersonForm(ModelForm):
    class Meta:
        model = Person
        exclude = ('user',)

    name = forms.CharField(max_length=100, required=False)
    surname = forms.CharField(max_length=100, required=False)
    email = forms.EmailField(required=False)

    #no make fields filled with User data on form load
    def __init__(self, *args, **kwargs):
    if 'instance' in kwargs:
        instance = kwargs['instance']
        initial = kwargs.get('initial', {})
        initial['name'] = instance.name
        initial['surname'] = instance.surname
        initial['email'] = instance.email
        kwargs['initial'] = initial
    super(PersonForm, self).__init__(*args, **kwargs)

    # to save form data to User model when commit
    def save(self, commit=True):
        instance = super(PersonForm, self).save(commit)  
        user = instance.user
        user.first_name = self.cleaned_data['name']
        user.last_name = self.cleaned_data['surname']
        user.email = self.cleaned_data['email']
        user.save()
        return instance

class PersonAdmin(admin.ModelAdmin):
    fields = ['name', 'surname', 'email', 'and_others']

    form = PersonForm

admin.site.register(Person, PersonAdmin)
Sashko Lykhenko
  • 1,554
  • 4
  • 20
  • 36
  • 1
    The very simplest way to allow changes to the related User in the context of a Person admin is to add an inline to the Person ModelAdmin. It's not a perfect solution, but the other solutions aren't simple. See: https://docs.djangoproject.com/en/1.7/ref/contrib/admin/#inlinemodeladmin-objects – dylrei Jan 13 '15 at 17:09

2 Answers2

1
class Person(models.Model):
    user = models.OneToOneField(User)
    @property
    def name(self):
        return self.user.first_name
    @property
    def surname(self):
        return self.user.last_name
dylrei
  • 1,728
  • 10
  • 13
1

If want you want is to access user.first_name, user.last_name, etc... directly as attributes of Person, you can add a name, surname, etc... properties to Person model, instead of fields:

class Person(models.Model):
    user = models.OneToOneField(User)
    birth_date = models.DateField(null=True, blank=True)
    #and other fields

    @property
    def name(self):
        return self.user.first_name

    @property
    def surname(self):
        return self.user.last_name
    ....
suselrd
  • 734
  • 4
  • 10
  • I like this option, but I am not sure whether `name` will be present in edit form of admin interface for example – Sashko Lykhenko Jan 13 '15 at 16:42
  • @СашкоЛихенко It won't be editible in admin if it's a property, but that's not what you asked for. – dylrei Jan 13 '15 at 16:45
  • My fault. I shall specify what i ment by "as if they were UserProfile's own fields" – Sashko Lykhenko Jan 13 '15 at 16:47
  • 2
    if you want to edit that info through admin site, you have to redefine the 'form' to be used by the corresponding ModelAdmin, adding form fields for that data, and overwriting form's save method, so that info gets saved into the related User. – suselrd Jan 13 '15 at 16:51