GithubHelp home page GithubHelp logo

django-auditlog's Introduction

django-auditlog

Jazzband Build Status Docs codecov Supported Python versions Supported Django versions

Migrate to V3

Check the Upgrading to version 3 doc before upgrading to V3.

django-auditlog (Auditlog) is a reusable app for Django that makes logging object changes a breeze. Auditlog tries to use as much as Python and Django's built in functionality to keep the list of dependencies as short as possible. Also, Auditlog aims to be fast and simple to use.

Auditlog is created out of the need for a simple Django app that logs changes to models along with the user who made the changes (later referred to as actor). Existing solutions seemed to offer a type of version control, which was found excessive and expensive in terms of database storage and performance.

The core idea of Auditlog is similar to the log from Django's admin. Unlike the log from Django's admin (django.contrib.admin) Auditlog is much more flexible. Also, Auditlog saves a summary of the changes in JSON format, so changes can be tracked easily.

Documentation

The documentation for django-auditlog can be found on https://django-auditlog.readthedocs.org. The source files are available in the docs folder.

License

Auditlog is licensed under the MIT license (see the LICENSE file for details).

Contribute

If you have great ideas for Auditlog, or if you like to improve something, feel free to fork this repository and/or create a pull request. I'm open for suggestions. If you like to discuss something with me (about Auditlog), please open an issue.

Releases

  1. Make sure all tests on master are green
  2. Create a new branch vX.Y.Z from master for that specific release
  3. Update the CHANGELOG release date
  4. Pull request vX.Y.Z -> master
  5. As a project lead, once the PR is merged, create and push a tag vX.Y.Z: this will trigger the release build and a notification will be sent from Jazzband of the availability of two packages (tgz and wheel)
  6. Test the install
  7. Publish the release to PyPI

django-auditlog's People

Contributors

jjkester avatar hramezani avatar pre-commit-ci[bot] avatar aleh-rymasheuski avatar audiolion avatar aqeelat avatar linkid avatar kbussell avatar 2ykwang avatar scotteadams avatar kurocon avatar vfigueiro avatar sum-rock avatar cleitondelima avatar francofuji avatar jezdez avatar johnrtipton avatar skorokithakis avatar rptmat57 avatar gwax avatar ppmathis avatar nathan-cohen avatar dependabot[bot] avatar fsniper avatar openrijal avatar arhell avatar fernandoe avatar theskumar avatar fgsamuel avatar ilius avatar

Stargazers

lonexd3vil avatar AJGUMIRAN avatar Piotr Siemieniak avatar Mohammad Massri avatar Ricardo Lenzi avatar  avatar  avatar Copperfield avatar  avatar Scarred Codez avatar Ionel Cristian Mărieș avatar Bartosz Sławecki avatar sujay avatar Hesam Hashemi avatar Emirhan Soytaş avatar Ole J. Rosendahl avatar HD (Sam) Khosravian avatar  avatar saeed avatar Peyman Salehi avatar Zachary Ross avatar David Higgins avatar  avatar Rob Moorman avatar AnsonCar avatar Khwilo Kabaka avatar li xinge avatar Marc 'risson' Schmitt avatar Lukas Richter avatar Pranta Chakraborty avatar  avatar Mohamed Habib Khattat - ARABSOFT  avatar Rohit avatar  avatar  avatar Randy Tan avatar Ali Abharya avatar  avatar Andres Hermosilla avatar Rowan Knight avatar jlobbes avatar Alex Adewole avatar  avatar Mostafa Nasser  avatar Cesar Carriel avatar Ha Doan avatar Ferdina Kusumah avatar Riso Tech Co.,Ltd. avatar day qinyanjui avatar Aryaman avatar  avatar  avatar Ilja Leiko avatar Kamyar Bashar avatar Attila Gulyas avatar  avatar Paul Keith avatar Israel Akinoso avatar Madalin Popa avatar Yasser Sinjab avatar Pete Doherty avatar Sky Guy avatar Geoff avatar  avatar Thanh Nguyen avatar Michael Basmanov avatar Lukash avatar Sergio Livi avatar Anne avatar 사재혁 avatar R. Mathieu Landvreugd avatar Luiggy Silva avatar Anton Makushchenko avatar Luiz Felipe Warmling Amadeu avatar Scott Werner avatar Davi Silva Rafacho avatar Kevin Trebing avatar  avatar David avatar mojtabaa hn avatar Sherry_AB avatar Arian avatar  avatar Sergei avatar Toni Sanmateu avatar Kyle Sin Lynn avatar Davorin Šego avatar Tomáš Daniel avatar Joe Chevalier avatar Алим Байрамуков avatar Daniel avatar Brett Weir avatar Nima HeydariNasab avatar Nicolas Delaby avatar Ali avatar Preeti Yuankrathok avatar springtian avatar jon ⚝ avatar Sezer Bozkır avatar Precious Imoniakemu avatar

