Metadata-Version: 2.0
Name: django-tools
Version: 0.39.0
Summary: miscellaneous tools for django
Home-page: http://github.com/jedie/django-tools/
Author: Jens Diemer
Author-email: django-tools@jensdiemer.de
License: UNKNOWN
Description-Content-Type: UNKNOWN
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Programming Language :: Python
Classifier: Framework :: Django
Classifier: Topic :: Database :: Front-Ends
Classifier: Topic :: Documentation
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Requires-Dist: Django (>=1.8)
Requires-Dist: lxml

============
django-tools
============

Miscellaneous tools for django.

Look also at the siblings project: `django-cms-tools <https://github.com/jedie/django-cms-tools>`_ (Tools/helpers around Django-CMS).

+-----------------------------------+--------------------------------------------------+
| |Build Status on travis-ci.org|   | `travis-ci.org/jedie/django-tools`_              |
+-----------------------------------+--------------------------------------------------+
| |Coverage Status on codecov.io|   | `codecov.io/gh/jedie/django-tools`_              |
+-----------------------------------+--------------------------------------------------+
| |Coverage Status on coveralls.io| | `coveralls.io/r/jedie/django-tools`_             |
+-----------------------------------+--------------------------------------------------+
| |Status on landscape.io|          | `landscape.io/github/jedie/django-tools/master`_ |
+-----------------------------------+--------------------------------------------------+

.. |Build Status on travis-ci.org| image:: https://travis-ci.org/jedie/django-tools.svg
.. _travis-ci.org/jedie/django-tools: https://travis-ci.org/jedie/django-tools/
.. |Coverage Status on codecov.io| image:: https://codecov.io/gh/jedie/django-tools/branch/master/graph/badge.svg
.. _codecov.io/gh/jedie/django-tools: https://codecov.io/gh/jedie/django-tools
.. |Coverage Status on coveralls.io| image:: https://coveralls.io/repos/jedie/django-tools/badge.svg
.. _coveralls.io/r/jedie/django-tools: https://coveralls.io/r/jedie/django-tools
.. |Status on landscape.io| image:: https://landscape.io/github/jedie/django-tools/master/landscape.svg
.. _landscape.io/github/jedie/django-tools/master: https://landscape.io/github/jedie/django-tools/master

--------------
existing stuff
--------------

django_tools.template.loader.DebugCacheLoader
=============================================

Insert template name as html comments, e.g.:

::

    <!-- START 'foo/bar.html' -->
    ...
    <!-- END 'foo/bar.html' -->

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.:

* `mail_test.txt <https://github.com/jedie/django-tools/blob/master/django_tools_test_project/django_tools_test_app/templates/mail_test.txt>`_

* `mail_test.html <https://github.com/jedie/django-tools/blob/master/django_tools_test_project/django_tools_test_app/templates/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="foo@bar.tld"
    ).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="foo@bar.tld"
    ).send()

See also the existing unittests:

* `django_tools_tests/test_email.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_email.py>`_

Filemanager library
===================

Library for building django application like filemanager, gallery etc.

more info, read `./filemanager/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/filemanager/README.creole>`_

per-site cache middleware
=========================

Similar to `django UpdateCacheMiddleware and FetchFromCacheMiddleware <https://docs.djangoproject.com/en/1.4/topics/cache/#the-per-site-cache>`_,
but has some enhancements: `'per site cache' in ./cache/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole#per-site-cache-middleware>`_

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: `'smooth cache backends' in ./cache/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole#smooth-cache-backends>`_

local sync cache
================

Keep a local dict in a multi-threaded environment up-to-date. Usefull for cache dicts.
More info, read DocString in `./local_sync_cache/local_sync_cache.py <https://github.com/jedie/django-tools/blob/master/django_tools/local_sync_cache/local_sync_cache.py>`_.

threadlocals middleware
=======================

For getting request object anywhere, use `./middlewares/ThreadLocal.py <https://github.com/jedie/django-tools/blob/master/django_tools/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 `./dynamic_site/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/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 `./utils/messages.py <https://github.com/jedie/django-tools/blob/master/django_tools/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 `./limit_to_usergroups.py <https://github.com/jedie/django-tools/blob/master/django_tools/limit_to_usergroups.py>`_

permission helpers
==================

See `django_tools.permissions <https://github.com/jedie/django-tools/blob/master/django_tools/permissions.py>`_
and unittests: `django_tools_tests.test_permissions <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_permissions.py>`_

form/model fields
=================

* `Directory field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/directory.py>`_ - check if exist and if in a defined base path

* `language code field with validator <https://github.com/jedie/django-tools/blob/master/django_tools/fields/language_code.py>`_

* `Media Path field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/media_path.py>`_ browse existign path to select and validate input

* `sign seperated form/model field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/sign_separated.py>`_ e.g. comma seperated field

* `static path field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/static_path.py>`_

* `url field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/url.py>`_ A flexible version of the original django form URLField

-----------------
unittests helpers
-----------------

Mockup utils
============

Create dummy PIL/django-filer images with Text, see:

* `/django_tools/unittest_utils/mockup.py <https://github.com/jedie/django-tools/blob/master/django_tools/unittest_utils/mockup.py>`_

usage/tests:

* `/django_tools_tests/test_mockup.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_mockup.py>`_

create users
============

`/unittest_utils/user.py <https://github.com/jedie/django-tools/blob/master/django_tools/unittest_utils/user.py>`_:

