从Django 2.0迁移到2.2时视图权限及跨库关联报错排查
Let's break down this issue and cover both the root cause and actionable solutions that don't require modifying Django's core code.
What's Causing the Error?
When upgrading from Django 2.0 to 2.2, you hit this error because Django 2.1 introduced view permissions (the view_<model> permission type). During migrations, Django automatically tries to create these permissions for your models.
The problem arises because:
- Permission objects are linked to ContentType objects (which track your app's models)
- Your custom database router's
allow_relationrule was blocking cross-database relations between the Permission (being created in thedemodatabase) and the ContentType (likely stored in your default database)
Solution 1: Adjust Your Custom Database Router
The simplest fix is updating your router's allow_relation method to explicitly allow relations involving the demo database. This lets Django link the Permission to the ContentType without hitting the router block.
Here's the modified router code:
class AppRouter: def allow_relation(self, obj1, obj2, **hints): # Allow relations if either object is in the demo database if obj1._state.db == "demo" or obj2._state.db == "demo": return True # Fallback to default rule: only allow same-database relations return obj1._state.db == obj2._state.db
After updating the router, re-run your migration command:
python manage.py migrate demo --database demo
Solution 2: Manually Create View Permissions (No Router Changes)
If you don't want to adjust your router's rules, you can bypass Django's automatic permission generation by creating the view permissions manually in a custom migration. This mimics the core code change you tried, but keeps modifications in your own codebase.
- Create an empty migration for your
demoapp:
python manage.py makemigrations demo --empty
- Open the generated migration file and replace its content with this code (update placeholders to match your models):
from django.db import migrations from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Permission def create_view_permissions(apps, schema_editor): # Replace 'your_model_name' with the name of your model (lowercase) ct = ContentType.objects.get(app_label='demo', model='your_model_name') # Create the view permission using content_type_id instead of the object Permission.objects.using('demo').get_or_create( codename='view_your_model_name', name='Can view your model name', content_type_id=ct.id ) class Migration(migrations.Migration): dependencies = [ # Add the dependency on your app's last migration, e.g.: # ('demo', '0001_initial'), ] operations = [ migrations.RunPython(create_view_permissions), ]
- Run the migration as usual:
python manage.py migrate demo --database demo
Why Your Core Code Change Worked
When you modified Django's core django/contrib/auth/management/__init__.py file to use content_type_id=ct.id instead of content_type=ct:
- Originally, passing the full ContentType object triggered Django's database router check (
allow_relation), which blocked the cross-database link. - Using
content_type_iddirectly sets the foreign key's numeric value without passing the object. This skips the router's relation check, so the Permission is saved successfully.
内容的提问来源于stack exchange,提问作者Arpit