Watchers

 avatar  avatar jmny avatar Michael Heumann avatar Minh-Triet Pham Tran avatar  avatar James Cloos avatar Scott Werner avatar Rui Neto avatar Duncan Abela avatar Lukas Vojt avatar  avatar rorosan avatar  avatar Gerri avatar Luis Duarte avatar  avatar Alan The Achiever avatar Louis Flores avatar Rod Manning avatar  avatar  avatar Sean P. Myrick V19.1.7.2 avatar Gabriel Mouta avatar  avatar

django-auditlog's Issues

Getting Started

Installed django-auditlog, and kept auditlog in the settings.py and also the 'auditlog.middleware.AuditlogMiddleware', in the MIDDLEWARE Classes, but when I run,

pip install django-auditlog

MIDDLEWARE_CLASSES = (
  'auditlog.middleware.AuditlogMiddleware', ) 

in the settings.py file.

Now, on running the server,

./manage.py runserver,  

I get the following,

Operations to perform:
Synchronize unmigrated apps: staticfiles, messages, widget_tweaks, inventory, crispy_forms, 
bootstrap3
Apply all migrations: admin, contenttypes, auditlog, auth, sessions
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Installing custom SQL... 
Running migrations:
Rendering model states... DONE
Applying auditlog.0006_object_pk_index...Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/core/management/__init__.py", 
line 338, in execute_from_command_line
utility.execute()
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/core/management/__init__.py", 
line 330, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/core/management/base.py",
line 
393, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/core/management/base.py", 
 line 
444, in execute
output = self.handle(*args, **options)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site 
-packages/django/core/management/commands/migrate.py", line 221, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/migrations/executor.py", line
110, in migrate
self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/migrations/executor.py", line 
148, in apply_migration
state = migration.apply(state, schema_editor)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/migrations/migration.py", line
115, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site
-packages/django/db/migrations/operations/fields.py", line 201, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/base/schema.py",
line 484, in alter_field
old_db_params, new_db_params, strict)
 File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/base/schema.py",
line 670, in _alter_field
self.execute(self._create_index_sql(model, [new_field], suffix="_uniq"))
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/base/schema.py", 
line 111, in execute
cursor.execute(sql, params)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/utils.py", line 79,  
in
 execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, 
in 
execute
return self.cursor.execute(sql, params)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/utils.py", line 64,
 in
 execute