* ``django_tools.unittest_utils.user.create_user()`` - create users, get_super_user

* ``django_tools.unittest_utils.user.get_super_user()`` - get the first existing superuser

Isolated Filesystem decorator / context manager
===============================================

`django_tools.unittest_utils.isolated_filesystem.isolated_filesystem <https://github.com/jedie/django-tools/blob/master/django_tools/unittest_utils/isolated_filesystem.py>`_ acts as either a decorator or a context manager.
Useful to for tests that will create files/directories in current work dir, it does this:

* create a new temp directory

* change the current working directory to the temp directory

* after exit:

* Delete an entire temp directory tree

usage e.g.:

::

    from django_tools.unittest_utils.isolated_filesystem import isolated_filesystem

    with isolated_filesystem(prefix="temp_dir_prefix"):
        open("foo.txt", "w").write("bar")

BaseUnittestCase
================

**django_tools.unittest_utils.unittest_base.BaseUnittestCase** contains some low-level assert methods:

* assertEqual_dedent()

* assert_is_dir(), assert_not_is_dir()

* assert_is_file(), assert_not_is_File()

*django_tools.unittest_utils.tempdir* contains **TempDir**, a Context Manager Class:

::

    with TempDir(prefix="foo_") as tempfolder:
        # create a file:
        open(os.path.join(tempfolder, "bar"), "w").close()

    # the created temp folder was deleted with shutil.rmtree()

usage/tests:

* `/django_tools_tests/test_unittest_utils.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_unittest_utils.py>`_

DjangoCommandMixin
==================

Helper to run shell commands. e.g.: "./manage.py cms check" in unittests.

usage/tests:

* `/django_tools_tests/test_unittest_django_command.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_unittest_django_command.py>`_

DOM compare in unittests
========================

The Problem:
You can’t easy check if e.g. some form input fields are in the response,
because the form rendering use a dict for storing all html attributes.
So, the ordering of form field attributes are not sorted and varied.

The Solution:
You need to parse the response content into a DOM tree and compare nodes.

We add the great work of Gregor Müllegger at his GSoC 2011 form-rendering branch.
You will have the following assert methods inherit from: django_tools.unittest_utils.unittest_base.BaseTestCase

* self.assertHTMLEqual() – for compare two HTML DOM trees

* self.assertDOM() – for check if nodes in response or not.

* self.assertContains() – Check if ond node occurs 'count’ times in response

More info and examples in `./django_tools_tests/test_dom_asserts.py <https://github.com/jedie/django-tools/blob/master/django_tools/django_tools_tests/test_dom_asserts.py>`_

@set_string_if_invalid() decorator
==================================

Helper to check if there are missing template tags by set temporary ``'string_if_invalid'``, see: `https://docs.djangoproject.com/en/1.8/ref/templates/api/#invalid-template-variables <https://docs.djangoproject.com/en/1.8/ref/templates/api/#invalid-template-variables>`_

Usage, e.g.:

::

    from django.test import SimpleTestCase
    from django_tools.unittest_utils.template import TEMPLATE_INVALID_PREFIX, set_string_if_invalid

    @set_string_if_invalid()
    class TestMyTemplate(SimpleTestCase):
        def test_valid_tag(self):
            response = self.client.get('/foo/bar/')
            self.assertNotIn(TEMPLATE_INVALID_PREFIX, response.content)

You can also decorate the test method ;)

@task_always_eager() celery decorator
=====================================

Decorator activate celery:

::

    CELERY_ALWAYS_EAGER=True # executed locally instead of being sent to the queue
    CELERY_EAGER_PROPAGATES_EXCEPTIONS=True # raise exceptions on errors

Is also set these two items in settings by using ``override_settings``
See also: `http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_always_eager <http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-task_always_eager>`_

Usage, e.g.:

::

    from django.core import mail
    from django.test import SimpleTestCase
    from django_tools.unittest_utils.celery_utils import task_always_eager

    @task_always_eager()
    class TestMyCeleryJobs(SimpleTestCase):
        def test_send_mail(self):
            response = self.client.get('/send_mail/foo/')
            self.assertEqual(len(mail.outbox), 1)

You can also decorate the test method ;)

Speedup tests
=============

Speedup test run start by disable migrations, e.g.:

::

    from django_tools.unittest_utils.disable_migrations import DisableMigrations
    MIGRATION_MODULES = DisableMigrations()

small tools
===========

debug_csrf_failure()
--------------------

Display the normal debug page and not the minimal csrf debug page.
More info in DocString here: `django_tools/views/csrf.py <https://github.com/jedie/django-tools/blob/master/django_tools/views/csrf.py>`_

import lib helper
-----------------

additional helper to the existing ``importlib``
more info in the sourcecode: `./utils/importlib.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/importlib.py>`_

http utils
----------

Pimped HttpRequest to get some more information about a request.
More info in DocString here: `django_tools/utils/http.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/http.py>`_

@display_admin_error
--------------------

Developer helper to display silent errors in ModelAdmin.list_display callables.
See: **display_admin_error** in `decorators.py <https://github.com/jedie/django-tools/blob/master/django_tools/decorators.py>`_

upgrade virtualenv
==================

A simple commandline script that calls ``pip install —-upgrade XY`` for every package thats installed in a virtualenv.
Simply copy/symlink it into the root directory of your virtualenv and start it.

