DRY添加创建/修改的方式和时间

Rya*_*yan 63 python django

有类似的东西

  • 由...制作
  • 创建日期
  • modified_by
  • 修改日期

对于很多表来说,这将是一种非常常见的模式.

1)您可以在model.py中自动设置创建日期(但不能设置其他日期)

created_date = models.DateTimeField(auto_now_add=True, editable=False)
Run Code Online (Sandbox Code Playgroud)

2)您可以在model.py中创建/修改日期(但不是/ user,因为没有请求上下文)

def save(self):
    if self.id:
        self.modified_date = datetime.now()
    else:
        self.created_date = datetime.now()
    super(MyModel,self).save()
Run Code Online (Sandbox Code Playgroud)

3)您可以在admin.py中设置创建/修改日期 - 但这不涉及非管理员更新

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()
Run Code Online (Sandbox Code Playgroud)

4)最后的位置将在view.py中,它可以完成所有4,但不包括管理员更新.

所以现实必须要有逻辑分散,至少在3和4中重复(或者从两者调用的模型上的方法,这将被遗漏)

什么是更好的方式?(我已经使用python/django工作了几天所以很容易丢失一些明显的东西)

  • 你可以做像@login_required这样的事情,例如@ audit_changes
  • 您是否可以访问模型中的请求和当前用户并集中逻辑?

vdb*_*oor 95

创建/修改日期现在可以由Django处理,因此可以像下面这样实现:

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

    class Meta:
        abstract = True
Run Code Online (Sandbox Code Playgroud)

通过将其添加到抽象模型基类,可以轻松地将其添加到应用程序的所有模型中.

存储用户更难,因为request.user它不可用.正如SeanOC所提到的,这是Web请求和模型层之间的关注点分离.您可以一直传递此字段,也可以存储request.user在threadlocal中.Django CMS为他们的权限系统执行此操作.

class CurrentUserMiddleware(object):
    def process_request(self, request):
        set_current_user(getattr(request, 'user', None))
Run Code Online (Sandbox Code Playgroud)

用户跟踪发生在其他地方:

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)
Run Code Online (Sandbox Code Playgroud)

对于非Web环境(例如管理命令),您必须set_current_user在脚本的开头调用.

  • 在 Django==1.10.2 中使用它会破坏中间件。您必须使用 `class CurrentUserMiddleware(MiddlewareMixin):` 意味着您导入 `from django.utils.deprecation import MiddlewareMixin` [根据此 django 链接](https://docs.djangoproject.com/en/1.10/topics/http /middleware/#upgrading-pre-django-1-10-style-middleware) (2认同)

Sea*_*nOC 9

对于带时间戳的模型,您可能需要查看django-model-utilsdjango-extensions.它们每个都包含抽象基类,可自动处理已创建和上次修改的时间戳.您可以直接使用这些工具,也可以查看他们如何解决问题并提出自己的解决方案.

至于你的其他问题:

你可以做像@login_required这样的事情,例如@ audit_changes

可能是的,但你必须非常小心保持线程安全.您可能做的是在@audit_changes装饰器中,设置一个标志以在threadlocal中启用审计.然后,在模型的save方法或信号处理程序中,您可以检查审计标志并记录您的审计信息(如果已设置标志).

您是否可以访问模型中的请求和当前用户并集中逻辑?

是的,但你会做出权衡.正如您稍微谈到的那样,Django的ORM与它的请求/认证处理位之间存在非常明确且有意的分离.有两种方法可以从请求(当前用户)到ORM(您的模型)获取信息.您可以手动管理更新对象上的创建者/修改器信息,也可以设置自动处理维护工作的机制.如果采用手动方法(通过方法调用将信息从视图中的请求传递到ORM),维护/测试的代码将更多,但您可以保持关注点的分离.使用手动方法,如果您必须在请求/响应周期之外使用对象(例如,cron脚本,延迟任务,交互式shell),您将会处于更好的状态.如果您可以分解关注点的分离,那么您可以设置一些内容,在中间件中将当前用户设置为本地线程,然后在模型的save方法中查看本地线程.与手动方法相反,您将需要处理的代码较少,但如果您希望在请求/响应周期之外处理对象,则会遇到更难的时间.此外,您必须非常小心地使用更自动化的方法保持所有线程安全.