Джанго: Как можно организовать этот большой беспорядок моделей / менеджеров / дизайнеров?
Подводя итог, прежде чем я приведу к плохим примерам, и др: я пытаюсь создать приложение, в котором мне не нужно писать код во всех моих моделях, чтобы ограничить выбор текущей зарегистрированной учетной записью (я не использую 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 ответа
Когда речь заходит о Джанго, есть две тесно связанные проблемы.
Одним из них являются разрешения на уровне строк, когда пользователям / учетным записям требуются специальные разрешения для просмотра определенной строки (объекта) в таблице, в отличие от обычной среды аутентификации Django, которая имеет разрешения на уровне таблицы.
Проект, на который вы ссылаетесь, является одним из нескольких проектов, пытающихся реализовать разрешения для строк. http://code.google.com/p/django-granular-permissions/ - это еще один, а третий (мой любимый и самый активный / поддерживаемый) - django-Authority.
В следующем выпуске Django 1.2 будут хуки, облегчающие реализацию разрешений на уровне строк, а автор django-Authority будет работать над интеграцией своего проекта.
Вторая связанная с этим проблема - это так называемая многопользовательская база данных, которая представляет собой вариант разрешений на строки. В этой схеме, например, у вас может быть несколько пользователей из одной компании, у которых у всех есть доступ к данным для этой компании, но нет других компаний (арендаторов).
Я не думаю, что это то, что вы ищете, но вы можете использовать некоторые из тех же методов. Узнайте, как обеспечить разделение учетных записей в приложениях Django и мультитенантных django. У обоих очень скудные ответы, но они являются отправной точкой, а также рассмотрением мультитенантной архитектуры для приложений Rails и этой статьи.
Что касается более конкретного ответа на ваш вопрос, я думаю, что вы должны либо использовать django-полномочия, либо написать собственный менеджер и использовать средство проверки владения записями во время разработки, чтобы убедиться, что ваши запросы не обходят пользовательский менеджер.
Основная проблема здесь, даже если вы не используете django.contrib.auth
эта информация о текущем вошедшем в систему пользователе доступна только в представлении и никогда в модели, потому что эта информация связана с запросом. Таким образом, вы всегда должны будете делать что-то подобное в представлении:
def some_view(request):
account = get_account_by_request(request)
Затем вы можете использовать учетную запись для фильтрации моделей. Вы всегда можете сделать этот подход более элегантным, используя промежуточное ПО или декоратор, но имейте в виду, что это не слишком сложно. Ваш дизайн может сломаться в неожиданные моменты (случалось со мной) из-за слишком большого количества множественных наследований с унаследованными менеджерами и т.п. Держите это простым и предсказуемым.
Чтобы получить текущего пользователя в свой код, вы можете использовать промежуточное программное обеспечение threadlocals, но в этом нет ничего особенного, только один большой взлом, так что следите:)
Лично я думаю, что плохо внедрять такую логику в модели, потому что они просто данные и не должны знать о таких вещах.