return self.cursor.execute(sql, params)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/django/db/backends/mysql/base.py", 
line 124, in execute
return self.cursor.execute(query, args)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in
execute
self.errorhandler(self, exc, value)
File "/home/tilaprimera/Envs/tp/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in
defaulterrorhandler
raise errorclass, errorvalue
django.db.utils.OperationalError: (1170, "BLOB/TEXT column 'object_pk' used in key specification
without a key length")

Support for changes in related models

Currently, as discovered in #8, Auditlog does not behave well when it comes to related data.

The following needs improvement:

  • Handle fixture loading (#8)
  • Make sure (test) that save is triggered when a reverse one-to-one relationship is changed. For example, when a different Profile object is assigned to a user from the other side of the relationship. If not, create a workaround for this.
  • Find a way to handle many-to-many relationships (easy logging for through model, easy lookup of data).

AuditlogHistoryField is not working

AuditlogHistoryField is not working with existing model and new models.

class TestAudit(models.Model):
    is_approved = models.BooleanField(default=False)
    history = AuditlogHistoryField()

    def __unicode__(self):
        return '%d' % self.id

auditlog.register(TestAudit)

I can see change history in auditlog_logentry table but not able to access it using AuditlogHistoryField.

Also, in models for south migration introspection rule is written as
add_introspection_rules([], ["^southtut\.fields\.UpperCaseField"]) (Django example one)

Model registration decorators

The current syntax is pretty much the poster child for decorators:

class MyModel(models.Model):
    pass
auditlog.register(MyModel, exclude_fields=["example"])

I propose the following:

@auditlog.register(exclude_fields=["example"])
class MyModel(models.Model):
    pass

Would you be interested in a PR?

Make manual logging easier

(As pointed out in #36)

Proposed solution:

  • Make connecting signals optional (but do it by default) when registering a model
  • Create an easy to use method for creating log entries
    • This method should accept and old and new version of the same instance (which should be checked)
    • This method should determine the correct action
    • This method should allow users to override certain model fields (whether action and changes should be overridden is debatable)
    • This method may be applied elsewhere, for example replacing code in the current signal receivers
  • Investigate whether creating a context manager for with statements is useful
    • This context manager should be outputted by a factory which takes the object instance (and maybe other relevant things) as argument and automatically determine as much as realistically possible without doing black magic

Anyone is free to suggest other implementations as well as submit a pull request for any improvement on the main issue, regardless of the implementation. However, I reserve the right to decline and/or alter any submissions.

auditlog error in django 1.10

Hi,

I installed django 1.10 and followed the doc to add 'auditlog' to INSTALLED_APPS and MIDDLEWARE, the migrate was doing success, however, when I start run_server, the below error shows:

Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x0453DBB8>
Traceback (most recent call last):
  File "D:\dev\envs\django\lib\site-packages\django\utils\autoreload.py", line 226, in wrapper
    fn(*args, **kwargs)
  File "D:\dev\envs\django\lib\site-packages\django\core\management\commands\runserver.py", line 142, in inner_run
    handler = self.get_handler(*args, **options)
  File "D:\dev\envs\django\lib\site-packages\django\contrib\staticfiles\management\commands\runserver.py", line 27, in get_handler
    handler = super(Command, self).get_handler(*args, **options)
  File "D:\dev\envs\django\lib\site-packages\django\core\management\commands\runserver.py", line 64, in get_handler
    return get_internal_wsgi_application()
  File "D:\dev\envs\django\lib\site-packages\django\core\servers\basehttp.py", line 49, in get_internal_wsgi_application
    return import_string(app_path)
  File "D:\dev\envs\django\lib\site-packages\django\utils\module_loading.py", line 20, in import_string
    module = import_module(module_path)
  File "C:\Program Files (x86)\Python35-32\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 665, in exec_module
  File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
  File "xxx\wsgi.py", line 16, in <module>
    application = get_wsgi_application()
  File "D:\dev\envs\django\lib\site-packages\django\core\wsgi.py", line 14, in get_wsgi_application
    return WSGIHandler()
  File "D:\dev\envs\django\lib\site-packages\django\core\handlers\wsgi.py", line 153, in __init__
    self.load_middleware()
  File "D:\dev\envs\django\lib\site-packages\django\core\handlers\base.py", line 82, in load_middleware
    mw_instance = middleware(handler)
TypeError: object() takes no parameters

If I commented below line from MIDDLEWARE

# 'auditlog.middleware.AuditlogMiddleware'

The run_server would work with no errors.

However, after doing some actions and check audit_logentry table, nothing was recorded there.

Any ideas? Thanks very much!

Support Django 1.4

What prevents the app to work on Django 1.4? As far as I could see it's all about the customisable AUTH_USER_MODEL, right? If so, it could be done by setting manually with minor changes.

The point is: I am working in a big project based on Django 1.4 so, I'd rather do this effort on adapting it to support 1.4 too than going through the whole project and upgrading it to 1.5 only because of that.

Index column size too large on MySQL 5.7

django.db.utils.OperationalError: (1709, 'Index column size too large. The maximum column size is 767 bytes.')

Can be fixed by setting max_length=255 in 0006_object_pk_index.py.

Add an admin interface

It would be nice to have a simple admin interface to make it easy for anyone to see, search, and filter the log (e.g., by model name).

How to retrieve auditlog data in template

Hi,

Sorry for the really noob question but I have django-auditlog working as expected but I am just having trouble pulling data out of Django-auditlog into my template.

Just wondering if there is an example project I can use to figure out where I'm going wrong?

{% for data in auditlog %}
{{data.actor_id}} - {{ data.name }}
{% endfor %}

actor_id works but I can't get name to work :( Any help would be appreciated

django.contrib.contenttypes.generic is deprecated

This warning appears when I run my project
env/lib/python2.7/site-packages/auditlog/models.py:6: RemovedInDjango19Warning: django.contrib.contenttypes.generic is deprecated and will be removed in Django 1.9. Its contents have been moved to the fields, forms, and admin submodules of django.contrib.contenttypes.

Problem with threadlocal

When doing an ajax request that performs an update I am getting the following:

File "/project/venv/lib/python2.7/site-packages/auditlog/middleware.py", line 74, in set_actor
    instance.remote_addr = threading.local().auditlog['remote_addr']
AttributeError: 'thread._local' object has no attribute 'auditlog'

Seems that by the time its reached that block the threading.local() is missing auditlog. Changing to use 'instance.remote_addr = threadlocal.auditlog['remote_addr']' seems to fix it up though.

Wrong user is written to audit log

Found that sometimes a wrong user is written to audit log when there is a high concurrency in access to server. Some investigations shown that the reason of it is AuditlogMiddleware imperfections, specifically a multiple signal receiver setup for LogEntry pre-save (https://github.com/jjkester/django-auditlog/blob/master/src/auditlog/middleware.py#L46)

A possible chain of events to reproduce the bug:

  1. User A does a request to the server, AuditlogMiddleware attaches a signal receiver to LogEntry, with signal_duidspecific to thread that prcesses the request of the user A.
  2. User B does a request to the server, AuditlogMiddleware also attaches a signal receiver to LogEntry, with signal_duidspecific to thread that prcesses the request of the user B
  3. Thread that processes request of user B does a write to LogEntry table, so pre-save signal for LogEntry is triggered.
  4. Because two signal handlers are attached to LogEntry pre-save at the moment (for user A and B), they are triggered sequentially, with the first one specific for user A, so user A is written to actor field of LogEntry record.
  5. After, signal handler specific to user B is triggered, but because of overwrite protection (https://github.com/jjkester/django-auditlog/blob/master/src/auditlog/middleware.py#L77) the user isn't written to the LogEntry record, leaving incorrect user A in a record for user B
  6. After the request of user B is processed, its signal handler is removed from LogEntry pre-save signal handlers by its specific signal_duid, leaving the only signal handler for user A, so any LogEntry writes for the user will write correct actor.
  7. At the end of user A request, its signal handler for LogEntry is removed by its signal_duid

There are also some thoughts about how to fix it: when currying set_actor to request user (https://github.com/jjkester/django-auditlog/blob/master/src/auditlog/middleware.py#L45), we can also curry signal_duid stored in threading.local, and when actually doing an actor write in set_actor, check if passed signal_duid matches the current value in threading.local. Match would mean that we execute signal handler of corresponding thread, so write the actor value, and avoid any writes on mismatch - because its a signal handler for different thread/user.

Problems with loading fixtures

I'm having problems with using this and also having fixtures -- seems to come down to a lot of instances where a related object doesn't exist yet.

I was going to wrap your code with try: ... except ObjectDoesNotExist: ... and submit the code back to you ... but I'm wondering if it would be preferable to just turn off tracking during fixture loading -- and is that even possible?

Auditlog needs more unit tests

At the moment not all crucial functionality is (correctly) tested. It would be nice if the unit tests are extended to a level that the correct behaviour of the most important functionality can be guaranteed by running the tests.

I posted this issue so the community is aware of this and can help out by writing the tests. If you wrote tests, please post a new pull request referencing this issue.

ValueError: astimezone() cannot be applied to a naive datetime

Hello, it appears that the fix applied to resolve #82 is triggering an error in our environment. I've included a partial stack trace below.

Django 1.8 is configured with the following timezone settings:

TIME_ZONE = 'UTC'
USE_TZ = True

Partial stack trace:

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 710, in save
    force_update=force_update, update_fields=update_fields)
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 747, in save_base
    update_fields=update_fields, raw=raw, using=using)
  File "/usr/local/lib/python2.7/dist-packages/django/dispatch/dispatcher.py", line 201, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/usr/local/lib/python2.7/dist-packages/auditlog/receivers.py", line 16, in log_create
    changes = model_instance_diff(None, instance)
  File "/usr/local/lib/python2.7/dist-packages/auditlog/diff.py", line 131, in model_instance_diff
    new_value = get_field_value(new, field)
  File "/usr/local/lib/python2.7/dist-packages/auditlog/diff.py", line 69, in get_field_value
    value = timezone.make_naive(value, timezone=timezone.utc)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/timezone.py", line 376, in make_naive
    value = value.astimezone(timezone)
ValueError: astimezone() cannot be applied to a naive datetime

Our model definition:

class InventoryAsset(Model):
  created = DateTimeField()

In this case, it looks like our timestamp is already naive? I haven't yet checked out the code, but I suspect the quick fix is first checking to see if the value is already naive. I will keep this issue updated if I discover anything else.

CHANGELOG

Hi,
do you have changelog anywhere? I could not find any.

Log only admin panel action

What is easiest way to change that code to log only things, that happened via admin panel ?

That app is very usefull for me, but now is logging all changes made on model instance, and I would like to have logged only things done by admin panel.

Cascade delete

class A(models.Model):
    ...

class B(models.Model):
    a = models.ForeignKey('A')

class C(models.Model):
    b = models.ForeignKey('B')

def log_delete(sender, instance, **kwargs):
    logging

auditlog.register(A)
auditlog.register(C)

When you delete an instance of A cascade delete occurs removing B and C instances. How can I disable signal for child instances on cascade delete by django?

Have changes_dict show get_<field_name>_display

If I have a model with some choices

class MyModel(models.Model):
    STATUS_CHOICES = (
        ('a', 'ACTIVE'),
        ('d', 'DISABLED'),
    )
    status = models.CharField(choices=STATUS_CHOICES, max_length=1, default='d')

If I update my model with an auditlog attached to it and get the changes_dict for the log entry I will get

[ 'status': [u'd', u'a'] ]

Is there a way to get the models get_status_display() method for that to give

[ 'status': [u'DISABLED', u'ACTIVE'] ]

Data in 'changes' field is unicode-escaped

I'm using django-auditlog with python 2.7.6 and django 1.9.

My source files are encoded with utf-8, so there is a # coding=utf-8 statement in the first lines. I have also imported unicode_literals from __future__

The issue is that while Logentry.changes correctly stores the changes in my data, every accented character is converted to escaped unicode characters before saving. I can workaround this issue with a simple get_queryset() override, but maybe letting django convert special characters would be a more elegant solution.

Here is my workaround code:

# coding=utf-8
from __future__ import unicode_literals

..

class AuditView(generic.ListView):
    model = LogEntry

    def get_queryset(self):
        result = LogEntry.objects.get_for_model(Kod)
        for row in result:
            row.changes = row.changes.decode('unicode-escape')
        return result

flake8 adherence

The codebase currently doesn't include formatting or styling standards, do you mind if we use flake8? In general it looks like you have stuck to 120 characters max and the usual flake8 standards, it is just never formally declared.

I can create a new PR for this:

  • add .flake8 config
  • fix all .flake8 errors or add noqa where sensical
  • add flake8 testing to .travis.yml builds
  • update documentation about using flake8
  • add flake8 to requirements documentation
  • integrate with coveralls or codecov and add a badge to README

Release to PyPI

Hi! We are currently being bit by the User.full_name issue from #83. I see that that has been fixed in #85 and is in master, however there is not an updated version in PyPI.

Could a new version of django-auditlog please be released to PyPI?

Thanks!

Tests for the middleware

Currently the middleware that Auditlog relies (heavily) on can only be tested by manually browsing a test site. It would be nice if this could be automated so that issues with the middleware can be found easily.

auditlogflush missing?

Docs says it comes with version 0.4.0. That's not the case. Unless I did something wrong. Any idea why that management command is missing?

Selective logging of changes

Consider a model A. This model gets updated in the following 2 ways:
(a) Non-user facing interface that constantly creates/updates model A instances.
(b) User facing interface where creates/updates to db instances can be done manually(django-admin interface is a good example).
In my use-case, I only want to track the changes done by a user via the user facing interface.

Would it be possible to check for an optional model instance attribute or an attribute passed with save as a kwargs ,e.g., "_skip_logging" if it is set to True in model_instance_diff and if so, return a distinct value like a constant int (-1) or a string "SKIP_LOGGING" . This value can be checked before creating a Log entry receivers.py and there by making logs so much more useful.

Thoughts, suggestions?

Audilog generating Deadlocks in log_create function with high volume of requests

We use auditlog in a high traffic site using MySql(PyMySQL==0.7.9 and Gevent) and it is giving us Deadlocks:

InternalError: (1213, u'Deadlock found when trying to get lock; try restarting transaction')

Please, could you retry for three times using something like this?:

import time 

from django.db import OperationalError

class DeadLockFreeManager(models.Manager):
    
    def create(self, **kwargs):
        attempts = 0
        while attempts < 3:
            try:
                return super(DeadLockFreeManager, self).create(**kwargs)
            except OperationalError as e:
                code = e.args[0]
                if attempts == 2 or code != 1213:
                    raise e
                attempts += 1
                time.sleep(0.2)
                

class LogEntryManager(DeadLockFreeManager):

As you can see in the Deadlock is created in log_create function when it is trying to create the record:

return self.create(**kwargs)

Sorry I haven't test the code yet but I hope I am giving enough information to fix the issue.

Stack trace:

File "/usr/local/lib/python2.7/dist-packages/auditlog/receivers.py", line 21, in log_create
   changes=json.dumps(changes),
 File "/usr/local/lib/python2.7/dist-packages/auditlog/models.py", line 56, in log_create
   return self.create(**kwargs)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 127, in manager_method
   return getattr(self.get_queryset(), name)(*args, **kwargs)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 348, in create
   obj.save(force_insert=True, using=self.db)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 734, in save
   force_update=force_update, update_fields=update_fields)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 762, in save_base
   updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 846, in _save_table
   result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 885, in _do_insert
   using=using, raw=raw)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 127, in manager_method
   return getattr(self.get_queryset(), name)(*args, **kwargs)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 920, in _insert
   return query.get_compiler(using=using).execute_sql(return_id)
 File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 974, in execute_sql
   cursor.execute(sql, params)
 File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
   return self.cursor.execute(sql, params)
 File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 98, in __exit__
   six.reraise(dj_exc_type, dj_exc_value, traceback)
 File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
   return self.cursor.execute(sql, params)
 File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 124, in execute
   return self.cursor.execute(query, args)
 File "/usr/local/lib/python2.7/dist-packages/pymysql/cursors.py", line 134, in execute
   result = self._query(query)
 File "/usr/local/lib/python2.7/dist-packages/pymysql/cursors.py", line 282, in _query
   conn.query(q)
 File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 768, in query
   self._affected_rows = self._read_query_result(unbuffered=unbuffered)
 File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 929, in _read_query_result
   result.read()
 File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 1125, in read
   first_packet = self.connection._read_packet()
 File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 893, in _read_packet
   packet.check_error()
 File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 369, in check_error
   err.raise_mysql_exception(self._data)
 File "/usr/local/lib/python2.7/dist-packages/pymysql/err.py", line 120, in raise_mysql_exception
   _check_mysql_exception(errinfo)
 File "/usr/local/lib/python2.7/dist-packages/pymysql/err.py", line 115, in _check_mysql_exception
   raise InternalError(errno, errorvalue)
InternalError: (1213, u'Deadlock found when trying to get lock; try restarting transaction')

Warning about `SubfieldBase` deprecation

I've installed the app and installation looks good, tests run fully and I am seeing expected functionality. However, when running all mange.py commands post-installation, I get the following deprecation warnings:

e:\Utilities\Python\Python34\lib\site-packages\django\utils\six.py:808: RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.
  return meta(name, bases, d)

e:\Utilities\Python\Python34\lib\site-packages\jsonfield\fields.py:139: RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.
  class TypedJSONField(JSONField):

Using django 1.9.4, django-auditlog 0.3.3.

Migration fails with unknown migration directory

On a new database the migrate fails as follows:

# python manage.py migrate 
Traceback (most recent call last):
  File "manage.py", line 8, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/core/management/__init__.py", line 354, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/core/management/__init__.py", line 346, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/core/management/commands/migrate.py", line 93, in handle
    executor = MigrationExecutor(connection, self.migration_progress_callback)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/db/migrations/executor.py", line 19, in __init__
    self.loader = MigrationLoader(self.connection)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/db/migrations/loader.py", line 47, in __init__
    self.build_graph()
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/db/migrations/loader.py", line 185, in build_graph
    self.load_disk()
  File "/usr/local/lib/python2.7/dist-packages/Django-1.8.7-py2.7.egg/django/db/migrations/loader.py", line 93, in load_disk
    for name in os.listdir(directory):
OSError: [Errno 20] Not a directory: '/usr/local/lib/python2.7/dist-packages/django_auditlog-0.3.3-py2.7.egg/auditlog/migrations'

My workaround was to add zip_safe=False to setup.py and re-install.

Integrate AuditLog to default history page

The core idea of Auditlog is similar to the log from Django’s admin. Unlike the log from Django’s admin (django.contrib.admin) Auditlog is much more flexible. Also, Auditlog saves a summary of the changes in JSON format, so changes can be tracked easily.

Considering this design purpose, it would be good to integrate or replace the default history view page with AuditLog log page, this will make the history page info more comprehensive and useful.

The implementation may need create a base ModelAdmin page and let all Admin page inherits it. It's better if the JSON changes can be shown in a beautiful format than the raw data.

Thanks.

Use Django 1.7+ migrations

This will cause issues with Django 1.5 and 1.6 which are currently supported. No South migrations will be provided.

Support new app loading style

Todo list

  • Create app config
  • Set app config in __init__.py
  • Document app config

Considerations

  • Check if anything needs to be moved to AppConfig.ready() (signals e.d.)

Purge logs

Is the only way to purge logs to manually go in and delete the objects?

Error codeship

CommandError: Conflicting migrations detected (0006_object_pk_index, 0005_auto_20151010_1453 in auditlog).
To fix them run 'python manage.py makemigrations --merge'

I'm taking this error when I try to use the 0.3.2 version in codeship.
Apparently, there is some problem with these migrations.
I'm having to use the 0.3.1 version.
Thank you.

Adding Auditlog to Installed Apps causes PostreSQL JSON fields to be re-encoded on model save, without explicity registering the model

Following Django's documentation for PostgreSQL's JSON field: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#querying-jsonfield

I get some weird behaviour after including AuditLog in my installed apps:

#models.py

from django.contrib.postgres.fields import JSONField
from django.db import models


class Dog(models.Model):
    name = models.CharField(max_length=200)
    data = JSONField()

    def __str__(self):  # __unicode__ on Python 2
        return self.name

#settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'audittest',
        'USER': 'audittest',
        'PASSWORD': 'audittest',
        'HOST': 'localhost',
        'PORT': '',
    }
}