**Note:** `Seems that this solution can't observe editables right. <https://github.com/pypa/pip/issues/319>`_

To use it, without installing django-tools:

::

    ~/$ cd goto/your_env
    .../your_env/$ wget https://github.com/jedie/django-tools/raw/master/django_tools/upgrade_virtualenv.py
    .../your_env/$ chmod +x upgrade_virtualenv.py
    .../your_env/$ ./upgrade_virtualenv.py

This script will be obsolete, if `pip has a own upgrade command <https://github.com/pypa/pip/issues/59>`_.

django_tools.utils.url.GetDict
==============================

Similar to origin django.http.QueryDict but:

* urlencode() doesn't add "=" to empty values: "?empty" instead of "?empty="

* always mutable

* output will be sorted (easier for tests ;)

More info, see tests: `django_tools_tests/test_utils_url.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_utils_url.py>`_

SignedCookieStorage
-------------------

Store information in signed Cookies, use **django.core.signing**.
So the cookie data can't be manipulated from the client.
Sources/examples:

* `/django_tools/utils/client_storage.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/client_storage.py>`_

* `/django_tools_tests/test_signed_cookie.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_signed_cookie.py>`_

Print SQL Queries
=================

Print the used SQL queries via context manager.

usage e.g.:

::

    from django_tools.unittest_utils.print_sql import PrintQueries

    # e.g. use in unittests:
    class MyTests(TestCase):
        def test_foobar(self):
            with PrintQueries("Create object"):
                FooBar.objects.create("name"=foo)

    # e.g. use in views:
    def my_view(request):
        with PrintQueries("Create object"):
            FooBar.objects.create("name"=foo)

the output is like:

::

    _______________________________________________________________________________
     *** Create object ***
    1 - INSERT INTO "foobar" ("name")
        VALUES (foo)
    -------------------------------------------------------------------------------

SetRequestDebugMiddleware
=========================

middleware to add debug bool attribute to request object.
More info: `./debug/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/debug/README.creole>`_

TracebackLogMiddleware
======================

Put traceback in log by call `logging.exception() <https://docs.python.org/3/library/logging.html#logging.Logger.exception>`_ on ``process_exception()``
Activate with:

::

    MIDDLEWARE_CLASSES = (
        ...
        'django_tools.middlewares.TracebackLogMiddleware.TracebackLogMiddleware',
        ...
    )

FnMatchIps() - Unix shell-style wildcards in INTERNAL_IPS / ALLOWED_HOSTS
=========================================================================

settings.py e.g.:

::

    from django_tools.settings_utils import FnMatchIps

    INTERNAL_IPS = FnMatchIps(["127.0.0.1", "::1", "192.168.*.*", "10.0.*.*"])
    ALLOWED_HOSTS = FnMatchIps(["127.0.0.1", "::1", "192.168.*.*", "10.0.*.*"])

StdoutStderrBuffer()
====================

redirect stdout + stderr to a string buffer. e.g.:

::

    from django_tools.unittest_utils.stdout_redirect import StdoutStderrBuffer

    with StdoutStderrBuffer() as buffer:
        print("foo")
    output = buffer.get_output() # contains "foo\n"

Management commands
===================

permission_info
---------------

List all permissions for one django user.
(Needs ``'django_tools'`` in INSTALLED_APPS)

e.g.:

::

    $ ./manage.py permission_info
    No username given!

    All existing users are:
    foo, bar, john, doe

    $ ./manage.py permission_info foo
    All permissions for user 'test_editor':
    	is_active    : yes
    	is_staff     : yes
    	is_superuser : no
    [*] admin.add_logentry
    [*] admin.change_logentry
    [*] admin.delete_logentry
    [ ] auth.add_group
    [ ] auth.add_permission
    [ ] auth.add_user
    ...

nice_diffsettings
-----------------

Similar to django 'diffsettings', but used pretty-printed representation.

To use it, add ``'django_tools.manage_commands.django_tools_nice_diffsettings'`` to your INSTALLED_APPS and call:

::

    $ ./manage.py nice_diffsettings

database_info
-------------

Just display some information about the used database and connections.
(Needs ``'django_tools'`` in INSTALLED_APPS)

e.g.:

::

    $ ./manage.py database_info

list_models
-----------

Just list all existing models in app_label.ModelName format. Useful to use this in 'dumpdata' etc.

To use it, add ``'django_tools.manage_commands.django_tools_list_models'`` to your INSTALLED_APPS and call:

::

    $ ./manage.py list_models

..all others…
=============

There exist many miscellaneous stuff. Look in the source, luke!

------------------------------
running django-tools unittests
------------------------------

Run all tests in all environment combinations via tox:

::

    .../django-tools $ python3 setup.py tox

Run all tests in current environment via pytest:

::

    .../django-tools $ python3 setup.py test

------------------------------
Backwards-incompatible changes
------------------------------

-----
v0.35
-----

Dummy image generation function in ``django_tools.unittest_utils.mockup`` has a new API.
The new API makes it possible to better adjust the generated dummy images.

The functions ``create_pil_image``, ``create_info_image`` and ``create_temp_filer_info_image`` was refactored to the class ``django_tools.unittest_utils.mockup.ImageDummy``

The old API will be removed in the future.

-----
v0.32
-----

remove outdated stuff:

* django-tagging addon

* upgrade_virtualenv.py (Alternative: `update_virtualenv_git_repos.py <https://github.com/jedie/python-code-snippets/blob/master/CodeSnippets/update_virtualenv_git_repos.py>`_)

