Handling conflicts when renaming permissions in concert with renaming models

Polling for input on how to handle conflicts when implementing a ticket involving permission renames.

We have a longstanding accepted ticket to automatically rename the name and codename of Permission objects to match a model being renamed in a migration.

For example, if you rename Song to Melody, Django currently will rename your ContentType records but will not rename your Permission records. New Permission records for Melody will be generated by the auth app’s post_migrate handler, with the result that you have stale permissions for Song (possibly with user & group data attached), and fresh ones for Melody with no related user & group data, both pointing to the new content type for Melody.

There’s a user thread about how to handle this situation: permission name not updating after migration - #3 by zybex86. Answer: very carefully. Would be nice to improve this.

We merged a solution for 6.0, but reverted it in 6.0.1 when discovering a few issues in the implementation.

I’m asking for feedback on the main issue left to decide: how to handle conflicts?

For instance, when migrating forward, what to do if can_add_melody already exists in the db? (Maybe you have another RenameModel operation in your migrations because you undid the change during code review.) Or when migrating backward, what if can_add_song already exists, because your environment predates the version of Django with this feature? Etc.


  1. Silently do nothing, letting the stale permission become the resulting permission matching the renamed model.
  2. Same as 1, but emit a warning.
  3. Detect the conflict and error out with recommended follow-up actions.
  4. Detect the conflict and if we are interactive mode, prompt the user for consent to delete the stale permission, do the delete, continue with the rename, otherwise error out.

The original solution did (1.). I opened a ticket suggesting this was a bug. (This is also how duplicate content types are handled, which I’ve also suggested is a bug, given that the original rationale for handling it silently no longer holds, but in any case I think the consequences of a conflict here are perhaps less severe?)

There’s a precedent for (2.) in a similar situation, but warnings are easy to miss.

(3.) sounds nice.

(4.) would require collecting related objects to be deleted and blaring, “are you really sure?”. Before content type conflicts were changed to be handled silently, those conflicts were handled like this. I pushed some commits to this closed PR sketching this out based on that precedent.


(4.) almost sounds nice to me, but I could be argued down to (3.) just to avoid doing anything clever.

Does anyone have advice? I’d like to make sure we’ve got a sound approach here before asking the original contributor take another look. Thanks.

1 Like

Wow! This takes me back :slight_smile:
To me 4. is the best option but is a lot of work on the dev side AND might be a pain to test. It all depends on what you want and how much pressure / time you have. I personally would go for 3 and show the dev what to do.
Automatic fixes by django are also problematic if the DEV made some custom behaviour in the app. That’s why I vote for 3.

Thank you @jacobtylerwalls for the excellent summary. I am strongly in favor of option 3. The situations where these conflicts occur are very niche, and I do not think the time investment required to get the interaction right is justified by those edge cases. I would though invest some time into getting the error message clear with enough context for the operator to understand and perform manual cleanup steps.

(As Carlton says: “Simple, to the point, covers the 80% case is probably enough for an addition to Django itself […]”)

1 Like

Hello everyone. I’m a relatively new contributor and(started in mid November), and I’m following this with a lot of interest. @jacobtylerwalls thanks for the detailed summary, it’s very helpful for understanding the context. I’ve been digging into the ORM recently while I was working my way through related tickets and I’ve gained a much deeper appreciation for how these database-level edge cases can spiral in complexity if left unchecked.
Although option 4 is compelling, personally I think option 3 strikes the right balance and is relatively light on the maintainers as rightfully said by zybex86. As @nessita mentioned, covering the 80% case with a clear, actionable error message feels like the right approach to stabilize the helpfulness and safety, making it a better experience across the framework.