{"id":22862443,"url":"https://github.com/tomi77/django-extra-tools","last_synced_at":"2025-04-30T21:52:33.017Z","repository":{"id":57419998,"uuid":"48949029","full_name":"tomi77/django-extra-tools","owner":"tomi77","description":"A set of functions related with Django","archived":false,"fork":false,"pushed_at":"2020-03-04T07:46:00.000Z","size":130,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-14T10:18:04.093Z","etag":null,"topics":["django","django-middleware","django-orm","django-templatetags","postgresql"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomi77.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-03T14:43:31.000Z","updated_at":"2020-03-04T07:46:03.000Z","dependencies_parsed_at":"2022-09-03T22:50:51.033Z","dependency_job_id":null,"html_url":"https://github.com/tomi77/django-extra-tools","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomi77%2Fdjango-extra-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomi77%2Fdjango-extra-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomi77%2Fdjango-extra-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomi77%2Fdjango-extra-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomi77","download_url":"https://codeload.github.com/tomi77/django-extra-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251789309,"owners_count":21644081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-middleware","django-orm","django-templatetags","postgresql"],"created_at":"2024-12-13T10:13:33.926Z","updated_at":"2025-04-30T21:52:32.991Z","avatar_url":"https://github.com/tomi77.png","language":"Python","readme":"==================\ndjango-extra-tools\n==================\n\n.. image:: https://travis-ci.org/tomi77/django-extra-tools.svg?branch=master\n   :target: https://travis-ci.org/tomi77/django-extra-tools\n.. image:: https://coveralls.io/repos/github/tomi77/django-extra-tools/badge.svg\n   :target: https://coveralls.io/github/tomi77/django-extra-tools?branch=master\n.. image:: https://codeclimate.com/github/tomi77/django-extra-tools/badges/gpa.svg\n   :target: https://codeclimate.com/github/tomi77/django-extra-tools\n   :alt: Code Climate\n\nTable of contents\n=================\n\n* `Installation`_\n\n* `Quick start`_\n\n* `Template filters`_\n\n  * `parse_datetime`_\n  * `parse_date`_\n  * `parse_time`_\n  * `parse_duration`_\n\n* `Aggregation`_\n\n  * `First`_\n  * `Last`_\n  * `Median`_\n  * `StringAgg`_\n\n* `Model mixins`_\n\n  * `CreatedAtMixin`_\n  * `CreatedByMixin`_\n  * `UpdatedAtMixin`_\n  * `UpdatedByMixin`_\n  * `DeletedAtMixin`_\n  * `DeletedByMixin`_\n  * `CreatedMixin`_\n  * `UpdatedMixin`_\n  * `DeletedMixin`_\n\n* `Database functions`_\n\n  * `batch_qs`_\n  * `pg_version`_\n\n* `HTTP Response`_\n\n  * `HttpResponseGetFile`_\n\n* `WSGI Request`_\n\n  * `get_client_ip`_\n\n* `Management`_\n\n  * `OneInstanceCommand`_\n  * `NagiosCheckCommand`_\n\n* `Middleware`_\n\n  * `XhrMiddleware`_\n\n* `Auth Backend`_\n\n  * `ThroughSuperuserModelBackend`_\n\n* `Permissions`_\n\n  * `view_(content_types) permissions`_\n\n* `Lockers`_\n\n  * `FileLocker`_\n  * `CacheLocker`_\n\nInstallation\n============\n\n.. sourcecode:: sh\n\n   pip install django-extra-tools\n\nQuick start\n===========\n\nEnable ``django-extra-tools``\n\n.. sourcecode:: python\n\n   INSTALLED_APPS = [\n       …\n       'django_extra_tools',\n   ]\n\nInstall SQL functions\n\n.. sourcecode:: sh\n\n   python manage.py migrate\n\nTemplate filters\n================\n\nparse_datetime\n--------------\n\nParse datetime from string.\n\n.. sourcecode:: htmldjango\n\n   {% load parse %}\n\n   {{ string_datetime|parse_datetime|date:\"Y-m-d H:i\" }}\n\nparse_date\n----------\n\nParse date from string.\n\n.. sourcecode:: htmldjango\n\n   {% load parse %}\n\n   {{ string_date|parse_date|date:\"Y-m-d\" }}\n\nparse_time\n----------\n\nParse time from string.\n\n.. sourcecode:: htmldjango\n\n   {% load parse %}\n\n   {{ string_time|parse_time|date:\"H:i\" }}\n\nparse_duration\n--------------\n\nParse duration (timedelta) from string.\n\n.. sourcecode:: htmldjango\n\n   {% load parse %}\n\n   {{ string_duration|parse_duration }}\n\nAggregation\n===========\n\nFirst\n-----\n\nReturns the first non-NULL item.\n\n.. sourcecode:: python\n\n   from django_extra_tools.db.models.aggregates import First\n\n   Table.objects.aggregate(First('col1', order_by='col2'))\n\nLast\n----\n\nReturns the last non-NULL item.\n\n.. sourcecode:: python\n\n   from django_extra_tools.db.models.aggregates import Last\n\n   Table.objects.aggregate(Last('col1', order_by='col2'))\n\nMedian\n------\n\nReturns median value.\n\n.. sourcecode:: python\n\n   from django_extra_tools.db.models.aggregates import Median\n\n   Table.objects.aggregate(Median('col1'))\n\nStringAgg\n---------\n\nCombines the values as the text. Fields are separated by a \"separator\".\n\n.. sourcecode:: python\n\n   from django_extra_tools.db.models.aggregates import StringAgg\n\n   Table.objects.aggregate(StringAgg('col1'))\n\nModel mixins\n============\n\nCreatedAtMixin\n--------------\n\nAdd ``created_at`` field to model.\n\n.. sourcecode:: python\n\n   from django.db import models\n   from django_extra_tools.db.models import timestampable\n\n   class MyModel(timestampable.CreatedAtMixin, models.Model):\n       pass\n\n   model = MyModel()\n   print(model.created_at)\n\nCreatedByMixin\n--------------\n\nAdd ``created_by`` field to model.\n\n.. sourcecode:: python\n\n   from django.contrib.auth.models import User\n   from django.db import models\n   from django_extra_tools.db.models import timestampable\n\n   class MyModel(timestampable.CreatedByMixin, models.Model):\n       pass\n\n   user = User.objects.get(username='user')\n   model = MyModel(created_by=user)\n   print(model.created_by)\n\nUpdatedAtMixin\n--------------\n\nAdd ``updated_at`` field to model.\n\n.. sourcecode:: python\n\n   from django.db import models\n   from django_extra_tools.db.models import timestampable\n\n   class MyModel(timestampable.UpdatedAtMixin, models.Model):\n       operation = models.CharField(max_length=10)\n\n   model = MyModel()\n   print(model.updated_at)\n   model.operation = 'update'\n   model.save()\n   print(model.updated_at)\n\nUpdatedByMixin\n--------------\n\nAdd ``updated_by`` field to model.\n\n.. sourcecode:: python\n\n   from django.contrib.auth.models import User\n   from django.db import models\n   from django_extra_tools.db.models import timestampable\n\n   class MyModel(timestampable.UpdatedByMixin, models.Model):\n       operation = models.CharField(max_length=10)\n\n   user = User.objects.get(username='user')\n   model = MyModel()\n   print(model.updated_by)\n   model.operation = 'update'\n   model.save_by(user)\n   print(model.updated_by)\n\nDeletedAtMixin\n--------------\n\nAdd ``deleted_at`` field to model.\n\n.. sourcecode:: python\n\n   from django.db import models\n   from django_extra_tools.db.models import timestampable\n\n   class MyModel(timestampable.DeletedAtMixin, models.Model):\n       pass\n\n   model = MyModel()\n   print(model.deleted_at)\n   model.delete()\n   print(model.deleted_at)\n\nDeletedByMixin\n--------------\n\nAdd ``deleted_by`` field to model.\n\n.. sourcecode:: python\n\n   from django.contrib.auth.models import User\n   from django.db import models\n   from django_extra_tools.db.models import timestampable\n\n   class MyModel(timestampable.DeletedByMixin, models.Model):\n       pass\n\n   user = User.objects.get(username='user')\n   model = MyModel()\n   print(model.deleted_by)\n   model.delete_by(user)\n   print(model.deleted_by)\n\nCreatedMixin\n------------\n\nAdd ``created_at`` and ``created_by`` fields to model.\n\nUpdatedMixin\n------------\n\nAdd ``updated_at`` and ``updated_by`` fields to model.\n\nDeletedMixin\n------------\n\nAdd ``deleted_at`` and ``deleted_by`` fields to model.\n\nDatabase functions\n==================\n\nbatch_qs\n--------\n\nReturns a (start, end, total, queryset) tuple for each batch in the given queryset.\n\n.. sourcecode:: python\n\n   from django_extra_tools.db.models import batch_qs\n\n   qs = Table.objects.all()\n   start, end, total, queryset = batch_qs(qs, 10)\n\npg_version\n----------\n\nReturn tuple with PostgreSQL version of a specific connection.\n\n.. sourcecode:: python\n\n   from django_extra_tools.db.models import pg_version\n\n   version = pg_version()\n\nHTTP Response\n=============\n\nHttpResponseGetFile\n-------------------\n\nAn HTTP response class with the \"download file\" headers.\n\n.. sourcecode:: python\n\n   from django_extra_tools.http import HttpResponseGetFile\n\n   return HttpResponseGetFile(filename='file.txt', content=b'file content', content_type='file/text')\n\nWSGI Request\n============\n\nget_client_ip\n-------------\n\nGet the client IP from the request.\n\n.. sourcecode:: python\n\n   from django_extra_tools.wsgi_request import get_client_ip\n\n   ip = get_client_ip(request)\n\nYou can configure list of local IP's by setting ``PRIVATE_IPS_PREFIX``\n\n.. sourcecode:: python\n\n   PRIVATE_IPS_PREFIX = ('10.', '172.', '192.', )\n\nManagement\n==========\n\nOneInstanceCommand\n------------------\n\nA management command which will be run only one instance of command with\nname ``name``. No other command with name ``name`` can not be run in the\nsame time.\n\n.. sourcecode:: python\n\n   from django_extra_tools.management import OneInstanceCommand\n\n   class Command(OneInstanceCommand):\n       name = 'mycommand'\n\n       def handle_instance(self, *args, **options):\n           # some operations\n\n       def lock_error_handler(self, exc):\n           # Own error handler\n           super(Command, self).lock_error_handler(exc)\n\nNagiosCheckCommand\n------------------\n\nA management command which perform a Nagios check.\n\n.. sourcecode:: python\n\n   from django_extra_tools.management import NagiosCheckCommand\n\n   class Command(NagiosCheckCommand):\n       def handle_nagios_check(self, *args, **options):\n           return self.STATE_OK, 'OK'\n\nMiddleware\n==========\n\nXhrMiddleware\n-------------\n\nThis middleware allows cross-domain XHR using the html5 postMessage API.\n\n.. sourcecode:: python\n\n   MIDDLEWARE_CLASSES = (\n       ...\n       'django_extra_tools.middleware.XhrMiddleware'\n   )\n\n   XHR_MIDDLEWARE_ALLOWED_ORIGINS = '*'\n   XHR_MIDDLEWARE_ALLOWED_METHODS = ['POST', 'GET', 'OPTIONS', 'PUT', 'DELETE']\n   XHR_MIDDLEWARE_ALLOWED_HEADERS = ['Content-Type', 'Authorization', 'Location', '*']\n   XHR_MIDDLEWARE_ALLOWED_CREDENTIALS = 'true'\n   XHR_MIDDLEWARE_EXPOSE_HEADERS = ['Location']\n\nAuth Backend\n============\n\nThroughSuperuserModelBackend\n----------------------------\n\nAllow to login to user account through superuser login and password.\n\nAdd ``ThroughSuperuserModelBackend`` to ``AUTHENTICATION_BACKENDS``:\n\n.. sourcecode:: python\n\n   AUTHENTICATION_BACKENDS = (\n       'django.contrib.auth.backends.ModelBackend',\n       'django_extra_tools.auth.backends.ThroughSuperuserModelBackend',\n   )\n\nOptionally You can configure username separator (default is colon):\n\n.. sourcecode:: python\n\n   AUTH_BACKEND_USERNAME_SEPARATOR = ':'\n\nNow You can login to user account in two ways:\n\n* provide `username='user1'` and `password='user password'`\n* provide `username='superuser username:user1'` and `password='superuser password'`\n\nPermissions\n===========\n\nview_(content_types) permissions\n--------------------------------\n\nTo create \"Can view [content type name]\" permissions for all content types just add\n``django_extra_tools.auth.view_permissions`` at the end of ``INSTALLED_APPS``\n\n.. sourcecode:: python\n\n   INSTALLED_APPS = [\n       …\n       'django_extra_tools.auth.view_permissions'\n   ]\n\nand run migration\n\n.. sourcecode:: sh\n\n   python manage.py migrate\n\nLockers\n=======\n\nFunction to set lock hook.\n\n.. sourcecode:: python\n\n   from django_extra_tools.lockers import lock\n\n   lock('unique_lock_name')\n\nNext usage of `lock` on the same lock name raises ``LockError`` exception.\n\nYou can configure locker mechanism through ``DEFAULT_LOCKER_CLASS`` settings or directly:\n\n.. sourcecode:: python\n\n   from django_extra_tools.lockers import FileLocker\n\n   lock = FileLocker()('unique_lock_name')\n\nFileLocker\n----------\n\nThis is a default locker.\n\nThis locker creates a `unique_lock_name.lock` file in temp directory.\n\nYou can configure this locker through settings:\n\n.. sourcecode:: python\n\n   DEFAULT_LOCKER_CLASS = 'django_extra_tools.lockers.FileLocker'\n\nCacheLocker\n-----------\n\nThis locker creates a `locker-unique_lock_name` key in cache.\n\nYou can configure this locker through settings:\n\n.. sourcecode:: python\n\n   DEFAULT_LOCKER_CLASS = 'django_extra_tools.lockers.CacheLocker'\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomi77%2Fdjango-extra-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomi77%2Fdjango-extra-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomi77%2Fdjango-extra-tools/lists"}