Tuesday, August 22, 2017

Re: 1.11: Value error on related user name during save of user model

Thanks for taking the time to write such an extensive answer.

Am 21.08.2017 um 23:53 schrieb James Schneider <jrschneider83@gmail.com>:



On Mon, Aug 21, 2017 at 7:50 AM, Axel Rau <Axel.Rau@chaos1.de> wrote:
While upgrading from 1.9 to 1.11, ForwardManyToOneDescriptor.__set__()
tries to assign a string (description of the related instance) to the related user name field
of user model.

class AbstractEmailUser(AbstractBaseUser, PermissionsMixin, FieldlistForDetailTemplateMixin):
    localemail = models.OneToOneField('Mailbox', verbose_name=_('Local E-mail'),
            related_name='localemail', db_column='localemail',
            editable=('UR', 'UE', 'UL'))

    objects = UserManager()

    USERNAME_FIELD = 'localemail'
    REQUIRED_FIELDS = []

    class Meta:
        abstract = True
        ordering = ['localemail']

    def get_username(self):
       return getattr(self, self.USERNAME_FIELD)

class Mailbox(models.Model):
    id = models.AutoField(primary_key=True)
    localpart = models.CharField(_('Localpart'), max_length=40)
    localdomainfk = models.ForeignKey(Localdomain,  verbose_name=_('Domain'), db_column='localdomainfk', editable=('AL',))
        

    def __str__(self):
        return self.localpart+ '@'+self.localdomainfk.name



<snip>
 
  File "...python3.5/site-packages/django/forms/models.py", line 408, in _post_clean
    self.instance.full_clean(exclude=exclude, validate_unique=False)
  File "...python3.5/site-packages/django/db/models/base.py", line 1234, in full_clean
    self.clean()
  File "...python3.5/site-packages/django/contrib/auth/base_user.py", line 77, in clean
    setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username()))
  File "...python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 216, in __set__
    self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "'unpriv@framailx.de'": "Account.localemail" must be a "Mailbox" instance.
[21/Aug/2017 16:08:37] "POST /admin/erdb/account/19/change/ HTTP/1.1" 500 166385

Any help to resolve this appreciated,
Axel


You've set your USERNAME_FIELD to a field that is an FK to another table. I've never seen that before, but apparently the docs say it is supported. To be fair, that's the extent of the documentation on how to utilize an FK as the username field. 

Some background info:

This is a realtime operational database, for which I try to create a GUI with Django.
The DB is fully normalized and multi-client.
To reduce the complexity, I have created a concept for shortcuts of model instances, which are used in list views or FK form fields.

Each model has a __str__() method which returns such a shortcut (like the above Mailbox) for an instance.

There are other concepts like
  Model forms just to display data, or, 
  For the multi-client part, the PK of the current user is kept in the session along with some Q-expressions to qualify account dependent queries.

My current problem with 1.11 is a model form for Account, which contains a FK field referencing Mailbox in which the above shortcut is displayed as a pop up (forms logic treats remote instance as text).
I changed something else in the form and tried to save with the Mailbox field unchanged.

It seems that forms logic does no longer manage to get the instance from its text representation.

When I access a model instance, AFAIK my context determines the data type I get (string or model instance).
Is this correct?

If this was working under 1.9 (I'd be surprised if it was), then I would file this as a backward-incompatibility bug with the bug tracker. It's possible that 1.9 did do the type/field conversion using some black magic, but with the information in your model, I don't know how it could have made that determination. 

I have just verified: It still works with 1.9. (-;


From a design perspective, the relation you presented seems backwards to me. I would think the Account model would hold the canonical username, and Mailbox would have the FK back to the Account. That design would not require the use of a username field as an FK, simplifying everything (authentication, forms, views, etc.). Your current design would implement excessive SQL JOIN's to pull relatively simple data on every request. 

Or, I could be completely wrong. :-D

Perhaps, I should publish the project at github (it's OSS anyway), to get more advice?

Axel
---
PGP-Key:29E99DD6  ☀  computing @ chaos claudius

No comments:

Post a Comment