Code

Opened 6 years ago

Closed 6 years ago

#7203 closed (fixed)

Admin error if an edit_inline=True object has a ForeignKey to some other object which has a unique_together specification

Reported by: Scott Moonen <smoonen@…> Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Here's a reduced example:

class Organization(models.Model) :
  pass

class User(models.Model) :
  organization = models.ForeignKey(Organization)
  username = models.SlugField(max_length = 30)
  class Meta :
    unique_together = ('organization', 'username')

class OrganizationService :
  organization = models.ForeignKey(Organization)
  service = models.SlugField(max_length = 30)
  class Meta :
    unique_together = ('organization', 'service')

class ServiceUser :
  user = models.ForeignKey(User, edit_inline = models.TABULAR)
  organization_service = models.ForeignKey(OrganizationService)
  class Meta :
    unique_together = ('organization_service', 'user')

So, ServiceUser is related to User and is edited inline there. ServiceUser is also related to OrganizationService. So, when we go to edit User in the admin interface, it builds the following get_follow list:

{'username': True, 'myapp:serviceuser': {'organization_service': True, 'id': True, 'user': False}, 'organization': True, 'id': True}

The problem is that the inner dictionary has 'organization_service' set to True. This results in our trying to extend the User ChangeManipulator with the unique_together validator for OrganizationService. That fails:

AttributeError at /myapp/user/6/
'ChangeManipulator' object has no attribute 'isUniqueorganization_service_user'

The 'organization_service' follow indicator is set to True because RelatedObject.get_follow is smart enough to force the edit_inline ForeignKey to have False for follow, however it doesn't set follow for other ForeignKey relations in the edit_inline object to False:

over[self.field.name] = False

I'm not sure what the right way is to fix this. I almost think that Options.get_follow needs a new parameter to indicate whether all ForeignKey relationships (not only the one that has edit_inline set) should be forced to False. Or, alternatively, we could create an alternative function to Options.get_follow with this behavior. We can then force this behavior in the call from RelatedObject.get_follow, but keep the existing behavior in the call from AutomaticManipulator. I'm not sure if that would create broader problems, though.

This bug is a little more problematic than average, since I can't find an easy workaround apart from removing the edit_inline = True specification.

Attachments (0)

Change History (2)

comment:1 Changed 6 years ago by Scott Moonen <smoonen@…>

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Alternative workaround is to comment out the unique_together specification (and rely on DB validation rather than Django validation).

comment:2 Changed 6 years ago by smoonen@…

  • Resolution set to fixed
  • Status changed from new to closed

As expected, this works fine now that the newforms-admin branch has landed. From what I read on the mailing lists, I understand that form-level validation of constraints like the unique_together has yet to happen in NFA; for now things will be validated only at the database level. But that's not of great concern to me; admin object editing is now possible without having to comment out the constraint altogether.

Closing this ticket as resolved.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.