* utils.http

-----
v0.29
-----

**ClientCookieStorage** was renamed to **SignedCookieStorage**
import e.g.:

::

    from django_tools.utils.client_storage import SignedCookieStorage

-------
v0.25.0
-------

SmoothCacheBackends API changed:
The **cache.clear()** method will really clear the cache, as the origin backend API.
You must call ``cache.smooth_update()`` to set the "last change" timestamp.

v0.24.10
========

AutoUpdateFileBasedCache is deprecated, use new SmoothCacheBackends.

v0.9
====

Language code field and SelectMediaPath are renamed.

change:
**from django_tools.fields import LanguageCodeFormField**
to:
**from django_tools.fields.language_code import LanguageCodeFormField**

change and rename:
**from django_tools.fields import LanguageCodeField**
to:
**from django_tools.fields.language_code import LanguageCodeModelField**

change and rename:
**from django_tools.widgets import SelectMediaPath**
to:
**from django_tools.fields.media_path import MediaPathWidget**

v0.39
=====

File renamed: ``django_tools/unittest_utils/{celery.py => celery_utils.py``}

--------------------
Django compatibility
--------------------

+------------------+----------------+-----------------+
| django-tools     | django version | python          |
+==================+================+=================+
| >= v0.39         | 1.11, 2.0      | 3.5, 3.6, pypy3 |
+------------------+----------------+-----------------+
| >= v0.38.1       | 1.8, 1.11      | 3.5, 3.6, pypy3 |
+------------------+----------------+-----------------+
| >= v0.38.0       | 1.8, 1.11      | 3.5, 3.6        |
+------------------+----------------+-----------------+
| >= v0.37.0       | 1.8, 1.11      | 3.4, 3.5        |
+------------------+----------------+-----------------+
| >= v0.33.0       | 1.8, 1.11      | 2.7, 3.4, 3.5   |
+------------------+----------------+-----------------+
| v0.30.1-v0.32.14 | 1.8, 1.9, 1.10 | 2.7, 3.4, 3.5   |
+------------------+----------------+-----------------+
| v0.30            | 1.8, 1.9       | 2.7, 3.4        |
+------------------+----------------+-----------------+
| v0.29            | 1.6 - 1.8      | 2.7, 3.4        |
+------------------+----------------+-----------------+
| v0.26            | <=1.6          |                 |
+------------------+----------------+-----------------+
| v0.25            | <=1.4          |                 |
+------------------+----------------+-----------------+

(See also combinations in `.travis.yml <https://github.com/jedie/django-tools/blob/master/.travis.yml>`_ and `tox.ini <https://github.com/jedie/django-tools/blob/master/tox.ini>`_)

-------
history
-------

* *dev* - `compare v0.39.0...master <https://github.com/jedie/django-tools/compare/v0.39.0...master>`_ 

    * no changes yet

* v0.39.0 - `compare v0.38.9...v0.39.0 <https://github.com/jedie/django-tools/compare/v0.38.9...v0.39.0>`_ 

    * NEW: Isolated Filesystem decorator / context manager

    * Backwards-incompatible change: file renamed ``django_tools/unittest_utils/{celery.py => celery_utils.py``}

    * Skip run test with Django 1.8 and run tests with Django 1.11 and 2.0

* v0.38.9 - 05.02.2018 - `compare v0.38.8...v0.38.9 <https://github.com/jedie/django-tools/compare/v0.38.8...v0.38.9>`_ 

    * lowering log level on missing permissions from "error" to "debug"

* v0.38.8 - 05.02.2018 - `compare v0.38.7...v0.38.8 <https://github.com/jedie/django-tools/compare/v0.38.7...v0.38.8>`_ 

    * send mail: use from celery import shared_task instead of djcelery_transactions

* v0.38.7 - 15.01.2018 - `compare v0.38.6...v0.38.7 <https://github.com/jedie/django-tools/compare/v0.38.6...v0.38.7>`_ 

    * Add missing arguments (like "attachments", "cc" etc.) to ``django_tools.mail.send_mail.SendMailCelery``

* v0.38.6 - 10.01.2018 - `compare v0.38.4...v0.38.5 <https://github.com/jedie/django-tools/compare/v0.38.4...v0.38.5>`_ 

    * NEW: ``./manage.py clear_cache``

    * Display POST data in browser debug (``django_tools.unittest_utils.BrowserDebug.debug_response``)

* v0.38.5 - 02.01.2018 - `compare v0.38.4...v0.38.5`_ 

    * NEW: Helper to assert django message framework output in unittests:

        * ``BaseUnittestCase.get_messages()``: return a list of all messages

        * ``BaseTestCase.assertMessages()``: compare messages

        * ``BaseTestCase.assertResponse()``: has new keyword argument ``messages``

    * NEW: ``BaseUnittestCase.assert_exception_startswith()``

* v0.38.4 - 28.12.2017 - `compare v0.38.3...v0.38.4 <https://github.com/jedie/django-tools/compare/v0.38.3...v0.38.4>`_ 

    * Bugfix attach user group on existing user in: ``django_tools.unittest_utils.user.get_or_create_user``

* v0.38.3 - 28.12.2017 - `compare v0.38.2...v0.38.3 <https://github.com/jedie/django-tools/compare/v0.38.2...v0.38.3>`_ 

    * Bugfix: ``unittest_utils.user.get_or_create_group`` also removes obsolete permissions, too.

