Группы на объект с использованием разрешений Django и django-guardian

В настоящее время я создаю структуру, в которой у меня есть сотрудники, принадлежащие компании. Внутри этой компании мне нужно создать несколько групп. Ранги, если хотите. Вы можете назначить меньше разрешений для более низких рангов и больше разрешений для более высоких рангов.

Я хочу пойти на разрешения уровня объекта, и я заметил, что проект django-guardian дал мне именно то, что мне нужно. Он работает с собственными объектами User и Group, поэтому теперь я пытаюсь найти способ реализовать объект родной группы в объекте компании.

Я сталкиваюсь с тем, что имя в группе уникально. Поэтому, если 2 компании добавят одну группу, будут возникать ошибки.

Я нашел реализацию, которая работает в некотором смысле, но кажется довольно "взломанной" для меня. В моей компании я объявила групповую переменную, которая ссылается на группу:

class Company(models.Model):
    ...
    groups = models.ManyToManyField(Group, through='CompanyRole')

КомпанияRole в основном содержит название группы и ссылку на компанию и группу

class CompanyRole(models.Model):
    group = models.ForeignKey(Group)
    company = models.ForeignKey(Company)
    real_name = models.CharField(max_length=60, verbose_name=_('Real name'))

    objects = CompanyGroupManager()

Я создал пользовательский менеджер с удобным методом для добавления новой "группы компаний"

class CompanyGroupManager(models.Manager):
    def create_group(self, company, group_name):
        un_group_name = str(company.id) + '#' + group_name
        group = Group.objects.create(name=un_group_name)
        company_group = self.model(
            real_name=group_name, 
            company=company, 
            group=group
        )

        company_group.save(using=self._db)
        return company_group

Вот часть, на которую я действительно не чувствую себя комфортно. Чтобы изменить проблему с уникальным именем в модели Group, я использовал комбинацию идентификатора компании, символа хэша и фактического имени группы, чтобы избежать столкновений.

Теперь мой вопрос: есть ли в моем сценарии лучшие методы, я что-то упускаю или это хороший способ выполнить то, что мне нужно?

Ответ 1

К сожалению, нет способа обойти уникальное требование, потому что это поле используется как id: https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.Field.unique

Ваши параметры следующие:

1) Издевается над моделью.

Вы бы просто создали новую модель группы, которая не имеет уникального требования. Недостатком здесь является то, что вам нужно будет использовать его повсюду, поэтому, если это требует обновления сторонних приложений, это может не стоить того.

2) сделайте имя уникальным. (Как вы это делали)

Убедитесь, что вы хорошо документируете свое соглашение, чтобы все будущие кодеры знали, на что они смотрят. Что-то вроде "название компании" # "имя группы" могло бы сделать более интуитивный смысл, чем идентификатор. Если хэш может появиться в любом случае, используйте более определенный разделитель ( "__" является относительно распространенным способом подключения связанных понятий в django, я могу пойти на это).

Я бы рекомендовал вам добавить следующее, чтобы упростить вам доступ к имени.

def get_name(self):
    # Explain how you get the group name from your uniqueified name
    return self.name.split('#')[1] 

Group.add_to_class('get_name', get_name)

Когда вы получаете доступ к имени своей группы в своем приложении, просто выполните:

my_group.get_name()

Вы также можете поместить генерирование уникального имени в переопределенную версию save(). Это даст вам более приятное разделение между моделью и представлением...