Yet another Django audit log app, hopefully the simplest one.

Overview

django-easy-audit

pypi PyPI - Django Version

Yet another Django audit log app, hopefully the easiest one.

This app allows you to keep track of every action taken by your users.

Quickstart

  1. Install Django Easy Audit by running pip install django-easy-audit.

    Alternatively, you can download the latest release from GitHub, unzip it, and place the folder 'easyaudit' in the root of your project.

  2. Add 'easyaudit' to your INSTALLED_APPS like this:

    INSTALLED_APPS = [
        ...
        'easyaudit',
    ]
  3. Add Easy Audit's middleware to your MIDDLEWARE (or MIDDLEWARE_CLASSES) setting like this:

    MIDDLEWARE = (
        ...
        'easyaudit.middleware.easyaudit.EasyAuditMiddleware',
    )
  4. Run python manage.py migrate easyaudit to create the app's models.

  5. That's it! Now every CRUD event on your whole project will be registered in the audit models, which you will be able to query from the Django admin app. Additionally, this app will also log all authentication events and all URLs requested.

Settings

For an exhaustive list of available settings, please check our wiki.

Below are some of the settings you may want to use. These should be defined in your project's settings.py file:

  • DJANGO_EASY_AUDIT_WATCH_MODEL_EVENTS

  • DJANGO_EASY_AUDIT_WATCH_AUTH_EVENTS

  • DJANGO_EASY_AUDIT_WATCH_REQUEST_EVENTS

    Set these to False to stop logging model, authentication, and/or request events.

  • DJANGO_EASY_AUDIT_UNREGISTERED_CLASSES_EXTRA

    A list of Django models which will be ignored by Django Easy Audit. Use it to prevent logging one or more of your project's models. List items can be classes or strings with app_name.model_name format.

  • DJANGO_EASY_AUDIT_UNREGISTERED_URLS_EXTRA

    A list of URLs which will be ignored by Django Easy Audit. List items are expected to be regular expressions that will be matched against the URL path. Check our wiki for more details on how to use it.

  • DJANGO_EASY_AUDIT_CRUD_DIFFERENCE_CALLBACKS

    May point to a list of callables/string-paths-to-functions-classes in which the application code can determine on a per CRUDEvent whether or not the application chooses to create the CRUDEvent or not. This is different from the registered/unregistered settings (e.g. DJANGO_EASY_AUDIT_UNREGISTERED_CLASSES_EXTRA). This is meant to be for dynamic configurations where the application may inspect the current save/create/delete and choose whether or not to save that into the database or ignore it.

  • DJANGO_EASY_AUDIT_USER_DB_CONSTRAINT

    Default is True. This is reserved for future use (does not do anything yet). The functionality provided by the setting (whether enabled or disabled) could be handled more explicitly in certain code paths (or even internally as custom model managers). For projects that separate the easyaudit database, such that the tables are not on the same database as the user table, this could help with making certain queries easier. Again, this doesn't do anything yet, and if it ever does, the version will be increased and the README will be updated accordingly. If you keep your database together (the standard usage), you have nothing to worry about.

  • DJANGO_EASY_AUDIT_CRUD_EVENT_LIST_FILTER

  • DJANGO_EASY_AUDIT_LOGIN_EVENT_LIST_FILTER

  • DJANGO_EASY_AUDIT_REQUEST_EVENT_LIST_FILTER

    Changeview filters configuration. Used to remove filters when the corresponding list of data would be too long. Defaults are:

    • ['event_type', 'content_type', 'user', 'datetime', ] for CRUDEventAdmin
    • ['login_type', 'user', 'datetime', ] for LoginEventAdmin
    • ['method', 'user', 'datetime', ] for RequestEventAdmin
  • DJANGO_EASY_AUDIT_DATABASE_ALIAS

    By default it is the django default database alias. But for projects that have split databases, this is necessary in order to keep database atomicity concerns in check during signal handlers.

    To clarify, this is only truly necessary for the model signals.

  • DJANGO_EASY_AUDIT_CRUD_EVENT_NO_CHANGED_FIELDS_SKIP

    By default this is False, but this allows the calling project not to save CRUDEvent if the changed fields as determined by the pre_save handler sees that there are no changed fields. We are keeping it off by default so that projects that wish to use this (potentially less CRUDEvent) can choose to turn it on! And those that do not want it (yet or ever), or those that do not closely follow the release notes of this project will have one less worry when upgrading.

  • DJANGO_EASY_AUDIT_READONLY_EVENTS

    Default is False. The events visible through the admin interface are editable by default by a superuser. Set this to True if you wish to make the recorded events read-only through the admin UI.

  • DJANGO_EASY_AUDIT_LOGGING_BACKEND

    A pluggable backend option for logging. Defaults to easyaudit.backends.ModelBackend. This class expects to have 3 methods:

    • login(self, login_info_dict):
    • crud(self, crud_info_dict):
    • request(self, request_info_dict):

    each of these methods accept a dictionary containing the info regarding the event. example overriding:

      import logging
    
      class PythonLoggerBackend:
          logging.basicConfig()
          logger = logging.getLogger('your-kibana-logger')
          logger.setLevel(logging.DEBUG)
    
          def request(self, request_info):
              return request_info # if you don't need it
    
          def login(self, login_info):
              self.logger.info(msg='your message', extra=login_info)
              return login_info
    
          def crud(self, crud_info):
              self.logger.info(msg='your message', extra=crud_info)
              return crud_info

