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 django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
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