# pip freeze

(venv) jwe in ~/Documents/audittest λ pip freeze 
Django==1.10.1
django-auditlog==0.4.0
django-jsonfield==1.0.1
psycopg2==2.6.2

./manage.py shell

(venv) jwe in ~/Documents/audittest λ ./manage.py shell
Python 3.4.2 (default, Oct  8 2014, 10:45:20) 
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from jsontest.models import Dog
>>> Dog.objects.create(name='Meg', data={'breed': 'collie'})
<Dog: Meg>
>>> Dog.objects.first().data
'{"breed": "collie"}'
>>> Dog.objects.first().save()
>>> Dog.objects.first().data
'"{\\"breed\\": \\"collie\\"}"'
>>> Dog.objects.first().save()
>>> Dog.objects.first().data
'"\\"{\\\\\\"breed\\\\\\": \\\\\\"collie\\\\\\"}\\""'
>>> Dog.objects.first().save()
>>> Dog.objects.first().data
'"\\"\\\\\\"{\\\\\\\\\\\\\\"breed\\\\\\\\\\\\\\": \\\\\\\\\\\\\\"collie\\\\\\\\\\\\\\"}\\\\\\"\\""'
>>> 

Things to note:

  • I did not include 'auditlog.middleware.AuditlogMiddleware'
  • Issue occurs both before and after I run ./manage.py migrate
  • I did not register the model to log for changes with auditlog.register(Dog)

I'll try snooing around the code base this weekend to figure out what's going on, but I can't garuntee anything. Just thought I make this known incase any other people encouter the issue.

Cheers, Jack

DateTimeFields change if the timezone changes.

Hello!

I was trying to implement audits for some models we use, and some of those models use Django DateTimeFields. When I update any field in the model, the auditlog also creates a change entry for the DateTimeField, changing it from timezone UTC to UTC+1, but when Django accesses the model after that, it just gets converted back to UTC time. This makes it so that the DateTimeFields are always marked as changed, even if it is actually the same time. See the image for an example:

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.