Джанго: Как можно организовать этот большой беспорядок моделей / менеджеров / дизайнеров? - PullRequest
3 голосов
/ 25 января 2010

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

то есть я не хочу сделать что-то вроде этого:

class Ticket(models.Model):
        account = models.ForeignKey(Account)
        client = models.ForeignKey(Client)  # A client will be owned by one account.
        content = models.CharField(max_length=255)

class TicketForm(forms.ModelForm):
        class Meta:
                model = Ticket
                exclude = ('account',)  #First sign of bad design?

        def __init__(self, *args, **kwargs):
                super(OrderForm, self).__init__(*args, **kwargs)
                if self.initial.get('account'):
                        # Here's where it gets ugly IMHO. This seems almost
                        # as bad as hard coding data. It's not DRY either.
                        self.fields['client'].queryset = Client.objects.filter(account=self.initial.get('account'))

Моя идея состоит в том, чтобы создать модель Account(models.Model) со следующим настраиваемым менеджером и подклассировать ее, используя наследование нескольких таблиц со всеми моими моделями. Это дает мне огромную головную боль. Нужен ли мне account внешний ключ для каждой модели? Могу ли я получить доступ к учетной записи родительского класса для определенного экземпляра модели?

class TicketManager(models.Manager):
    def get_query_set(self):
        return super(TicketManager, self).get_query_set().filter(account=Account.objects.get(id=1))
        # Obviously I don't want to hard code the account like this.
        # I want to do something like this:
        # return super(ProductManager, self).get_query_set().filter(account=self.account)
        # Self being the current model that's using this manager
        # (obviously this is wrong because you're not inside a model
        # instance , but this is where the confusion comes in for me.
        # How would I do this?).

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

Здесь у меня появилась идея сделать это: Проект пространства имен Django

Ответы [ 3 ]

7 голосов
/ 26 января 2010

Есть две тесно связанные проблемы, когда речь идет о Джанго.

Один из них - разрешения на уровне строки , где пользователям / учетным записям требуется специальное разрешение для просмотра конкретной строки (объекта) в таблице, в отличие от обычной среды аутентификации Django, которая имеет разрешения на уровне таблицы .

Проект, на который вы ссылаетесь, является одним из нескольких проектов, пытающихся реализовать разрешения для строк. django-granular-permissions - это еще один, а третий (мой любимый и самый активный / поддерживаемый) - django-авторитет .

В следующем выпуске Django 1.2 будут хуки, упрощающие реализацию разрешений на уровне строк, а автор django-Authority будет работать над интеграцией своего проекта .

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

Я не думаю, что это то, что вы ищете, но вы могли бы использовать некоторые из тех же техник. См. о том, как принудительно разделить учетные записи в мультитенантных приложениях Django Django и . У обоих очень скудные ответы, но они являются отправной точкой, а также рассмотрением мультитенантной архитектуры для приложений Rails и этой статьи .

Что касается более конкретного ответа на ваш вопрос, я думаю, что вы должны либо использовать django-author , либо написать собственный менеджер и использовать средство проверки принадлежности записи во время разработки для проверки ваших запросов не обходят пользовательский менеджер.

2 голосов
/ 25 января 2010

Основная проблема здесь в том, что, даже если вы не используете django.contrib.auth, информация о текущем вошедшем в систему пользователе доступна только в представлении и никогда в модели, потому что эта информация связана с запросом. Так что вам всегда нужно будет делать что-то подобное в представлении:

def some_view(request):
    account = get_account_by_request(request)

Тогда вы можете использовать учетную запись для фильтрации моделей. Вы всегда можете сделать этот подход более элегантным, используя промежуточное ПО или декоратор, но имейте в виду, что это не слишком сложно. Ваш дизайн может сломаться в неожиданные моменты (со мной) из-за слишком большого количества множественных наследований с унаследованными менеджерами и т.п. Сохраняйте это простым и предсказуемым.

1 голос
/ 25 января 2010

Чтобы получить текущего пользователя в свой код, вы можете использовать промежуточное программное обеспечение threadlocals , но в этом нет ничего фантастического, только один большой взлом, так что следите:)

Лично я считаю, что плохо внедрять такую ​​логику в модели, потому что они просто данные и не должны знать о таких вещах.

...