django-tools
django-tools copied to clipboard
miscellaneous django tools
{{https://raw.githubusercontent.com/jedie/django-tools/master/logo/logo.svg|django-tools}}
Miscellaneous tools for django.
Look also at the siblings project: [[https://github.com/jedie/django-cms-tools|django-cms-tools]] (Tools/helpers around Django-CMS).
| {{https://img.shields.io/pypi/v/django-tools?label=django-tools%20%40%20PyPi|PyPi}} | https://pypi.python.org/pypi/django-tools/ | | {{https://github.com/jedie/django-tools/workflows/test/badge.svg?branch=main|Build Status on github}} | [[https://github.com/jedie/django-tools/actions|github.com/jedie/django-tools/actions]] | | {{https://codecov.io/gh/jedie/django-tools/branch/main/graph/badge.svg|Coverage Status on codecov.io}} | [[https://codecov.io/gh/jedie/django-tools|codecov.io/gh/jedie/django-tools]] | | {{https://coveralls.io/repos/jedie/django-tools/badge.svg|Coverage Status on coveralls.io}} | [[https://coveralls.io/r/jedie/django-tools|coveralls.io/r/jedie/django-tools]] |
{{https://img.shields.io/pypi/pyversions/django-tools|Python Versions}} {{https://img.shields.io/pypi/l/django-tools|License}}
(Logo contributed by [[https://github.com/reallinfo|@reallinfo]] see [[https://github.com/jedie/django-tools/pull/16|#16]])
== try-out
e.g.: {{{ ~$ git clone https://github.com/jedie/django-tools.git ~$ cd django-tools/ ~/django-tools$ make install ~/django-tools$ make help List all commands install-poetry install or update poetry install install django-tools via poetry update update the sources and installation lint Run code formatters and linter fix-code-style Fix code formatting tox-listenvs List all tox test environments tox Run pytest via tox with all environments tox-py37 Run pytest via tox with python v3.7 tox-py38 Run pytest via tox with python v3.8 tox-py39 Run pytest via tox with python v3.9 pytest Run pytest update-test-snapshot-files Update all snapshot files (by remove and recreate all snapshot files) update-rst-readme update README.rst from README.creole publish Release new version to PyPi start-dev-server Start Django dev. server with the test project playwright-install Install test browser for Playwright tests playwright-inspector Run Playwright inspector playwright-tests Run only the Playwright tests }}}
== existing stuff
=== Serve User Media File
Serve {{{settings.MEDIA_ROOT}}} files only for allowed users.
See separate README here: [[https://github.com/jedie/django-tools/tree/main/django_tools/serve_media_app|django_tools/serve_media_app]]
=== Mode Version Protect
Protect a model against overwriting a newer entry with an older one, by adding a auto increment version number.
See separate README here: [[https://github.com/jedie/django-tools/tree/main/django_tools/model_version_protect|django_tools/model_version_protect]]
=== OverwriteFileSystemStorage
A django filesystem storage that will overwrite existing files and can create backups, if content changed. usage:
{{{ class ExampleModel(models.Model): foo_file = models.FileField( storage=OverwriteFileSystemStorage(create_backups=True) ) bar_image = models.ImageField( storage=OverwriteFileSystemStorage(create_backups=False) ) }}}
Backup made by appending a suffix and sequential number, e.g.:
- source....: foo.bar
- backup 1..: foo.bar.bak
- backup 2..: foo.bar.bak0
- backup 3..: foo.bar.bak1
Backup files are only made if file content changed. But at least one time!
=== Django Logging utils
Put this into your settings, e.g.:
{{{ from django_tools.unittest_utils.logging_utils import CutPathnameLogRecordFactory, FilterAndLogWarnings
Filter warnings and pipe them to logging system
Warnings of external packages are displayed only once and only the file path.
warnings.showwarning = FilterAndLogWarnings()
Adds 'cut_path' attribute on log record. So '%(cut_path)s' can be used in log formatter.
logging.setLogRecordFactory(CutPathnameLogRecordFactory(max_length=50))
LOGGING = { # ... 'formatters': { 'verbose': { 'format': '%(levelname)8s %(cut_path)s:%(lineno)-3s %(message)s' }, }, # ... } }}} (Activate warnings by, e.g.: {{{export PYTHONWARNINGS=all}}})
==== ThrottledAdminEmailHandler
[[https://github.com/jedie/django-tools/blob/master/django_tools/log_utils/throttle_admin_email_handler.py|ThrottledAdminEmailHandler]] works similar as the origin [[https://docs.djangoproject.com/en/1.11/topics/logging/#django.utils.log.AdminEmailHandler|django.utils.log.AdminEmailHandler]] but is will throttle the number of mails that can be send in a time range. usage e.g.:
{{{ LOGGING = { # ... "handlers": { "mail_admins": { "level": "ERROR", "class": "django_tools.log_utils.throttle_admin_email_handler.ThrottledAdminEmailHandler", "formatter": "email", "min_delay_sec": 20, # << -- skip mails in this time range }, # ... }, # ... } }}}
=== django_tools.template.loader.DebugCacheLoader
Insert template name as html comments, e.g.:
{{{
...
}}}
To use this, you must add django_tools.template.loader.DebugCacheLoader as template loader.
e.g.: Activate it only in DEBUG mode:
{{{ if DEBUG: TEMPLATES[0]["OPTIONS"]["loaders"] = [ ( "django_tools.template.loader.DebugCacheLoader", ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ) ) ] }}}
=== send text+html mails
A helper class to send text+html mails used the django template library.
You need two template files, e.g.:
- [[https://github.com/jedie/django-tools/blob/master/django_tools_test_project/django_tools_test_app/templates/mail_test.txt|mail_test.txt]]
- [[https://github.com/jedie/django-tools/blob/master/django_tools_test_project/django_tools_test_app/templates/mail_test.html|mail_test.html]]
You have to specify the template file like this: {{{template_base="mail_test.{ext}"}}}
Send via Celery task: {{{
settings.py
SEND_MAIL_CELERY_TASK_NAME="mail:send_task"
from django_tools.mail.send_mail import SendMailCelery SendMailCelery( template_base="mail_test.{ext}", mail_context={"foo": "first", "bar": "second"}, subject="Only a test", recipient_list="[email protected]" ).send() }}}
Send without Celery: {{{ from django_tools.mail.send_mail import SendMail SendMail( template_base="mail_test.{ext}", mail_context={"foo": "first", "bar": "second"}, subject="Only a test", recipient_list="[email protected]" ).send() }}}
See also the existing unittests:
- [[https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_email.py|django_tools_tests/test_email.py]]
=== Delay tools
Sometimes you want to simulate when processing takes a little longer. There exists {{{django_tools.debug.delay.SessionDelay}}} and {{{django_tools.debug.delay.CacheDelay}}} for this. The usage will create logging entries and user messages, if user is authenticated.
More info in seperate [[https://github.com/jedie/django-tools/blob/master/django_tools/debug/README.creole|django_tools/debug/README.creole]] file.
=== Filemanager library
Library for building django application like filemanager, gallery etc.
more info, read [[https://github.com/jedie/django-tools/blob/master/django_tools/filemanager/README.creole|./filemanager/README.creole]]
=== per-site cache middleware
Similar to [[https://docs.djangoproject.com/en/1.4/topics/cache/#the-per-site-cache|django UpdateCacheMiddleware and FetchFromCacheMiddleware]], but has some enhancements: [[https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole#per-site-cache-middleware|'per site cache' in ./cache/README.creole]]
=== smooth cache backends
Same as django cache backends, but adds {{{cache.smooth_update()}}} to clears the cache smoothly depend on the current system load. more info in: [[https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole#smooth-cache-backends|'smooth cache backends' in ./cache/README.creole]]
=== local sync cache
Keep a local dict in a multi-threaded environment up-to-date. Usefull for cache dicts. More info, read DocString in [[https://github.com/jedie/django-tools/blob/master/django_tools/local_sync_cache/local_sync_cache.py|./local_sync_cache/local_sync_cache.py]].
=== threadlocals middleware
For getting request object anywhere, use [[https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/ThreadLocal.py|./middlewares/ThreadLocal.py]]
=== Dynamic SITE_ID middleware
Note: Currently not maintained! TODO: Fix unittests for all python/django version
Set settings.SITE_ID dynamically with a middleware base on the current request domain name. Domain name alias can be specify as a simple string or as a regular expression.
more info, read [[https://github.com/jedie/django-tools/blob/master/django_tools/dynamic_site/README.creole|./dynamic_site/README.creole]].
=== StackInfoStorage
Message storage like LegacyFallbackStorage, except, every message would have a stack info, witch is helpful, for debugging. Stack info would only be added, if settings DEBUG or MESSAGE_DEBUG is on. To use it, put this into your settings:
{{{ MESSAGE_STORAGE = "django_tools.utils.messages.StackInfoStorage" }}}
More info, read DocString in [[https://github.com/jedie/django-tools/blob/master/django_tools/utils/messages.py|./utils/messages.py]].
=== limit to usergroups
Limit something with only one field, by selecting:
- anonymous users
- staff users
- superusers
- ..all existing user groups..
More info, read DocString in [[https://github.com/jedie/django-tools/blob/master/django_tools/limit_to_usergroups.py|./limit_to_usergroups.py]]
=== permission helpers
See [[https://github.com/jedie/django-tools/blob/master/django_tools/permissions.py|django_tools.permissions]] and unittests: [[https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_permissions.py|django_tools_tests.test_permissions]]
=== form/model fields
- [[https://github.com/jedie/django-tools/blob/master/django_tools/fields/directory.py|Directory field]] - check if exist and if in a defined base path
- [[https://github.com/jedie/django-tools/blob/master/django_tools/fields/language_code.py|language code field with validator]]
- [[https://github.com/jedie/django-tools/blob/master/django_tools/fields/media_path.py|Media Path field]] browse existign path to select and validate input
- [[https://github.com/jedie/django-tools/blob/master/django_tools/fields/sign_separated.py|sign seperated form/model field]] e.g. comma seperated field
- [[https://github.com/jedie/django-tools/blob/master/django_tools/fields/static_path.py|static path field]]
- [[https://github.com/jedie/django-tools/blob/master/django_tools/fields/url.py|url field]] A flexible version of the original django form URLField
== unittests helpers
=== Selenium Test Cases
There are Firefox and Chromium test cases, with and without django StaticLiveServerTestCase!
Chromium + StaticLiveServer example: {{{ from django_tools.selenium.chromedriver import chromium_available from django_tools.selenium.django import SeleniumChromiumStaticLiveServerTestCase
@unittest.skipUnless(chromium_available(), "Skip because Chromium is not available!") class ExampleChromiumTests(SeleniumChromiumStaticLiveServerTestCase): def test_admin_login_page(self): self.driver.get(self.live_server_url + "/admin/login/") self.assert_equal_page_title("Log in | Django site admin") self.assert_in_page_source('