2

I have overridden AdminModel's ModelForm to make User fields edible and savable from Person's admin change form.

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

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

    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)

However I am struggling with writing a test that checks save() method:

def test_form_saves_values_to_instance_user_on_save(self):
    """
    test that, form saves name, surname, email values to corresponding User
    when commiting form
    """
    user = User.objects.get(username='admin')
    person = Person.objects.get(user=user)
    personform = PersonForm(instance=person, data={'name': 'has_changed'})

    # if uncommented raisesValueError: The Person could not be changed
    # because the data didn't validate.
    # personform.save()

    self.assertEquals("has_changed", User.objects.get(pk=user.pk).first_name)

upd test

upd solution. It turned out that I had unfilled requested invisible field 'user'. Exclusion made form valid and test passing.

admin.py

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

tests.py

def test_form_saves_values_to_instance_user_on_save(self):
    """
    test that, form saves name, surname, email values to corresponding User
    when commiting form
    """

    person = Person.objects.get(user__username='admin')
    personform = PersonForm(instance=person, data={'name': 'has_changed'})

    if personform.is_valid():
        person = personform.save()
        self.assertEquals(User.objects.get(pk=person.user.pk).first_name, "has_changed")
    else:
        self.fail("personform not valid")
Sashko Lykhenko
  • 1,554
  • 4
  • 20
  • 36

2 Answers2

2
def test_form_saves_values_to_instance_user_on_save(self):
    """
    test form saves name, surname, email values to corresponding User object
    when commiting form
    """
    person = Person.objects.get(user__username='admin')
    personform = PersonForm(instance=person, data={'name': 'has_changed'})

    if personform.is_valid():
        person = personform.save()
        self.assertEquals(person.user.first_name, "has_changed")
    else:
        self.fail("personform not valid")

I think you also need to exclude the user field from your form

class PersonForm(ModelForm):
    class Meta:
        model = Person
        exclude = ('user',)
    ...
Anentropic
  • 32,188
  • 12
  • 99
  • 147
1

Pass the new data as a dictionary to your form (as first positional argument or as data), and assert that personform.cleaned_data['name'] is equal to User.objects.get(pk=user.pk).username. Then do the same for surname and email.

Note that first_name and last_name have a max_length of 30, while your form fields have a max_length of 100.

knbk
  • 52,111
  • 9
  • 124
  • 122