Fixed #27489 -- Renamed permissions upon model renaming in migrations.#20539
Fixed #27489 -- Renamed permissions upon model renaming in migrations.#20539artirix1927 wants to merge 1 commit intodjango:mainfrom
Conversation
92be68e to
ef510f8
Compare
jacobtylerwalls
left a comment
There was a problem hiding this comment.
Thanks, I copied over some findings that I had from working on #20481.
tests/auth_tests/test_management.py
Outdated
| ct = ContentType.objects.create(app_label="auth_tests", model="oldmodel") | ||
| actions = ["add", "change", "delete", "view"] | ||
| for action in actions: | ||
| Permission.objects.create( | ||
| codename=f"{action}_oldmodel", | ||
| name=f"Can {action} old model", | ||
| content_type=ct, | ||
| ) | ||
|
|
||
| call_command("migrate", "auth_tests", verbosity=0) |
There was a problem hiding this comment.
I think it would be simpler & model some realism to rely on the behavior of the post_migrate handler, so just migrate one step:
| ct = ContentType.objects.create(app_label="auth_tests", model="oldmodel") | |
| actions = ["add", "change", "delete", "view"] | |
| for action in actions: | |
| Permission.objects.create( | |
| codename=f"{action}_oldmodel", | |
| name=f"Can {action} old model", | |
| content_type=ct, | |
| ) | |
| call_command("migrate", "auth_tests", verbosity=0) | |
| # Create initial content type and permissions for OldModel. | |
| call_command("migrate", "auth_tests", "0001", verbosity=0) | |
| # Apply the migration that renames OldModel to NewModel. | |
| call_command("migrate", "auth_tests", "0002", verbosity=0) | |
| actions = ContentType._meta.default_permissions |
There was a problem hiding this comment.
Don't want to force you to do it my way, but after merging the original version Tim Graham observed without comments it was difficult to follow what was going on, so I think keeping the suggested comments here will help.
6531c21 to
176a899
Compare
jacobtylerwalls
left a comment
There was a problem hiding this comment.
Appreciate the updates!
tests/auth_tests/test_management.py
Outdated
| ct = ContentType.objects.create(app_label="auth_tests", model="oldmodel") | ||
| actions = ["add", "change", "delete", "view"] | ||
| for action in actions: | ||
| Permission.objects.create( | ||
| codename=f"{action}_oldmodel", | ||
| name=f"Can {action} old model", | ||
| content_type=ct, | ||
| ) | ||
|
|
||
| call_command("migrate", "auth_tests", verbosity=0) |
There was a problem hiding this comment.
Don't want to force you to do it my way, but after merging the original version Tim Graham observed without comments it was difficult to follow what was going on, so I think keeping the suggested comments here will help.
| new_name_str = f"Can {action} {verbose_name_raw}" | ||
|
|
||
| if perm.codename == new_codename and perm.name == new_name_str: | ||
| continue |
There was a problem hiding this comment.
You think its better to mock the save and test it that way?
Or get the permission and check that the pk says the same which means its same permission (hope that makes sense to you) ?
There was a problem hiding this comment.
It's not clear to me whether this condition ever evaluates True. We would need a perm in the database with a codename that __endswith the old codename but also == the new_codename, so that would either happen because of:
- substring matches (which I think you said you were looking into)
- or
MODELandmodelboth mapping tomodel
So you could add a test case for a MODEL being renamed to model (seems silly, but might happen on legacy dbs, I guess). Or revisit this depending on how you remove the substring matching.
If it's not reachable, but you want to add a sanity check in the code, I'd be open to adding an assert.
|
|
||
| for _, from_codename, to_codename, _ in planned: | ||
| if verbosity >= 2: | ||
| print( |
| print( | ||
| style.WARNING( | ||
| f"Failed to rename permission {pk} " | ||
| f"from '{old}' to '{new}'. " | ||
| f"Please resolve the conflict manually." | ||
| ) |
There was a problem hiding this comment.
We need to capture this output in the test with captured_stdout and assert over it, see test run:
.........Failed to rename permission 463 from 'change_oldmodel' to 'change_newmodel'. Please resolve the conflict manually.
....
----------------------------------------------------------------------
Ran 117 tests in 2.015s|
|
||
|
|
||
| def _get_permission_metadata(apps, app_label, model_name): | ||
| Permission = apps.get_model("auth", "Permission") |
There was a problem hiding this comment.
We should get the default permissions defined on the model being renamed, not the Permission model itself.
There was a problem hiding this comment.
I get them on the model being renamed if its available. If we have lookup error I use the permission model default permissions.
There was a problem hiding this comment.
Gotcha, sorry. In that case, I wonder if we should:
- move this line into the except
- or, just handle LookupError a lot earlier instead of inside this util
create_permissions() returns very early if there's a LookupError.
|
|
||
| perms = Permission.objects.using(db).filter( | ||
| content_type__app_label=app_label, | ||
| codename__endswith=old_suffix, |
There was a problem hiding this comment.
Like the first version with icontains, I'm still concerned about substring conflation, can we avoid using endswith somehow?
There was a problem hiding this comment.
I can just prepare the whole codename and just codename = looking_for_codename. I don't think there is another way to filter permissions other than strings.
|
I think sometimes the GitHub UI isn't super helpful showing replies. I replied to a comment from a previous review: here In that review, I added a suggestion to replace the manual content type creations with stepwise migrations, e.g. 0001, then 0002: # Create initial content type and permissions for OldModel.
call_command("migrate", "auth_tests", "0001", verbosity=0)
# Apply the migration that renames OldModel to NewModel.
call_command("migrate", "auth_tests", "0002", verbosity=0)You applied that suggestion (thank you!) but without the comments. So, unless you're deeply familiar with the content type internals (I certainly wasn't!) it's not clear that there's a side effect of permissions being created. All I meant to indicated was to keep the comments I put in my suggestion. You're doing a great job being responsive to all the feedback, this is a tricky area for several reasons and explains why the ticket has been open so long. I'm very positive on the positive of landing this soon 🤝 |
e013d89 to
d729f81
Compare
📊 Coverage Report for Changed FilesNote: Missing lines are warnings only. Some lines may not be covered by SQLite tests as they are database-specific. For more information about code coverage on pull requests, see the contributing documentation. |
63e5bf8 to
2c74929
Compare
I noticed that my recent PR is failing during the CI/CD stage due to a PostgreSQL connection error. It also seems that other PRs are experiencing similar failures today, so I wanted to check whether this is a known infrastructure issue or something caused by my changes. Could you please confirm whether this is on my side or related to the CI setup? Thank you. |
|
Nothing to do with your changes -- there have been a lot of infrastructure problems on CI recently. The GitHub actions have been more resilient than the Jenkins actions, so I would just pay attention to that feedback for now. Sorry. |
Changed the pre migrate signal and inserting permission rename operations in the migration plan to a post migrate signal. When having conflicting permission rename, added a note for user with next steps. Avoiding integrity error by finding conflicting perms in advance and skipping them. Added taking permission actions and verbose name raw from model class when available. Added using full literal codename for filtering instead of using substings with endswith/startswith. Hence deleted dead condition for checking if permission is already correct. Added stdout for instead of prints for logging. Brought back respects other db test. Improved some tests by calling migrate 0001 instead of creating permissions manually. Added verbosity prints test. Added warning msg assertion for conflicting permissions test. Updated general docs and 6.1 release docs.
2c74929 to
9d4cc95
Compare
ticket-27489
AI Assistance Disclosure (REQUIRED)
GPT-5 Mini was used to write a verbose prints and warning catching tests, reviewed the output carefully.
Checklist
mainbranch.