不存在多对多关系。它在不同的架构中

Posted

技术标签:

【中文标题】不存在多对多关系。它在不同的架构中【英文标题】:manytomany relation does not exist. It's in a different schema 【发布时间】:2016-12-13 19:11:27 【问题描述】:

我将 AbstractBaseUser 与 CustomPermissionsMixin 一起使用。 CustomPermissionsMixin 与 django PermissionsMixin 有点相同,不同之处在于我更改了 user_permissions 和组的相关名称和相关查询名称,因此它不会与 django PermissionsMixin 相关名称发生冲突

@python_2_unicode_compatible
class CustomPermissionsMixin(models.Model):
    """
    A mixin class that adds the fields and methods necessary to support
    Django's Group and Permission model using the ModelBackend.
    """
    is_superuser = models.BooleanField(
        _('superuser status'),
        default=False,
        help_text=_(
            'Designates that this user has all permissions without '
            'explicitly assigning them.'
        ),
    )
    groups = models.ManyToManyField(
        Group,
        verbose_name=_('groups'),
        blank=True,
        help_text=_(
            'The groups this user belongs to. A user will get all permissions '
            'granted to each of their groups.'
        ),
        related_name="%(app_label)s_%(class)s_related",
        related_query_name="%(app_label)s_%(class)ss",
    )
    user_permissions = models.ManyToManyField(
        Permission,
        verbose_name=_('student user permissions'),
        blank=True,
        help_text=_('Specific permissions for this user.'),
        related_name="%(app_label)s_%(class)s_related",
        related_query_name="%(app_label)s_%(class)ss",
    )

    class Meta:
        abstract = True
    ....

我在两个不同的应用中有相同的学生课程。一个在 App1 中,另一个在 App2 中,字段略有不同。我使用postgresql。 App1 在公共架构中,而 App2 在架构 krt5jdjtrx 中。(使用 django 租户架构。以编程方式创建)两者都使用 AbstractBaseUser 和 CustomPermissionsMixin

class Student(AbstractBaseUser, CustomPermissionsMixin):
    ...

我也使用 DRF DjangoModelPermissions

REST_FRAMEWORK = 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
        'rest_framework.permissions.DjangoModelPermissions',

以及自定义身份验证后端

class CustomBackend(ModelBackend):
    ....

问题出在 django ModelBackend 内的_get_user_permissions。假设user_objapp1.Student 类型,user_obj.user_permissions.all().query 有时使用app1_student_user_permissionsapp2_student_user_permissions。为什么查询使用app2_student_user_permissionsuser_obj 确实是app1 而不是app2? .它会创建 django.db.utils.ProgrammingError: relationship does not exist.

def _get_user_permissions(self, user_obj):
    print('inside _get_user_perm !!!!!!!!!!!!!!!!!!!!!!!')
    print(user_obj)
    print(type(user_obj))
    print(user_obj.user_permissions.all().query)
    return user_obj.user_permissions.all()

这是原始查询集

SELECT "auth_permission"."id", "auth_permission"."name", "auth_permission"."content_type_id", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "app2_student_user_permissions" ON ("auth_permission"."id" = "app2_student_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "app2_student_user_permissions"."student_id" = 1 ORDER BY "django_content_type"."app_label" ASC, "django_content_type"."model" ASC, "auth_permission"."codename" ASC

编辑

App2 学生的架构/表将在程序稍后的某个时间点创建。 由于 App2 student 与 Permissions 有很多关系,Permissions 现在有 app1 关系和 app2 关系。我认为它是由 ManyRelatedManager 注册的。 (Permissions 将这两个关系视为公共模式)

如果我执行 student1_of_app1.user_permissions.all(),Django 将遍历 Permissions 所具有的关系。包括不存在的 App2 表。因此它会创建 django.db.utils.ProgrammingError: 关系不存在。

但是,有时没有错误,因为 Django 先进入 app1 关系,但有时 Django 进入 app2 关系,因此出现错误。

我怎样才能防止这种情况发生?

【问题讨论】:

也许他们都是在同一张表中创建的,而 Django 看不出有什么区别? 我不太明白它会如何以这种方式影响您,但您需要 unique names for all your fields,但组和 user_permissions 会发生冲突。 它会影响权限检查,因为 app2 架构不在公共架构中。 【参考方案1】:

我发现问题是关于 django 租户模式而不是 django。 migrate_schema --shared 实际上迁移整个 makemigration 文件,无论是共享的应用程序还是租户。 两个应用程序(共享和租户)都注册在 django_content_type 表中,该表也在 auth_permissions 中注册。因此,该关系不存在,因为此时尚未创建租户表,但已为 Permissions 注册了多对多关系。

【讨论】:

以上是关于不存在多对多关系。它在不同的架构中的主要内容,如果未能解决你的问题,请参考以下文章

数据库中多对多关系及其实现

XAF中多对多关系 (XPO)

Java中多对多映射关系

Laravel 中多对多关系中连接表的命名约定

防止 SQLAlchemy 中多对多关系中的重复表条目

数据库表中多对多关系怎么设计?