* v0.38.2 - 27.12.2017 - `compare v0.38.1...v0.38.2 <https://github.com/jedie/django-tools/compare/v0.38.1...v0.38.2>`_ 

    * NEW: ``./manage.py update_permissions``

* v0.38.1 - 21.12.2017 - `compare v0.38.0...v0.38.1 <https://github.com/jedie/django-tools/compare/v0.38.0...v0.38.1>`_ 

    * refactor travis/tox/pytest/coverage stuff

    * Tests can be run via ``python3 setup.py tox`` and/or ``python3 setup.py test``

    * Test also with pypy3 on Travis CI.

* v0.38.0 - 19.12.2017 - `compare v0.37.0...v0.38.0 <https://github.com/jedie/django-tools/compare/v0.37.0...v0.38.0>`_ 

    * NEW: ``django_tools.unittest_utils.user.get_or_create_group``

    * NEW: ``django_tools.unittest_utils.user.get_or_create_user``

    * NEW: ``django_tools.unittest_utils.user.get_or_create_user_and_group``

    * NEW: ``BaseUnittestCase.get_admin_change_url()`` and ``BaseUnittestCase.get_admin_add_url()``

    * NEW: ``BaseUnittestCase.assert_startswith()`` and ``BaseUnittestCase.assert_endswith()``

* v0.37.0 - 11.12.2017 - `compare v0.36.0...v0.37.0 <https://github.com/jedie/django-tools/compare/v0.36.0...v0.37.0>`_ 

    * Skip official support for python v2 (remove from text matrix)

    * NEW: ``./manage.py permission_info``: Display a list of all permissions for one django user

    * NEW: ``django_tools.permissions.get_filtered_permissions()`` and ``django_tools.permissions.pprint_filtered_permissions()``

    * ``django_tools.settings_utils.InternalIps`` was renamed to ``FnMatchIps`` and can be also used for **ALLOWED_HOSTS**

    * Bugfix/Enhance permission helpers

* v0.36.0 - 20.11.2017 - `compare v0.35.0...v0.36.0 <https://github.com/jedie/django-tools/compare/v0.35.0...v0.36.0>`_ 

    * NEW: ``./manage.py database_info``

    * Bugfix: **ModelPermissionMixin**

    * Dynamic Sites is no longer maintained and tests are deactivated. It's currently not compatible with all django versions.

* v0.35.0 - 26.09.2017 - `compare v0.34.0...v0.35.0 <https://github.com/jedie/django-tools/compare/v0.34.0...v0.35.0>`_ 

    * CHANGE: The dummy image generation function in ``django_tools.unittest_utils.mockup`` has a new API.

* v0.34.0 - 18.09.2017 - `compare v0.33.0...v0.34.0 <https://github.com/jedie/django-tools/compare/v0.33.0...v0.34.0>`_ 

    * CHANGE: The test usernames changed and spaces was replace with underscores e.g.: "staff test user" -> "staff_test_user"

    * Bugfix in mockup.create_pil_image: Created images has wrong sizes

* v0.33.0 - 11.07.2017 - `compare v0.32.14...v0.33.0 <https://github.com/jedie/django-tools/compare/v0.32.14...v0.33.0>`_ 

    * Run tests only against Django v1.8 TLS and v1.11 TLS

    * For Django 1.11: Add support for new-style middleware - contributed by benkonrath

    * NEW: ``django_tools.utils.request.create_fake_request()`` for easier create a faked request object with ``RequestFactory``

    * NEW: ``django_tools.utils.html_utils.html2text()`` - Strip HTML tags with lxml Cleaner + Django 'strip_tags'

* v0.32.14 - 14.06.2017 - `compare v0.32.13...v0.32.14 <https://github.com/jedie/django-tools/compare/v0.32.13...v0.32.14>`_ 

    * Bugfix for Python 2: ``mock`` backport package is needed and added to ``setup.install_requires``

* v0.32.13 - 24.05.2017 - `compare v0.32.12...v0.32.13 <https://github.com/jedie/django-tools/compare/v0.32.12...v0.32.13>`_ 

    * remove some warnings

* v0.32.12 - 04.05.2017 - `compare v0.32.11...v0.32.12 <https://github.com/jedie/django-tools/compare/v0.32.11...v0.32.12>`_ 

    * NEW: ``self.assertIn_dedent()`` in ``django_tools.unittest_utils.unittest_base.BaseUnittestCase``

* v0.32.11 - 02.05.2017 - `compare v0.32.10...v0.32.11 <https://github.com/jedie/django-tools/compare/v0.32.10...v0.32.11>`_ 

    * Fix PyPi package mistake (``.tar.gz`` archive contains ``.tox`` ;)

* v0.32.10 - 02.05.2017 - `compare v0.32.9...v0.32.10 <https://github.com/jedie/django-tools/compare/v0.32.9...v0.32.10>`_ 

    * NEW: ``django_tools.mail`` to send text+html mails (see above)

* v0.32.9 - 21.03.2017 - `compare v0.32.8...v0.32.9 <https://github.com/jedie/django-tools/compare/v0.32.8...v0.32.9>`_ 

    * Bugfix ``DebugCacheLoader`` if TemplateDoesNotExist was raised

