The tables for ManyToMany relationship are created by lines with models.ManyToManyField
string that are in the migration file.
In this case they are created by the initial migration django/contrib/auth/migrations/0001_initial.py
. It is very similar to django/contrib/auth/models.py
.
The related SQL commands can be read by
$ python manage.py sqlmigrate auth 0001_initial
See the lines:
CREATE TABLE "auth_user_groups"...
CREATE TABLE "auth_group_permissions"...
CREATE TABLE "auth_user_user_permissions"...
Especially interesting two texts are around the words REFERENCES
. That are the foreign keys to base tables, e.g.:
... "user_id" integer NOT NULL REFERENCES "auth_user" ("id") ...
EDIT:
You probably know a ManyToMany relationship joined by an explicit intermediate model specified by the parameter through=SomeModel with an extra field.
I explain it in example how you can use a hidden intermediate table in your code.
Imagine that you want to make a note to some permission why you added it to some person.
You can explore the model structure from command line, because in "auth/models.py" you could read only the name "user_parmissions".
>>> User._meta.local_many_to_many
[<django.db.models.fields.related.ManyToManyField: groups>,
<django.db.models.fields.related.ManyToManyField: user_permissions>]
>>> User.user_permissions.through
<class 'django.contrib.auth.models.User_user_permissions'>
>>> User.user_permissions.through._meta.local_fields
[<django.db.models.fields.AutoField: id>,
<django.db.models.fields.related.ForeignKey: user>,
<django.db.models.fields.related.ForeignKey: permission>]
your_app/models.py
from django.contrib.auth.models import User, Group, Permission
from django.db import models
# This line is instead of import, because the implicit intermediate table
# can not be imported.
UserPermission = User.user_permissions.through
class UserPermissionReason(models.Model)
user_permission = models.ForeignKey(UserPermission, ...)
reason = models.CharField(help_text="Why I added that permission", ...)
makemigrations, migrate, shell...
Example: Create a user permission with your note
>>> from your_app.models import UserPermissionReason, UserPermission
>>> from django.contrib.auth.models import User, Group, Permission
>>> permission = Permission.objects.get(name='Can add user',
content_type__app_label='auth')
>>> permission
<Permission: auth | user | Can add user>
>>> user_permission = UserPermission.objects.create(user=me_superuser,
permission=permission)
>>> why = UserPermissionReason.objects.create(
user_permission=user_permission,
reason="Because I can :-)"
)
If you don't need to reference the intermediate table you would use a normal simple some_ruser.user_permissions.add(permission)