Should this be considered a bug? When you provide the to_field_name to a 
ModelChoiceField, the instance object's field (the primary key) will not 
match the form's field (the to_field_name field name).  Therefore the 
has_changed() function will return True.  In my example, I created an app 
called 'app'.

############ app/models.py ###########

from django.conf import settings
from django.db import models


class Account(models.Model):
    """ Each user has an account """
    name = models.CharField(max_length=64)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
    description = models.TextField()



############ app/forms.py ###########

from django import forms
from django.apps import apps
from django.contrib.auth import get_user_model


class AccountForm(forms.ModelForm):

    class Meta:
        model = apps.get_model('app.Account')
        fields = ['user', 'name', 'description']

    user = forms.ModelChoiceField(get_user_model().objects, 
to_field_name='username')



############ FROM DJANGO SHELL ###########

In [1]: from app.models import Account
In [2]: from app.forms import AccountForm
In [3]: from django.contrib.auth import get_user_model
In [4]: username = 'mynewname'
In [5]: usr = get_user_model().objects.get_or_create(username=username)[0]
In [6]: obj = Account.objects.get_or_create(name='abc', user=usr, 
description='aaa')[0]
In [7]: new_form = {'name': obj.name, 'user': username, 'description': 'aaa'}
In [8]: frm = AccountForm(new_form, instance=obj)
In [9]: assert frm.is_valid()
In [10]: assert frm.cleaned_data['user'] == usr
In [11]: assert frm.cleaned_data['user'] == obj.user
In [12]: frm.has_changed()
Out[12]: *True*
In [13]: frm.changed_data
Out[13]: *['user']*



##########################################
# My Override of the ModelChoiceField #
##########################################


############# app/forms.py ############

from django import forms
from django.apps import apps
from django.contrib.auth import get_user_model


class UsernameToObjectField(forms.ModelChoiceField):
    """ Take a the value of a name and return the object. """

    def has_changed(self, initial, data):
        if self.to_field_name is not None:
            data_value = self.to_python(data) if data is not None else ''
            if data_value is not None:
                data_value = data_value.pk
        else:
            data_value = data
        return super(UsernameToObjectField, self).has_changed(initial, 
data_value)


class AccountForm(forms.ModelForm):

    class Meta:
        model = apps.get_model('app.Account')
        fields = ['user', 'name', 'description']

    user = UsernameToObjectField(get_user_model().objects, 
to_field_name='username')


############ FROM DJANGO SHELL ###########

In [1]: from app.models import Account
In [2]: from app.forms import AccountForm
In [3]: from django.contrib.auth import get_user_model
In [4]: username = 'mynewname'
In [5]: usr = get_user_model().objects.get_or_create(username=username)[0]
In [6]: obj = Account.objects.get_or_create(name='abc', user=usr, 
description='aaa')[0]
In [7]: new_form = {'name': obj.name, 'user': username, 'description': 'aaa'}
In [8]: frm = AccountForm(new_form, instance=obj)
In [9]: assert frm.is_valid()
In [10]: assert frm.cleaned_data['user'] == usr
In [11]: assert frm.cleaned_data['user'] == obj.user
In [12]: frm.has_changed()

Out[12]: *False*
In [13]: frm.changed_data
Out[13]: *[]*

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/41095b7e-6bb5-4518-8558-dcbb86dc4047%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to