添加按时间创建/修改的 DRY 方法

比如说

  • Create _ date
  • 修改 _ by
  • (修改日期)

Would be a very common pattern for a lot of tables.

1)您可以使用

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

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

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

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()

4)最后一个位置是 view.py,它可以完成所有4项任务,但不包括管理员更新。

所以实际上必须有逻辑展开,至少在3 & 4中重复(或者模型上的一个方法从两者调用,这将被忽略)

有什么更好的办法吗?(我已经使用 python/django 工作了几天,所以很容易遗漏一些显而易见的东西)

  • 你能做一些像@login _ need 这样的事情吗
  • 你能够访问模型中的请求和当前用户并将逻辑集中在那里吗?
43182 次浏览

可以导入 User 模型对象并调用 get _ current ()吗?

另外,我认为您可以在 admin.py 中调用视图。

对于时间戳模型,您可能想看看 Django-模型-实用工具姜戈接发。它们都包括抽象基类,这些基类自动处理创建的和最后修改的时间戳。您可以直接使用这些工具,也可以查看它们是如何解决问题并提出自己的解决方案的。

至于你的其他问题:

你能做一些像@login _ need 这样的事情吗

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

你能够访问模型中的请求和当前用户并将逻辑集中在那里吗?

是的,但是你要做一个交易。正如你所触及到的,在 Django 的 ORM 和它的请求/认证处理位之间有一个非常清晰和有意识的关注点分离。有两种方法可以从请求(当前用户)获取信息到 ORM (您的模型)。您可以手动管理对象上的创建者/修改者信息的更新,也可以设置一种机制来自动处理维护工作。如果你采用手工方法(通过方法调用将信息从视图中的请求传递给 ORM) ,那么需要维护/测试的代码将会更多,但是你需要保持关注点分离。使用手动方法,如果您需要在请求/响应周期之外处理对象(例如 cron-script、延迟任务、交互式 shell) ,那么您的状态会好得多。如果你不介意拆分这个关注点分离,那么你可以设置一些东西,在中间件中为当前用户设置一个本地线程,然后在模型的 save 方法中查看这个本地线程。与手动方法相反,您需要处理的代码会更少,但是如果您希望在请求/响应周期之外处理对象,那么将会遇到更多困难。另外,使用更自动化的方法,您必须非常小心地保持所有内容都是线程安全的。

创建/修改日期现在可以由 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 提到的,这是一个介于 web 请求和模型层之间的关注点分离。要么一直传递此字段,要么将 request.user存储在线程本地。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)

For non-web environments (e.g. management commands), you'd have to call set_current_user at the start of the script.