What does it do

Django Easy Audit uses Django signals to listen to the events happenning in your project, such as when a user creates, updates or deletes a registry. This applies to every model of every app in your project.

When any of these events takes place, Django Easy Audit will log it in the model CRUDEvent. You can query this information in the Django Admin app.

Besides logging CRUD events, Django Easy Audit will log all authentication events (such as when a user logs in, out, or fails to log in) and all the URLs requested in the project. This information is stored in models LoginEvent and RequestEvent.

Why you should use it

There are many Django auditing apps out there, but most them require you to change very important parts of your project's code. For example, they require you to add fields to your models, or make them inherit from a certain class. Some of them create a mirror for each of your models, which means duplicate migrations.

It is not that they don't work or that they are not great apps. But in case you need something easier to set up, and you don't want your code to depend so much on a third-party app, Django Easy Audit may be your best choice.

The good thing about this app is that it doesn't get in the way. It is easy and quick to install, and it begins logging everything right away, without you having to inject code anywhere in your project.

Contact

Find me on Twitter at @soynatan, or send me an email to [email protected].

Comments
  • Update that Changed URL fields from CharField to TextField leads to issue on MS SQLServer

    Update that Changed URL fields from CharField to TextField leads to issue on MS SQLServer

    Running migration 0009_auto_20180314_2225 causes the following error:

    Running migrations:
      Applying easyaudit.0009_auto_20180314_2225...Traceback (most recent call last):
      File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
        return self.cursor.execute(sql, params)
      File "/usr/local/lib/python3.6/site-packages/sql_server/pyodbc/base.py", line 520, in execute
        return self.cursor.execute(sql, params)
    pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Column 'url' in table 'easyaudit_requestevent' is of a type that is invalid for use as a key column in an index. (1919) (SQLExecDirectW)")
    
    bug database 
    opened by jdkizer9 26
  • ASGI RequestEvent support

    ASGI RequestEvent support

    I have also created a test which utilizes ASGI (the view being called is synchronous, but that's fine!). Testing websocket at some point would be nice, as well as async views (websockets can be synchronous, which is a pattern django channels offers as a concrete solution). But yes, websockets likely would require django channels (not opposed to making it an extra install which is grabbed by the test runner), and that's outside the scope of this code change as that's not truly supported in django at this time (not natively).

    bug django asgi 
    opened by jheld 19
  • Request Event Instability

    Request Event Instability

    Is anyone running master in a system with many concurrent users? I'm seeing some instability in that the request events don't seem to always point to the correct user when multiple users are accessing the site.

    opened by steverecio 18
  • Potential security issue

    Potential security issue

    I may have found a security issue. I'm not comfortable posting it here yet as I don't want an unpatched vuln out there. I reached out to @soynatan directly via email a few days ago, but haven't heard back yet. Is there anyone else I can reach out to?

    opened by jdkizer9 18
  • Django 3.2 support

    Django 3.2 support

    Thanks for this great package.

    Django made 3.2 release a couple of days ago.

    I wonder if there's any plan to upgrade django-easy-audit to be compatible with it?

    Thanks!

    opened by tian-yi 17
  • Change

    Change "object_id" to be a "CharField"

    The code in this change set migrates the current CrudEvent.object_id from an IntegerField to a CharField as a means to allow various objects with different PK types.

    This includes a change to the model_signals that query's for the object instead of looking for the PK, this is because the common UUIDField as a PK usually has a default, thereofre PK would never be empty, even on creation.

    This also includes a bug fix for post_delete with the PK not being available in the crud_flow closure. See https://github.com/soynatan/django-easy-audit/pull/138#issuecomment-629869400

    Fixes: #131 Fixes: #90

    • [x] Tested with Django 3.0
    • [x] Tested with UUIDField
    • [x] Tested with BigAutoField
    • [x] Added Unit tests for UUIDField and BigAutoField
    • [x] Added Unit tests for deleting objects
    • [x] Added Test models for UUIDField and BigAutoField
    • [x] Added test app endpoints for UUID and BigInt
    • [x] Includes updates to the sqlite DB with data related UUID and BigInt

    Deep dive

    The main purpose of these tests is to ensure current users of this app, will not need worry about the migration that will change the type of object_id from integer to char. All the output below should be the same per test group, i.e. django version and db. If anything should be different, it will be noted below.

    All the test below will do the following

    1. Checkout current master and initialize the test project
    2. Hit test_app/create_obj/ 5 times
    3. Hit test_app/update_obj/?id=N for the 5 items above
    4. print the following to verify the current type of object is int and basic query works
    >>> for x in CRUDEvent.objects.all():
    ...     print(x.content_type, x.object_id, type(x.object_id))
    ...
    test_app | test model 5 <class 'int'>
    test_app | test model 4 <class 'int'>
    test_app | test model 3 <class 'int'>
    test_app | test model 2 <class 'int'>
    test_app | test model 1 <class 'int'>
    test_app | test model 5 <class 'int'>
    test_app | test model 4 <class 'int'>
    test_app | test model 3 <class 'int'>
    test_app | test model 2 <class 'int'>
    test_app | test model 1 <class 'int'>
     >>> CRUDEvent.objects.filter(object_id=int(1))
    <QuerySet [<CRUDEvent: CRUDEvent object (6)>, <CRUDEvent: CRUDEvent object (1)>]>
    
    1. checkout the new branch and run migrations
    2. print the same output as above, ensuring the new type is str and the query still works and returns the same results, by passing it str and int versions.
    >>> for x in CRUDEvent.objects.all():
    ...     print(x.content_type, x.object_id, type(x.object_id))
    ...
    test_app | test model 5 <class 'str'>
    test_app | test model 4 <class 'str'>
    test_app | test model 3 <class 'str'>
    test_app | test model 2 <class 'str'>
    test_app | test model 1 <class 'str'>
    test_app | test model 5 <class 'str'>
    test_app | test model 4 <class 'str'>
    test_app | test model 3 <class 'str'>
    test_app | test model 2 <class 'str'>
    test_app | test model 1 <class 'str'>
    >>> CRUDEvent.objects.filter(object_id='1')
    <QuerySet [<CRUDEvent: CRUDEvent object (6)>, <CRUDEvent: CRUDEvent object (1)>]>
    >>> CRUDEvent.objects.filter(object_id=int(1))
    <QuerySet [<CRUDEvent: CRUDEvent object (6)>, <CRUDEvent: CRUDEvent object (1)>]>
    
    

    Current progress

    | | Django Version | DB | DB Version | | ---- | ---------------- | ---------- | ------------ | | [x] | 3.0 | Postgres | 12.0 | | [x] | 3.0 | Postgres | 11.0 | | [x] | 3.0 | Postgres | 10.0 | | [x] | 3.0 | Postgres | 9 | | [x] | 2.2 | Postgres | 12.0 | | [x] | 2.2 | Postgres | 11.0 | | [x] | 2.2 | Postgres | 10.0 | | [x] | 2.2 | Postgres | 9.0 | | [x]* | 1.11 | Postgres | 12.0 | | [x]* | 1.11 | Postgres | 11.0 | | [x]* | 1.11 | Postgres | 10.0 | | [x]* | 1.11 | Postgres | 9.0 | | [x] | 3.0 | MySQL | 8 | | [x] | 3.0 | MySQL | 5 | | [x] | 2.2 | MySQL | 8 | | [x] | 2.2 | MySQL | 5 | | [x]* | 1.11 | MySQL | 8 | | [x]* | 1.11 | MySQL | 5 |

    Notes

    • Django 1.11 created more CRUDEvent objects (on master branch)
    >>> for x in CRUDEvent.objects.all():
    ...     print(x.content_type, x.object_id, type(x.object_id))
    ...
    test model 5 <class 'int'>
    test model 4 <class 'int'>
    test model 3 <class 'int'>
    test model 2 <class 'int'>
    test model 1 <class 'int'>
    test model 5 <class 'int'>
    test model 4 <class 'int'>
    test model 3 <class 'int'>
    test model 2 <class 'int'>
    test model 1 <class 'int'>
    content type 12 <class 'int'>
    content type 11 <class 'int'>
    content type 10 <class 'int'>
    content type 9 <class 'int'>
    content type 8 <class 'int'>
    content type 7 <class 'int'>
    content type 6 <class 'int'>
    content type 5 <class 'int'>
    content type 4 <class 'int'>
    content type 3 <class 'int'>
    content type 1 <class 'int'>
    
    • After migrating
    content type 18 <class 'str'>
    content type 17 <class 'str'>
    content type 16 <class 'str'>
    content type 15 <class 'str'>
    content type 14 <class 'str'>
    content type 13 <class 'str'>
    test model 5 <class 'str'>
    test model 4 <class 'str'>
    test model 3 <class 'str'>
    test model 2 <class 'str'>
    test model 1 <class 'str'>
    test model 5 <class 'str'>
    test model 4 <class 'str'>
    test model 3 <class 'str'>
    test model 2 <class 'str'>
    test model 1 <class 'str'>
    content type 12 <class 'str'>
    content type 11 <class 'str'>
    content type 10 <class 'str'>
    content type 9 <class 'str'>
    content type 8 <class 'str'>
    content type 7 <class 'str'>
    content type 6 <class 'str'>
    content type 5 <class 'str'>
    content type 4 <class 'str'>
    content type 3 <class 'str'>
    content type 1 <class 'str'>
    
    opened by jsoa 17
  • Programming error when migrating to 1.1.1 on re- char field 0013, postgres

    Programming error when migrating to 1.1.1 on re- char field 0013, postgres

    When I run python manage.py migrate easyaudit I get the following error:

    django.db.utils.ProgrammingError: relation "easyaudit_requestevent_url_37d1b8c4" already exists

    Full stack:

    File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
        return self.cursor.execute(sql, params)
    psycopg2.errors.DuplicateTable: relation "easyaudit_requestevent_url_37d1b8c4" already exists
    
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "manage.py", line 28, in <module>
        execute_from_command_line(sys.argv)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
        utility.execute()
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
        self.fetch_command(subcommand).run_from_argv(self.argv)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
        self.execute(*args, **cmd_options)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
        output = self.handle(*args, **options)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/core/management/base.py", line 83, in wrapped
        res = handle_func(*args, **kwargs)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/core/management/commands/migrate.py", line 234, in handle
        fake_initial=fake_initial,
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/migrations/executor.py", line 121, in migrate
        state = self._migrate_all_backwards(plan, full_plan, fake=fake)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/migrations/executor.py", line 196, in _migrate_all_backwards
        self.unapply_migration(states[migration], migration, fake=fake)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/migrations/executor.py", line 269, in unapply_migration
        state = migration.unapply(state, schema_editor)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/migrations/migration.py", line 175, in unapply
        operation.database_backwards(self.app_label, schema_editor, from_state, to_state)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/migrations/operations/fields.py", line 254, in database_backwards
        self.database_forwards(app_label, schema_editor, from_state, to_state)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/migrations/operations/fields.py", line 249, in database_forwards
        schema_editor.alter_field(from_model, from_field, to_field)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 535, in alter_field
        old_db_params, new_db_params, strict)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/postgresql/schema.py", line 122, in _alter_field
        new_db_params, strict,
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 726, in _alter_field
        self.execute(self._create_index_sql(model, [new_field]))
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 137, in execute
        cursor.execute(sql, params)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/utils.py", line 99, in execute
        return super().execute(sql, params)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/utils.py", line 67, in execute
        return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
        return executor(sql, params, many, context)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
        return self.cursor.execute(sql, params)
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/utils.py", line 89, in __exit__
        raise dj_exc_value.with_traceback(traceback) from exc_value
      File "/Users/antondemeester/.local/share/virtualenvs/oper-product-KNG_xSge/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
        return self.cursor.execute(sql, params)
    django.db.utils.ProgrammingError: relation "easyaudit_requestevent_url_37d1b8c4" already exists
    

    It has to do something with the back and forth from textfield to charfield in the newest version.

    We use Django 2.2.6, and postgresql.

    When reverting to migration 0008, I also get the same error.

    Any idea why this is and how we can fix this?

    When I reverted to easyaudit 1.1 without the bugfix, it worked fine again.

    opened by AntonDeMeester 15
  • Compatibility with Django 2.x

    Compatibility with Django 2.x

    Goal

    The goal of this PR is to allow compatibility between easy_audit and Django v 2.x.

    Implementation Details

    Django 2 signal receivers do not accept an environ parameter anymore. Instead, this information is taken from the request scope.

    Discussion

    Also, I've updated the URL column to use a Charfield, so that the library accommodates MySQL users.

    opened by dopatraman 13
  • M2M changes now logged

    M2M changes now logged

    Added new event types to separate addition and deletion of M2M relations.

    (M2M_ADD, _('Many-to-Many Add')),
    (M2M_ADD_REV, _('Reverse Many-to-Many Add')),
    (M2M_REMOVE, _('Many-to-Many Remove')),
    (M2M_REMOVE_REV, _('Reverse Many-to-Many Remove')),
    

    M2M changes are logged in the following format: Changed groups on user

    {"groups": [1, 2]}
    

    Changed permissions on group

    {"permissions": [9, 10, 11, 12]}
    
    opened by Real-Gecko 12
  • Django4.0 compatibility

    Django4.0 compatibility

    What does this do?

    • replace force_text with force_str
    • replace smart_text with smart_str
    • replace from django.conf.urls import url with from django.urls import re_path

    closes: https://github.com/soynatan/django-easy-audit/issues/206

    opened by aymaneMx 11
  • Migration missing for field ID

    Migration missing for field ID

    Migrations were not included for commit fd05524dec14316a29191ad3e2934b99ee44843c.

    Please add the missing migrations so that running "makemigrations" is not required after installing django-easy-audit.

    opened by majikman111 10
  • XSS / HTML injection when deleting a record ?

    XSS / HTML injection when deleting a record ?

    I was wondering how come in the easyaudit.admin.CRUDEventAdmin.object_repr_link we escape the obj.object_repr only when the operation is not a CRUDEvent.DELETE.

    For example: if you create a record with a field value of "" and then you delete the record the javascript would be executed when going to the crudevent changelist!

    def object_repr_link(self, obj):
            if obj.event_type == CRUDEvent.DELETE:
                html = obj.object_repr
            else:
                escaped_obj_repr = escape(obj.object_repr)
                try:
                    content_type = self.get_content_type(obj)
                    url = reverse("admin:%s_%s_change" % (
                        content_type.app_label,
                        content_type.model,
                    ), args=(obj.object_id,))
                    html = '<a href="%s">%s</a>' % (url, escaped_obj_repr)
                except Exception:
                    html = escaped_obj_repr
            return mark_safe(html)
    
    opened by GigiusB 0
  • User object not recorded

    User object not recorded

    I noticed that the User object was not being recorded for request events. Is anyone else running into this? Previously it seemed to be isolated to requests using token authentication (knox-rest-auth) now I'm seeing it for django-allauth authentication schemes as well (running v1.3.3)

    opened by steverecio 2
  • Poor performance due to datetime column is not indexed

    Poor performance due to datetime column is not indexed

    Hi, we noticed very slow performance on showing the logs in production. This is due to the default sorting on "datetime" column, but it's not indexed.

    Normally people would not notice this issue unless they have massive logs like us.

    Please add the index. Thx!

    opened by 3cp 9
  • How to get Client timeZone date and time in Logs

    How to get Client timeZone date and time in Logs

    The Current audit logging (loginevent) has datetime as server, but need user timezone

    will require to add pytz and utilize from django.utils import timezone , but not sure how to change it

    requesting assistance @soynatan [Natán]

    opened by rshnGhost 2
