Подтвердить что ты не робот

СУХОЙ способ добавления созданных/модифицированных и временных

Что-то вроде

  • created_by
  • created_date
  • MODIFIED_BY
  • MODIFIED_DATE

Будет очень распространенным шаблоном для большого количества таблиц.

1) Вы можете автоматически установить созданную дату (но не другие) в model.py с помощью

created_date = models.DateTimeField(auto_now_add=True, editable=False)

2) Вы могли бы создать/измененные даты (но не через /user, так как не иметь контекста запроса) в model.py с

def save(self):
    if self.id:
        self.modified_date = datetime.now()
    else:
        self.created_date = datetime.now()
    super(MyModel,self).save()

3) Вы можете установить созданную/модифицированную дату и в admin.py - но это не касается обновлений не admin

def save_model(self, request, obj, form, change):
    if change:
        obj.modified_by = request.user
        obj.modified_date = datetime.now()
    else:
        obj.created_by = request.user
        obj.created_date = datetime.now()
    obj.save()

4) И последнее место будет в view.py, который может выполнять все 4, но не распространяется на обновления администратора.

Таким образом, реалистично должна быть разбросана логика, минимально повторяемая в 3 и 4 (или метод на модели, вызванной из обоих, которая будет пропущена)

Чем лучше? (Я работаю с python/django в течение нескольких дней, поэтому легко можно было бы пропустить что-то очевидное)

  • Можете ли вы сделать что-то вроде @login_required, например. @audit_changes
  • Можете ли вы получить доступ к запросу и текущему пользователю в модели и централизовать там логику?
4b9b3361

Ответ 1

Даты создания/модификации теперь могут обрабатываться Django, поэтому их можно реализовать так:

class BaseModel(models.Model):
    created_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

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

Сохранение пользователя сложнее, так как request.user недоступен. Как упоминалось в SeanOC, это разделение проблем между веб-запросом и уровнем модели. Либо вы проходите это поле все время, либо сохраняете request.user в threadlocal. Django CMS делает это для своей системы разрешений.

class CurrentUserMiddleware(object):
    def process_request(self, request):
        set_current_user(getattr(request, 'user', None))

И отслеживание пользователя происходит в другом месте:

from threading import local
_thread_locals = local()

def set_current_user(user):
    _thread_locals.user=user

def get_current_user():
    return getattr(_thread_locals, 'user', None)

Для не-веб-сред (например, команд управления) вам нужно вызвать set_current_user в начале script.

Ответ 2

Для временных моделей, которые вы, вероятно, захотите посмотреть django-model-utils или django-extensions. Каждый из них включает абстрактные базовые классы, которые автоматически обрабатывают созданную и последнюю измененную временную метку. Вы можете использовать эти инструменты напрямую или посмотреть, как они решили проблему, и придумать собственное решение.

Что касается других вопросов:

Можете ли вы сделать что-то вроде @login_required, например. @audit_changes

Потенциально да, но вы должны быть очень осторожны, чтобы сохранить потоки в безопасности. То, что вы потенциально могли бы сделать, это ваш декоратор @audit_changes, установите флаг для включения аудита в threadlocal. Затем, либо в методе сохранения ваших моделей, либо в обработчике сигналов, вы можете проверить свой флаг аудита и записать свою аудиторскую информацию, если флаг установлен.

Можете ли вы получить доступ к запросу и текущему пользователю в модели и централизовать там логику?

Да, но вы будете делать компромисс. По мере того как вы немного коснулись, существует очень четкое и преднамеренное разделение проблем между Django ORM и битами обработки запроса/аутентификации. Существует два способа получить информацию из запроса (текущего пользователя) в ORM (ваша модель (ы)). Вы можете вручную управлять обновлением информации о создателе/​​модификаторе на своих объектах или вы можете настроить механизм автоматического управления этой работой по техническому обслуживанию. Если вы возьмете ручной подход (передавая информацию через вызовы методов из запроса в представлении ORM), это будет больше кода для поддержки/тестирования, но вы сохраните разделение проблем. Благодаря ручному подходу вы окажетесь в гораздо лучшей форме, если вам придется работать с вашими объектами за пределами цикла запроса/ответа (например, cron-скрипты, отложенные задачи, интерактивная оболочка). Если вы согласны с нарушением этого разделения проблем, тогда вы можете настроить что-то, где вы установите поток локальный с текущим пользователем в промежуточном программном обеспечении, а затем посмотрите на этот поток локально в методе сохранения вашей модели. Обратившись к ручному подходу, у вас будет меньше кода для работы, но вам будет гораздо труднее, если вы когда-нибудь захотите работать с вашими объектами за пределами цикла запроса/ответа. Кроме того, вы должны быть очень осторожны, чтобы сохранить все поточно-безопасные с более автоматизированным подходом.

Ответ 3

Можете ли вы импортировать объект модели пользователя и вызвать get_current()?

Кроме того, я думаю, вы можете вызвать views в admin.py.