Курица и Яичный кошмар с Django миксином - PullRequest
0 голосов
/ 02 марта 2020

Я обновляю большое приложение на основе Django с Django 1.7 приложения до Django 2.2 и испытываю большие проблемы с миксином, связанным с разрешениями.

   class PrincipalRoleRelation(models.Model):

    """A role given to a principal (user or group). If a content object is
    given this is a local role, i.e. the principal has this role only for this
    content object. Otherwise it is a global role, i.e. the principal has
    this role generally.

    user
        A user instance. Either a user xor a group needs to be given.

    group
        A group instance. Either a user xor a group needs to be given.

    role
        The role which is given to the principal for content.

    content
        The content object which gets the local role (optional).
    """

       :::

    user         = models.ForeignKey(User,        verbose_name=_(u"User"),         blank=True, null=True, on_delete=models.SET_NULL)
    group        = models.ForeignKey(Group,       verbose_name=_(u"Group"),        blank=True, null=True, on_delete=models.SET_NULL)
    role         = models.ForeignKey(Role,        verbose_name=_(u"Role"),                                on_delete=models.CASCADE)

       :::

Однако, это не удается загрузить во время инициализации приложения, потому что User, Group и Role et c также являются приложениями, загрузка которых выполняется и «populate () не является входящим» (поэтому Дан go жалуется)

Я попытался обойти это путем внесения поправок в приведенный выше код для создания своего рода «каркасного» класса, который не пытается ссылаться на какие-либо другие приложения, например:

app_models_loaded = True

try:
    from django.contrib.auth import get_user_model
    User = get_user_model()
except:
    app_models_loaded = False

if app_models_loaded:

    from django.contrib.auth.models import Group

    user         = models.ForeignKey(User,        verbose_name=_(u"User"),         blank=True, null=True, on_delete=models.SET_NULL)
    group        = models.ForeignKey(Group,       verbose_name=_(u"Group"),        blank=True, null=True, on_delete=models.SET_NULL)
    role         = models.ForeignKey(Role,        verbose_name=_(u"Role"),                                on_delete=models.CASCADE)
              :::

Затем в manage.py я бы определил полный класс mixin, называемый say PrincipalRoleRelation2 и перезаписывающий класс скелета с помощью кода:

from django.contrib import admin

from permissions.models import PrincipalRoleRelation

if admin.site.is_registered(PrincipalRoleRelation):
    admin.site.unregister(PrincipalRoleRelation)

admin.site.register(PrincipalRoleRelation, PrincipalRoleRelation2)

Однако, хотя это почти кажется работающим, я не вижу некоторых атрибутов PrincipalRoleRelation2, например "role" в том, что я надеялся, будет переопределенный класс PrincipalRoleRelation со всеми присутствующими атрибутами.

Я чувствую, что копаюсь во все более глубокой яме, и что Такой подход неэффективен и никогда не будет работать должным образом. Так что любая помощь будет очень цениться!

- = - = - = - = - = - = - = - = - = - = = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - =

edit: В ответ на комментарий Шиллингта класс User определяется следующим образом:

class User(AbstractBaseUser):  # , PermissionsMixin):
    """ Custom user model
        Currently just used by the tests for django-permissions

        All unique user fields required for a user
        NB: Fields that are customizable across multiple identities will be part of a Profile object
    """
    # Dont use PermissionsMixin since not using contrib.auth.models.Permissions
    # and not using authentication backend perms ... so its only relevant for groups
    # ... however it causes user.groups relations name clashes ..
    # But we are using the groups part with django-permissions:
    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 '
                                                            'his/her group.'),
                                    related_name="user_set", related_query_name="user")
    is_superuser = models.BooleanField(_('superuser status'), default=False,
                                       help_text=_('Designates that this user has all permissions without '
                                                   'explicitly assigning them.'))

    username = models.EmailField(_('Email (Username)'), max_length=255, unique=True)
    # Make username an email and just dummy in email here so its clearer for user.email use cases

1 Ответ

0 голосов
/ 02 марта 2020

В качестве решения для циклической референции django имеет возможность указать ForeignKey (или любое другое реляционное поле) со строковой ссылкой на связанную модель вместо импорта фактического класса.

user = models.ForeignKey('users.User', on_delete=models.CASCADE)

Это рекомендуемый способ определения связанных полей.

...