Releases(v1.3.4a2)
  • v1.3.4a2(Sep 4, 2022)

    What's Changed

    • Allow to ignore request.user validation by @hugobranquinho in https://github.com/soynatan/django-easy-audit/pull/233
    • Avoid DB savepoints if no audit is going to be created by @hugobranquinho in https://github.com/soynatan/django-easy-audit/pull/232
    • Fixes issue #229 (ImproperlyConfigured error raised in auth_signals.p… by @LukaRiba in https://github.com/soynatan/django-easy-audit/pull/231
    • ASGI scope client value should be converted to the remote_ip by @nnseva in https://github.com/soynatan/django-easy-audit/pull/205

    New Contributors

    • @hugobranquinho made their first contribution in https://github.com/soynatan/django-easy-audit/pull/233
    • @LukaRiba made their first contribution in https://github.com/soynatan/django-easy-audit/pull/231
    • @nnseva made their first contribution in https://github.com/soynatan/django-easy-audit/pull/205

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.4a1...v1.3.4a2

    Source code(tar.gz)
    Source code(zip)
  • v1.3.4a1(Sep 4, 2022)

    What's Changed

    • Fix migration 0013 IrreversibleError by @Lukasdoe in https://github.com/soynatan/django-easy-audit/pull/236
    • Add helper to show CRUD history for particular object by @kirmalyshev in https://github.com/soynatan/django-easy-audit/pull/193

    New Contributors

    • @Lukasdoe made their first contribution in https://github.com/soynatan/django-easy-audit/pull/236
    • @kirmalyshev made their first contribution in https://github.com/soynatan/django-easy-audit/pull/193

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.3...v1.3.4a1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3(Jun 30, 2022)

  • v1.3.3b3(Jun 30, 2022)

    What's Changed

    • Fix #221: Using DjangoJSONEncoder by @MaehMaeh in https://github.com/soynatan/django-easy-audit/pull/223

    New Contributors

    • @MaehMaeh made their first contribution in https://github.com/soynatan/django-easy-audit/pull/223

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.3b2...v1.3.3b3

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3b2(May 24, 2022)

    What's Changed

    • Fix EasyAuditModelAdmin.has_delete_permission() by @cybelew in https://github.com/soynatan/django-easy-audit/pull/224

    New Contributors

    • @cybelew made their first contribution in https://github.com/soynatan/django-easy-audit/pull/224

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.3b1...v1.3.3b2

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3b1(Apr 7, 2022)

    What's Changed

    • remove default_config for Django versions 3.2+ by @mschoettle in https://github.com/soynatan/django-easy-audit/pull/226

    New Contributors

    • @mschoettle made their first contribution in https://github.com/soynatan/django-easy-audit/pull/226

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.3a6...v1.3.3b1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3a6(Mar 11, 2022)

    What's Changed

    • Fix #167 by @steverecio in https://github.com/soynatan/django-easy-audit/pull/215

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.2...v1.3.3a6

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3a5(Mar 10, 2022)

    What's Changed

    • And french translation by @tboulogne in https://github.com/soynatan/django-easy-audit/pull/222

    New Contributors

    • @tboulogne made their first contribution in https://github.com/soynatan/django-easy-audit/pull/222

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.2...v1.3.3a5

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3a4(Feb 25, 2022)

    We have opted to explicity set the app config setting so there should not be a migration generated. even if there is, there should be no change for users (unless of course they chose to run the previous migration generation request from django before this change, and that's out of scope for this problem).

    What's Changed

    • fix: migration missing for field ID by @aymaneMx in https://github.com/soynatan/django-easy-audit/pull/217

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.2...v1.3.3a4

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3a3(Feb 12, 2022)

    django 4 and adds support for m2m clear.

    What's Changed

    • Django4.0 compatibility by @aymaneMx in https://github.com/soynatan/django-easy-audit/pull/211
    • Update Django version in setup.py by @Real-Gecko in https://github.com/soynatan/django-easy-audit/pull/213
    • Fix bug on Many-To-Many clear() (#171) by @AriAbr in https://github.com/soynatan/django-easy-audit/pull/210

    New Contributors

    • @Real-Gecko made their first contribution in https://github.com/soynatan/django-easy-audit/pull/162
    • @aymaneMx made their first contribution in https://github.com/soynatan/django-easy-audit/pull/211
    • @AriAbr made their first contribution in https://github.com/soynatan/django-easy-audit/pull/210

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.2...v1.3.3a3

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3a2(Feb 11, 2022)

  • v1.3.2(Dec 16, 2021)

    django 3.2, python 3.9-3.10 support

    What's Changed

    • Make models translatable and add Russian translation by @Real-Gecko in https://github.com/soynatan/django-easy-audit/pull/162
    • M2M changes now logged by @Real-Gecko in https://github.com/soynatan/django-easy-audit/pull/163
    • Added missing migration by @Real-Gecko in https://github.com/soynatan/django-easy-audit/pull/164
    • CI builds install explicit django version by @jheld in https://github.com/soynatan/django-easy-audit/pull/166
    • Add new Django/Python versions by @serl in https://github.com/soynatan/django-easy-audit/pull/198
    • use TransactionTestCase for asgi test by @jkarstens in https://github.com/soynatan/django-easy-audit/pull/185
    • Spelling fixes by @boxed in https://github.com/soynatan/django-easy-audit/pull/196

    New Contributors

    • @Real-Gecko made their first contribution in https://github.com/soynatan/django-easy-audit/pull/162
    • @serl made their first contribution in https://github.com/soynatan/django-easy-audit/pull/198
    • @jkarstens made their first contribution in https://github.com/soynatan/django-easy-audit/pull/185
    • @boxed made their first contribution in https://github.com/soynatan/django-easy-audit/pull/196

    Full Changelog: https://github.com/soynatan/django-easy-audit/compare/v1.3.0...v1.3.2

    Source code(tar.gz)
    Source code(zip)
  • v1.3.2a1(Oct 28, 2021)

    Thanks to all for your hard-work in fixing the compatibility story on newer versions of django and python, as well as your patience and persistence in lighting a fire to get this out.

    #198 rolls up all of the fixes and is built upon #184 and #185 so as we can see, this was quite a group effort.

    Thank you to @jkarstens @tian-yi and @serl for your contributions so far.

    v1.3.2a1 is up on PyPI (you must check the releases page in order to see pre-releases), and in order for pip to grab it (CLI or requirements file), you must specify the version you're seeking to install, otherwise you'll get the latest stable release, which is behind this.

    v1.3.2 proper will be released as soon as we get :+1: from the community.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.1a1(Nov 7, 2020)

  • v1.3.0(Sep 14, 2020)

  • v1.3.0a5(Aug 7, 2020)

    Accidentally kept a tracemalloc import in the tests module, and apparently that is not available in pypy3! So, new version, but if you're not on pypy, you're fine with v.1.3.0a4 (or until we release officially).

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0.a4(Aug 7, 2020)

    Adds ASGI support via #147 so RequestEvent will work on WSGI and ASGI. async views (async def, not async as in "asgi") are not explicitly tested at this time. The changes made were in the signal handler and the middleware (the middleware will function correctly in ASGI and WSGI -- it does not support async at this time, which django is fine with no matter what). Should your view be run via async, please test ahead of time and we should be able to support that use case (if things break).

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0a3(Jul 23, 2020)

    nothing "new" since v.1.3.0a2, but had forgotten to remove the django < 2.2 and py < 35 tests on travis. We support 2.2-3, and thus officially py35-38.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0a2(Jul 23, 2020)

  • v1.3.0a1(Jul 23, 2020)

  • v1.2.3(Jul 11, 2020)

  • v1.2.3a5(Jun 19, 2020)

    More strict vendor checking (postgres) on the conditional index drop fix, on PR #149

    This is the last planned pre-release for the 1.2.3 release.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.3a4(May 30, 2020)

  • v1.2.3a3(May 19, 2020)

    #144 for issues on postgres (at least) for index creation/deletion management during the migration from an earlier PR from the user DB split (it was trying to fix something, and made a mistake trying to fix it).

    This is a good fix for tests and anyone that hasn't yet upgraded to a release where the affected migration is present.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.3a2(May 18, 2020)

  • v1.2.3a1(May 15, 2020)

    #134 merged which improves the admin model performance for select related (user for most, and content type for crudevent). For django debug toolbar users, this will likely show a huge speedup.

    Also includes #136 (which is later effectively rolled back in 1.2.3a4 (we hope to put it back it seems to be causing a bug).

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2(May 6, 2020)

    This release adds a bug pluggability/usability feature, an improvement (or partial fix to some) around changed_fields and CRUDEvent creation logic via a settings parameter, and a couple of smaller changes. This is essentially the same release as v1.2.2b4 (just a version bump).

    As a recap:

    PR #124

    PR #106 and #129 (adds a configuration to allow using the simpler/smarter flow).

    Adds a small (still needs further improvement in the logging) fix in #133

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2b4(Apr 1, 2020)

    This includes an additional fix that (due to changes on the on commit handling on CRUDEvent creation, if there was an error and the logger tried to log it, it was possible that instance's repr/str would have included something that was already deleted (this is a consumer level issue), so now we will try/except on the logger and pass if we have an error (not wonderful for now, but easier to just do that and get the release out).

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2b3(Mar 12, 2020)

    Default fix on the changed_fields conditional (if no changed fields, not making a CRUDEvent), not to use the newer flow (you may turn on the newer flow with a new settings toggle), via PR #129

    This is likely the last beta release for 1.2.2.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2b2(Feb 20, 2020)

    Adds pluggable logging/auditing support (not just database, but could do logging, elasticsearch, etc). database is the default. This was on PR #124 thanks to @atakanarikan

    changeset also includes from release v1.2.2b1, but for brevity not included here.

    Source code(tar.gz)
    Source code(zip)
Owner
Natán
Natán
A beginner django project and also my first Django project which involves shortening of a longer URL into a short one using a unique id.

Django-URL-Shortener A beginner django project and also my first Django project which involves shortening of a longer URL into a short one using a uni

Rohini Rao 3 Aug 08, 2021
Easy thumbnails for Django

Easy Thumbnails A powerful, yet easy to implement thumbnailing application for Django 1.11+ Below is a quick summary of usage. For more comprehensive

Chris Beaven 1.3k Dec 30, 2022
Dashboad Full Stack utilizando o Django.

Dashboard FullStack completa Projeto finalizado | Informações Cadastro de cliente Menu interatico mostrando quantidade de pessoas bloqueadas, liberada

Lucas Silva 1 Dec 15, 2021
Thumbnails for Django

Thumbnails for Django. Features at a glance Support for Django 2.2, 3.0 and 3.1 following the Django supported versions policy Python 3 support Storag

Jazzband 1.6k Jan 03, 2023
A simple Django middleware for Duo V4 2-factor authentication.

django-duo-universal-auth A lightweight middleware application that adds a layer on top of any number of existing authentication backends, enabling 2F

Adam Angle 1 Jan 10, 2022
An insecure login and registration website with Django.

An insecure login and registration website with Django.

Luis Quiñones Requelme 1 Dec 05, 2021
A collection of models, views, middlewares, and forms to help secure a Django project.

Django-Security This package offers a number of models, views, middlewares and forms to facilitate security hardening of Django applications. Full doc

SD Elements 258 Jan 03, 2023
A Django backed for PostgreSQL using Psycopg 3

A Django backend for PostgreSQL using Psycopg 2 The backend passes the entire Django test suite, but it needs a few modifications to Django and to i

Daniele Varrazzo 42 Dec 16, 2022
Add Chart.js visualizations to your Django admin using a mixin class

django-admincharts Add Chart.js visualizations to your Django admin using a mixin class. Example from django.contrib import admin from .models import

Dropseed 22 Nov 22, 2022
Use watchfiles in Django’s autoreloader.

django-watchfiles Use watchfiles in Django’s autoreloader. Requirements Python 3.7 to 3.10 supported. Django 2.2 to 4.0 supported. Installation Instal

Adam Johnson 43 Dec 14, 2022
Bringing together django, django rest framework, and htmx

This is Just an Idea There is no code, this README just represents an idea for a minimal library that, as of now, does not exist. django-htmx-rest A l

Jack DeVries 5 Nov 24, 2022
Website desenvolvido em Django para gerenciamento e upload de arquivos (.pdf).

Website para Gerenciamento de Arquivos Features Esta é uma aplicação full stack web construída para desenvolver habilidades com o framework Django. O

Alinne Grazielle 8 Sep 22, 2022
A web app which allows user to query the weather info of any place in the world

weather-app This is a web app which allows user to get the weather info of any place in the world as soon as possible. It makes use of OpenWeatherMap

Oladipo Adesiyan 3 Sep 20, 2021
Boilerplate Django Blog for production deployments!

CFE Django Blog THIS IS COMING SOON This is boilerplate code that you can use to learn how to bring Django into production. TLDR; This is definitely c

Coding For Entrepreneurs 26 Dec 09, 2022
A Django web application that allows you to be in the loop about everything happening in your neighborhood.

A Django web application that allows you to be in the loop about everything happening in your neighborhood. From contact information of different handyman to meeting announcements or even alerts.

Kennedy Ngugi Mwaura 3 Dec 11, 2022
Django Query Capture can check the query situation at a glance, notice slow queries, and notice where N+1 occurs.

django-query-capture Overview Django Query Capture can check the query situation at a glance, notice slow queries, and notice where N+1 occurs. Some r

GilYoung Song 80 Nov 22, 2022
Redia Cache implementation in django.

django-redis Recipe APP Simple Recipe app which shows different kinds off recipe to the user. Why Cache ? Accessing data from cache is much faster tha

Avinash Alanjkar 1 Sep 21, 2022
Realworld - Realworld using Django and HTMX

Realworld - Realworld using Django and HTMX

Dan Jacob 53 Jan 05, 2023
Bootstrap 3 integration with Django.

django-bootstrap3 Bootstrap 3 integration for Django. Goal The goal of this project is to seamlessly blend Django and Bootstrap 3. Want to use Bootstr

Zostera B.V. 2.3k Jan 02, 2023
A visual indicator of what environment/system you're using in django

A visual indicator of what environment/system you're using in django

Mark Walker 4 Nov 26, 2022