* v0.32.8 - 16.03.2017 - `compare v0.32.7...v0.32.8 <https://github.com/jedie/django-tools/compare/v0.32.7...v0.32.8>`_ 

    * NEW: ``django_tools.template.loader.DebugCacheLoader`` to add template name as html comments

    * Change temp filename in BrowserDebug and use ``django_tools_browserdebug_`` prefix

    * Bugfix in ``django_tools.middlewares.ThreadLocal.ThreadLocalMiddleware``

* v0.32.7 - 10.03.2017 - `compare v0.32.6...v0.32.7 <https://github.com/jedie/django-tools/compare/v0.32.6...v0.32.7>`_ 

    * NEW: ``django_tools.permissions`` - helper for setup permissions

    * NEW: ``/unittest_utils/user.py`` - helper for creating users (needfull in unittests)

* v0.32.6 - 22.02.2017 - `compare v0.32.5...v0.32.6 <https://github.com/jedie/django-tools/compare/v0.32.5...v0.32.6>`_

* ``@task_always_eager()`` decorator will set ``CELERY_EAGER_PROPAGATES_EXCEPTIONS=True``, too.

* v0.32.5 - 10.02.2017 - `compare v0.32.4...v0.32.5 <https://github.com/jedie/django-tools/compare/v0.32.4...v0.32.5>`_ 

    * NEW: Add ``template_name`` (optional) to ``self.assertResponse()`` (check with ``assertTemplateUsed()``)

* v0.32.4 - 01.02.2017 - `compare v0.32.3...v0.32.4 <https://github.com/jedie/django-tools/compare/v0.32.3...v0.32.4>`_

* Fix: Set "is_active" for created test users

* v0.32.3 - 25.01.2017 - `compare v0.32.2...v0.32.3 <https://github.com/jedie/django-tools/compare/v0.32.2...v0.32.3>`_ 

    * Fix UnicodeDecodeError in BrowserDebug

    * NEW: ``@set_string_if_invalid()`` decorator

    * NEW: ``@task_always_eager()`` decorator

* v0.32.2 - 13.01.2017 - `compare v0.32.1...v0.32.2 <https://github.com/jedie/django-tools/compare/v0.32.1...v0.32.2>`_ 

    * NEW: django_tools.utils.url.GetDict

* v0.32.1 - 29.12.2016 - `compare v0.32.0...v0.32.1 <https://github.com/jedie/django-tools/compare/v0.32.0...v0.32.1>`_ 

    * NEW: TracebackLogMiddleware

* v0.32.0 - 19.12.2016 - `compare v0.31.0...v0.32.0 <https://github.com/jedie/django-tools/compare/v0.31.0...v0.32.0>`_ 

    * NEW: Management commands: 'nice_diffsettings', 'list_models'

    * NEW: @display_admin_error to display silent errors in ModelAdmin.list_display callables.

    * NEW: django_tools.template.render.render_template_file

    * use `pytest-django <https://pypi.python.org/pypi/pytest-django>`_

    * remove outdated stuff: See 'Backwards-incompatible changes' above.

* v0.31.0 - 03.11.2016 - `compare v0.30.4...v0.31.0 <https://github.com/jedie/django-tools/compare/v0.30.4...v0.31.0>`_ 

    * add Mockup utils to create dummy PIL/django-filer images with Text (see above)

    * move tests into ``/django_tools_tests/``

* v0.30.4 - 27.10.2016 - `compare v0.30.2...v0.30.4 <https://github.com/jedie/django-tools/compare/v0.30.2...v0.30.4>`_ 

    * add DjangoCommandMixin

* v0.30.2 - 05.10.2016 - `compare v0.30.1...v0.30.2 <https://github.com/jedie/django-tools/compare/v0.30.1...v0.30.2>`_ 

    * Bugfix Python 2 compatibility

* v0.30.1 - 26.08.2016 - `compare v0.30.0...v0.30.1 <https://github.com/jedie/django-tools/compare/v0.30.0...v0.30.1>`_ 

    * add: ``django_tools.unittest_utils.disable_migrations.DisableMigrations`` (see above)

    * run tests also with django v1.10 and Python 3.5

    * use tox

* v0.30.0 - 27.04.2016 - `compare v0.29.5...v0.30.0 <https://github.com/jedie/django-tools/compare/v0.29.5...v0.30.0>`_ 

    * Django 1.9 and Python 3 support contributed by `naegelyd <https://github.com/jedie/django-tools/pull/9>`_

* v0.29.4 and v0.29.5 - 10.08.2015 - `compare v0.29.3...v0.29.5 <https://github.com/jedie/django-tools/compare/v0.29.3...v0.29.5>`_ 

    * Some bugfixes for django 1.6 support

* v0.29.3 - 10.08.2015 - `compare v0.29.2...v0.29.3 <https://github.com/jedie/django-tools/compare/v0.29.2...v0.29.3>`_ 

    * Clear ThreadLocal request atttribute after response is processed (contributed by Lucas Wiman)

* v0.29.2 - 19.06.2015 - `compare v0.29.1...v0.29.2 <https://github.com/jedie/django-tools/compare/v0.29.1...v0.29.2>`_ 

    * Bugfix in unittest_utils.selenium_utils.selenium2fakes_response

    * assertResponse used assertContains from django

    * Add QueryLogMiddleware (TODO: add tests)

* v0.29.1 - 17.06.2015 - `compare v0.29.0...v0.29.1 <https://github.com/jedie/django-tools/compare/v0.29.0...v0.29.1>`_ 

    * Bugfixes for Py2 and Py3

    * add StdoutStderrBuffer()

