使用Django和DRF的

时间:2016-11-22 10:57:48

标签: python django django-rest-framework audit-logging django-auditlog

我需要在我的一个使用Django 1.8Django-Rest-Framework 3.2.2的项目中实施审核日志功能。我已经扩展BaseUserManager class来创建用户模型,因为我必须在我的应用程序中使用电子邮件作为用户名(如果此信息很重要)。

下面是我的数据库设计,它将保存日志:

**fields    type    desc**

id           pk      ( auto_increment)  
cust_id   FK  customer 
customer_name   FK  customer
user_id FK  user
user_name   FK  user
module  Varchar(100) sales,order,billing,etc
action  Varchar(10) Create/Update/Delete
previous_value  varchar(500)    
current_value   varchar(500)    
Datetime    Datetime    timestamp of change

我已经尝试了https://pypi.python.org/pypi/django-audit-log,但根据我的要求它有两个问题 -

  1. 它不会根据我的要求捕获数据,我理解这是我的问题所以我修改了它的代码并将我的字段添加到它的模型中。
  2. 它不捕获模块信息。行为是随机的。
  3. 我正在寻求建议继续使用此功能。哪个包最适合我的任务。

    P.S我也试过Django-reversion,我不需要数据版本控制。

    由于

3 个答案:

答案 0 :(得分:3)

我通过修改审计日志代码实现了我所需要的 -

  1. 在审核日志的LogEntry模型中添加了必填字段。
  2. 修改了receiver.py的log_create,log_update和log_delete函数,以便在新添加的字段中保存信息。
  3. 使用这个我已经完成了一半。现在我唯一面临的问题是,由于表中使用的FK,因此1表的模型实例包含其他表的信息。

    为了解决这个问题,我可以提出一个运作良好的解决方案,但我对此并不满意。 我在每个模型中添加了一个类似 include_in_model()的函数,并修改了auditlog的 registry.py register()函数来获取这些字段,并仅使用它来保存LogEntry模型中的信息。

    这种方法需要我在每个模型类中创建这个 include_in_model()函数,并为特定模型传递必需的字段。这样我就避免了与FK相关的信息。

答案 1 :(得分:2)

Django Simple History是我过去在制作项目中使用的优秀应用,它会根据您的用户为您提供模型审核。

此外,您应该创建自己的身份验证类,它将负责记录请求。假设用户使用令牌对您的API进行身份验证。它会在每个HTTP请求的标头中发送到您的API,如下所示:Authorization: Bearer <My Token>。然后,我们应该记录与请​​求相关联的用户,时间,用户的IP和正文。

这很简单:

<强> settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'common.authentication.MyTokenAuthenticationClass'
    ),
    ...
}

<强>公共/ authentication.py

from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

from ipware.ip import get_real_ip
from rest_framework import authentication
from rest_framework import exceptions

from accounts.models import Token, AuditLog


class MyTokenAuthenticationClass(authentication.BaseAuthentication):

    def authenticate(self, request):

        # Grab the Athorization Header from the HTTP Request
        auth = authentication.get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'bearer':
            return None

        # Check that Token header is properly formatted and present, raise errors if not
        if len(auth) == 1:
            msg = _('Invalid token header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid token header. Credentials string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            token = Token.objects.get(token=auth[1])
            # Using the `ipware.ip` module to get the real IP (if hosted on ElasticBeanstalk or Heroku)
            token.last_ip = get_real_ip(request)
            token.last_login = timezone.now()
            token.save()

            # Add the saved token instance to the request context
            request.token = token

        except Token.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token.')

        # At this point, insert the Log into your AuditLog table:
        AuditLog.objects.create(
            user_id=token.user,
            request_payload=request.body,
            # Additional fields
            ...
        )

        # Return the Authenticated User associated with the Token
        return (token.user, token)

答案 2 :(得分:0)

首先,您可以使用用户包https://github.com/jcugat/django-custom-user来解决Email as Username字段。 然后,您可以尝试使用以下内容进行开发:http://django-reversion.readthedocs.io/en/stable/