Reputation: 825
I want to make foreign key from auth_group_permissions table.(the M2M table between permission and group) I know that I can use through, but it isn't appropriate if I make modify in Django library.
I used Django guardian library, so customize group model is not good idea.
I want like this:
class MyModel(models.Model):
my_field = models.ForeignKey(???,on_delete=models.CASCAD)
Is there any appropriate solution.
Upvotes: 1
Views: 543
Reputation: 158
First solution: manage this relationship not automatically
class MyModel(models.Model):
grouppermission_id = models.PositiveIntegerField()
some_field = models.TextField()
grouppermissions_instance = group_instance.permissions.through.objects.filter(permission=permission_instance, group=group_instance.id).first()
grouppermissions_settings = MyModel.create(grouppermissions_instance.pk, "extra settings")
Second solution: You can create your own intermediate model and elegancy slip it to Group model from your app models.py and make migrations in your app not in django.
in my account.models:
class GroupPermission(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE, db_index=False)
permission = models.ForeignKey(Permission, on_delete=models.CASCADE)
timedelta = models.DurationField(
"Timedelta to restrict access.", null=True, blank=True
)
class Meta:
unique_together = ("group", "permission")
app_label = "auth"
def __str__(self):
return f"{self.group} | {self.permission} | {self.timedelta}"
Permission.group_set.field.remote_field.through = GroupPermission
account.migrations:
0011
class Migration(migrations.Migration):
dependencies = [
('account', '0009_some_migrations_prev'),
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='GroupPermission',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timedelta', models.DurationField(verbose_name='Timedelta to restrict access.', blank=True, null=True)),
('group', models.ForeignKey(db_index=False, on_delete=django.db.models.deletion.CASCADE, to='auth.group')),
('permission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.permission')),
],
options={
'unique_together': {('group', 'permission')},
},
),
migrations.RunSQL(sql="""INSERT INTO auth_grouppermission SELECT "id", NULL, "group_id", "permission_id" FROM auth_group_permissions;""", reverse_sql="")
]
def mutate_state(self, project_state, preserve=True):
"""
This is a workaround that allows to store ``auth``
migration outside the directory it should be stored.
"""
app_label = self.app_label
self.app_label = "auth"
state = super(Migration, self).mutate_state(project_state, preserve)
self.app_label = app_label
return state
def apply(self, project_state, schema_editor, collect_sql=False):
"""
Same workaround as described in ``mutate_state`` method.
"""
app_label = self.app_label
self.app_label = "auth"
state = super(Migration, self).apply(project_state, schema_editor, collect_sql)
self.app_label = app_label
return state
def unapply(self, project_state, schema_editor, collect_sql=False):
"""
Same workaround as described in ``mutate_state`` method.
"""
app_label = self.app_label
self.app_label = "auth"
state = super(Migration, self).unapply(project_state, schema_editor, collect_sql)
self.app_label = app_label
return state
0012
class Migration(migrations.Migration):
dependencies = [
("account", "0011_some_migrations_prev"),
("auth", "0012_alter_user_first_name_max_length"),
]
operations = [
migrations.RunSQL(
sql="DROP TABLE auth_group_permissions CASCADE",
reverse_sql="""
BEGIN;
CREATE TABLE IF NOT EXISTS "auth_group_permissions" ("id" serial NOT NULL PRIMARY KEY, "group_id" integer NOT NULL, "permission_id" integer NOT NULL);
ALTER TABLE "auth_group_permissions" ADD CONSTRAINT "auth_group_permissions_group_id_2fcb7b02_fk_auth_group_id" FOREIGN KEY ("group_id") REFERENCES "auth_group" ("id") DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE "auth_group_permissions" ADD CONSTRAINT "auth_group_permissions_permission_id_3dd4a24a_fk_auth_perm" FOREIGN KEY ("permission_id") REFERENCES "auth_permission" ("id") DEFERRABLE INITIALLY DEFERRED;
BEGIN;
INSERT INTO "auth_group_permissions" SELECT "id", "group_id", "permission_id" FROM "auth_grouppermission";
COMMIT;
BEGIN;
CREATE INDEX "auth_group_permissions_group_id_2fcb7b02" ON "auth_group_permissions" ("group_id");
CREATE INDEX "auth_group_permissions_permission_id_3dd4a24a" ON "auth_group_permissions" ("permission_id");
COMMIT;
COMMIT;
""",
),
migrations.AddField(
model_name="group",
name="permissions",
field=models.ManyToManyField(
blank=True,
through="auth.GroupPermission",
to="auth.Permission",
verbose_name="permissions",
),
),
]
def mutate_state(self, project_state, preserve=True):
"""
This is a workaround that allows to store ``auth``
migration outside the directory it should be stored.
"""
app_label = self.app_label
self.app_label = "auth"
state = super(Migration, self).mutate_state(project_state, preserve)
self.app_label = app_label
return state
def apply(self, project_state, schema_editor, collect_sql=False):
"""
Same workaround as described in ``mutate_state`` method.
"""
app_label = self.app_label
self.app_label = "auth"
state = super(Migration, self).apply(project_state, schema_editor, collect_sql)
self.app_label = app_label
return state
def unapply(self, project_state, schema_editor, collect_sql=False):
"""
Same workaround as described in ``mutate_state`` method.
"""
app_label = self.app_label
self.app_label = "auth"
state = super(Migration, self).unapply(project_state, schema_editor, collect_sql)
self.app_label = app_label
return state
Upvotes: 1