* v0.29.0 - 09.06.2015 - `compare v0.26.0...v0.29.0 <https://github.com/jedie/django-tools/compare/v0.26.0...v0.29.0>`_ 

    * WIP: Refactor unittests (DocTests must be updated for Py3 and more unittests must be written to cover all)

    * catch more directory traversal attacks in BaseFilesystemBrowser (and merge code parts)

    * Bugfix for "django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet." if using **UpdateInfoBaseModel**

    * Bugfixes in **dynamic_site** for django 1.7

    * add: `django_tools.settings_utils.InternalIps <https://github.com/jedie/django-tools/blob/master/django_tools/settings_utils.py>`_

* v0.28.0 - 12.02.2015 - `compare v0.26.0...v0.28.0 <https://github.com/jedie/django-tools/compare/v0.26.0...v0.28.0>`_ 

    * Work-a-round for import loops

    * (new Version number, because of PyPi stress)

* v0.26.0 - 11.02.2015 - `compare v0.25.1...v0.26.0 <https://github.com/jedie/django-tools/compare/v0.25.1...v0.26.0>`_ 

    * Updates for Django 1.6 and Python 3

* v0.25.1 - 18.11.2013

    * Bugfix: Fall back to "UTF-8" if server send no encoding info

* v0.25.0 - 28.08.2012

    * Rename **cache.clear()** in SmoothCacheBackends to **cache.smooth_update()**, so that reset timestamp is independ from clear the cache.

* v0.24.10 - 24.08.2012

    * Add **SmoothCacheBackends**: `./cache/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole>`_

* v0.24.9 - 24.08.2012

    * Bugfix in per-site cache middleware: set inital count values to None, if counting is disabled.

* v0.24.8 - 24.08.2012

    * Enhanced **per-site cache middleware**: `./cache/README.creole`_

    * Add **SetRequestDebugMiddleware**: `./debug/README.creole`_

* v0.24.7 - 21.08.2012

    * Add the **per-site cache middleware** (see above)

    * Add **import lib helper**: `./utils/importlib.py`_

* v0.24.6 - 21.08.2012

    * Add the **filemanager library** (see above)

* v0.24.5 - 06.08.2012

    * Add **Print SQL Queries** context manager. (see above)

* v0.24.4 - 26.07.2012

    * remove date from version string, cause of side-effects e.g.: user clone the repo and has the filter not installed

* v0.24.3 - 25.07.2012

    * "Hardcode" the version string date attachment via `gitattribute filter script <https://github.com/jedie/python-code-snippets/tree/master/CodeSnippets/git>`_ to fix `a reported issues <https://github.com/jedie/django-tools/issues/1>`_ with `pip requirements file bug <https://github.com/pypa/pip/issues/145>`_.

* v0.24.2 - 10.07.2012

    * Split `UpdateInfoBaseModel() <https://github.com/jedie/django-tools/blob/master/django_tools/models.py>`_: So you can only set "createtime", "lastupdatetime" or "createby", "lastupdateby" or both types (This is backwards compatible)

* v0.24.1 - 12.06.2012

    * Bugfix: UsergroupsModelField() and add unittests for it

    * Add "normal users" in UsergroupsModelField()

    * New: Add create_user() and create_testusers() to BaseTestCase

    * Add a test project for the unittests. TODO: use this for all tests

* v0.24.0 - 04.06.2012

    * `Don't use auto_now_add and auto_now in UpdateInfoBaseModel <https://github.com/jedie/django-tools/commit/a3cf1f7b2e9dbe4964306f4793c74f1782f8b2ea>`_

    * Bugfix in `UsergroupsModelField <https://github.com/jedie/django-tools/blob/master/django_tools/limit_to_usergroups.py>`_

* v0.23.1

    * `Dynamic Site <https://github.com/jedie/django-tools/tree/master/django_tools/dynamic_site#dynamic-site-id>`_ would be only initialised if settings.USE_DYNAMIC_SITE_MIDDLEWARE = True

* v0.23.0

    * Use cryptographic signing tools from django 1.4 in django_tools.utils.client_storage

* v0.22.0

    * Add `static_path.py <https://github.com/jedie/django-tools/blob/master/django_tools/fields/static_path.py>`_ thats used settings.STATIC_ROOT.

    * The old `media_path.py <https://github.com/jedie/django-tools/blob/master/django_tools/fields/media_path.py>`_ which used settings.MEDIA_ROOT is deprecated and will be removed in the future.

    * auto_add_check_unique_together() can use settings.DATABASES["default"]["ENGINE"], too.

* v0.21.1

    * Bugfixes in `Dynamic Site`_.

* v0.21.0beta

    * New: site alias function

    * refractory 'DynamicSiteMiddleware' to a own app (**Backwards-incompatible change:** change your settings if you use the old DynamicSiteMiddleware.)

* v0.20.1

    * New: `debug_csrf_failure() <https://github.com/jedie/django-tools/blob/master/django_tools/views/csrf.py>`_ to display the normal debug page and not the minimal csrf debug page.

* v0.20.0

    * Add experimental `DynamicSiteMiddleware <https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/DynamicSite.py>`_, please test it and give feedback.

* v0.19.6

    * Add some south introspection rules for LanguageCodeModelField and jQueryTagModelField

    * fallback if message for anonymous user can't created, because django.contrib.messages middleware not used.

    * Bugfix in django_tools.utils.messages.StackInfoStorage

* v0.19.5

    * Add `http://bugs.python.org/file22767/hp_fix.diff <http://bugs.python.org/file22767/hp_fix.diff>`_ for `https://github.com/gregmuellegger/django/issues/1 <https://github.com/gregmuellegger/django/issues/1>`_

* v0.19.4

    * Bugfix for PyPy in local_sync_cache get_cache_information(): sys.getsizeof() not implemented on PyPy

    * Bugfix in template.filters.chmod_symbol()

    * Nicer solution for template.filters.human_duration()

* v0.19.3

    * Add support for https in utils/http.py

* v0.19.2

    * Bugfix in utils/http.py timeout work-a-round

* v0.19.1

    * utils/http.py changes:

        * Use a better solution, see:

        * Add timeout and add a work-a-round for Python < 2.6

* v0.19.0

    * NEW: Add utils/http.py with helpers to get a webpage via http GET in unicode

    * Change README from textile to creole ;)

* v0.18.2

    * Bugfix: Add missing template in pypi package

* v0.18.0

    * NEW: Add DOM compare from Gregor Müllegger GSoC work into unittest utils.

* v0.17.1

    * Bugfix in “limit_to_usergroups”: Make choices “lazy”: Don’t access the database in *init*

* v0.17

    * Add the script “upgrade_virtualenv.py”

    * Add “limit_to_usergroups”

    * Add “local sync cache”

    * Add models.UpdateInfoBaseModel

    * Update decorators.render_to

    * render_to pass keyword arguments to render_to_response() (e.g.: mimetype=“text/plain”)

    * new argument “skip_fail” in get_filtered_apps(): If True: raise excaption if app is not importable

* v0.16.4

    * Bugfix: ``get_db_prep_save() got an unexpected keyword argument 'connection’`` when save a SignSeparatedModelField()

* v0.16.3

    * Update BrowserDebug: Use response.templates instead of response.template and make output nicer

* v0.16.2

    * Merge stack info code and display better stack info on browser debug page

* v0.16.1

    * Update django_tools.utils.messages.StackInfoStorage for django code changes.

* v0.16.0

    * NEW: path model field (check if direcotry exist)

* v0.15.0

    * NEW: Add a flexible URL field (own validator, model- and form-field)

* v0.14.1

    * Bugfix: make path in MediaPathModelField relativ (remove slashes)

* v0.14

    * NEW: django-tagging addon: Display existing tags under a tag field

* v0.13

    * Bugfix UnicodeEncodeError in Browser debug

* v0.12

    * NEW: django_tools.utils.messages.failsafe_message

* v0.11

    * NEW: Store data in a secure cookie, see: utils/client_storage.py

* v0.10.1

    * New: Display used templates in unittest BrowserDebug

    * Bugfix: catch if last usermessages exist

* v0.10.0

    * NEW: utils around django messages, see: /django_tools/utils/messages.py

* v0.9.1

    * Bugfix: database column was not created: don’t overwrite get_internal_type()

* v0.9

    * New: stuff in /django_tools/fields/

    * see also backwards-incompatible changes, above!

* v0.8.2

    * New: widgets.SelectMediaPath(): Select a sub directory in settings.MEDIA_ROOT

    * New: fields.SignSeparatedField()

* v0.8.1

    * Add “no_args” keyword argument to installed_apps_utils.get_filtered_apps()

* v0.8.0

    * Add model LanguageCode field and form LanguageCode field in Accept-Language header format (RFC 2616)

* v0.7.0

    * Add decorators.py

* v0.6.0

    * Add forms_utils.LimitManyToManyFields, crosspost: `http://www.djangosnippets.org/snippets/1691/ <http://www.djangosnippets.org/snippets/1691/>`_

* v0.5.0

    * Add template/filters.py from PyLucid v0.8.x

* v0.4.0

    * Add experimental “warn_invalid_template_vars”

* v0.3.1

    * Bugfix: Exclude the instance if it was saved in the past.

* v0.3.0

    * Add utils.installed_apps_utils

* v0.2.0

    * Add models_utils, see: `http://www.jensdiemer.de/_command/118/blog/detail/67/ <http://www.jensdiemer.de/_command/118/blog/detail/67/>`_ (de)

* v0.1.0

    * first version cut out from PyLucid CMS – `http://www.pylucid.org <http://www.pylucid.org>`_

-----
links
-----

+----------+----------------------------------------------+
| Homepage | `http://github.com/jedie/django-tools`_      |
+----------+----------------------------------------------+
| PyPi     | `http://pypi.python.org/pypi/django-tools/`_ |
+----------+----------------------------------------------+

.. _http://github.com/jedie/django-tools: http://github.com/jedie/django-tools
.. _http://pypi.python.org/pypi/django-tools/: http://pypi.python.org/pypi/django-tools/

--------
donation
--------

* `paypal.me/JensDiemer <https://www.paypal.me/JensDiemer>`_

* `Flattr This! <https://flattr.com/submit/auto?uid=jedie&url=https%3A%2F%2Fgithub.com%2Fjedie%2Fdjango-tools%2F>`_

* Send `Bitcoins <http://www.bitcoin.org/>`_ to `1823RZ5Md1Q2X5aSXRC5LRPcYdveCiVX6F <https://blockexplorer.com/address/1823RZ5Md1Q2X5aSXRC5LRPcYdveCiVX6F>`_

