Skip to main content

django-tos

CI PyPI Python versions Django versions

This project gives the admin the ability to reset terms of agreement with the end users. It tracks when TOS are changed and when users agree to the new TOS.

Summary

  • Keeps track of when TOS is changed
  • Users need to be informed and agree/re-agree when they login (custom login is provided)
  • Just two models (TOS and user agreement)

Requirements

Supports Django 4.2, 5.0, 5.1, 5.2, 6.0, and 6.1 on Python 3.10 through 3.15 (including free-threaded 3.14 and 3.15). Python 3.15 is still in beta, so it is tested but not yet promised.

django-tos also relies on AUTH_USER_MODEL (the UserAgreement foreign key) and LOGIN_REDIRECT_URL (the post-agreement redirect fallback).

Terms Of Service Installation

  1. pip install django-tos
  2. Add tos to your INSTALLED_APPS setting.
  3. Sync your database with python manage.py migrate

Creating a Terms of Service

django-tos needs an active TermsOfService to check users against. Create one in the Django admin (or via a data migration / fixture) and mark it active. Saving a new active TermsOfService automatically deactivates the previous one.

If no active terms exist, django-tos warns when DEBUG is True and raises tos.models.NoActiveTermsOfService when DEBUG is False. A fresh database in development therefore will not crash, while a misconfigured production deploy fails loudly rather than silently skipping the check.

Configuration

Options

There are two ways to configure django-tos - either enable the TOS check when users sign in, or use middleware to enable the TOS check on every GET request.

If you cannot override your login view (for instance, if you're using django-allauth) you should use the second option.

Option 1: TOS Check On Sign In

In your root urlconf file urls.py add:

from django.urls import include, path, re_path

from tos.views import login

# terms of service links
urlpatterns += [
    re_path(r'^login/$', login, name='auth_login'),
    path('terms-of-service/', include('tos.urls')),
]

Option 2: Middleware Check

This option uses the incr methods for the configured Django cache. If you are using django-tos in a complex or parallel environment, be sure to use a cache backend that supports atomic increment operations. For more information, see the notes at the end of this section of the Django documentation.

Also, to ensure that warming the cache with users who can skip the agreement check works properly, you will need to include tos before your own apps in your INSTALLED_APPS setting:

INSTALLED_APPS = (
    ...
    'tos',
    # your own apps come after tos
    ...
)

Advantages

  • Can optionally use a separate cache for TOS agreements (necessary if your default cache does not support atomic increment operations)
  • Allow some of your users to skip the TOS check (eg: developers, staff, admin, superusers, employees)
  • Uses signals to invalidate cached agreements
  • Skips the agreement check when the user is anonymous or not signed in
  • Skips the agreement check when the request is AJAX
  • Skips the agreement check when the request isn't a GET request (to avoid getting in the way of data mutations)

Disadvantages

  • Requires a cache key for each user who is signed in
  • Requires an additional cache key for each staff user
  • May leave keys in the cache when the active TermsOfService changes

Efficiency

  • Best case for staff users: 2 cache hits
  • Best case for non-staff users: 1 cache miss, 2 cache hits
  • Worst case: 1 cache hit, 2 cache misses, 1 database query, 1 cache set (this should only happen when the user signs in)

Option 2 Configuration

  1. In your root urlconf file urls.py only add the terms-of-service URLs:

    # terms of service links
    urlpatterns += [
        path('terms-of-service/', include('tos.urls')),
    ]
    
  2. Optional: Since the cache used by TOS will be overwhelmingly read-heavy, you can use a separate cache specifically for TOS. To do so, create a new cache in your project's settings.py:

    CACHES = {
        ...
        # The cache specifically for django-tos
        'tos': {  # Can use any name here
            'BACKEND': ...,
            'LOCATION': ...,
            'NAME': 'tos-cache',  # Can use any name here
        },
    }
    

    and configure django-tos to use the new cache:

    TOS_CACHE_NAME = 'tos'  # Must match the key name in CACHES
    

    this setting defaults to the default cache.

  3. Then in your project's settings.py add the middleware to MIDDLEWARE:

    MIDDLEWARE = (
        ...
        # Terms of service checks
        'tos.middleware.UserAgreementMiddleware',
    )
    
  4. Optional: To allow users to skip the TOS check, you will need to set corresponding cache keys for them in the TOS cache. The cache key for each user will need to be prefixed with django:tos:skip_tos_check:, and have the user ID appended to it.

    Here is an example app configuration that allows staff users and superusers to skip the TOS agreement check:

    from django.apps import AppConfig, apps
    from django.conf import settings
    from django.contrib.auth import get_user_model
    from django.db.models.signals import post_save
    
    class MyAppConfig(AppConfig):
        name = 'myapp'
    
        def ready(self):
            if 'tos' in settings.INSTALLED_APPS:
                from tos.utils import add_staff_users_to_tos_cache, set_staff_in_cache_for_tos
                tos_app = apps.get_app_config('tos')
                TermsOfService = tos_app.get_model('TermsOfService')
    
                post_save.connect(set_staff_in_cache_for_tos, sender=get_user_model(), dispatch_uid='set_staff_in_cache_for_tos')
    
                post_save.connect(add_staff_users_to_tos_cache, sender=TermsOfService, dispatch_uid='add_staff_users_to_tos_cache')
    

django-tos-i18n

django-tos internationalization using django-modeltranslation.

Terms Of Service i18n Installation

Assuming you have correctly installed django-tos in your app you only need to add following apps to INSTALLED_APPS:

INSTALLED_APPS += ('modeltranslation', 'tos_i18n')

You should also define your languages in Django's LANGUAGES setting, e.g.:

LANGUAGES = (
    ('pl', 'Polski'),
    ('en', 'English'),
)

Please note that adding those to INSTALLED_APPS changes Django models: for every registered field that should be translated, it adds fields named field_<lang_code>. For example, given this model:

class MyModel(models.Model):
    name = models.CharField(max_length=10)

the following fields are generated: name, name_en, name_pl.

That's it. You are now running tos in i18n mode with the languages you declared in LANGUAGES setting. This will also make all required adjustments in the Django admin.

For more info on how translation works in details please refer to the django-modeltranslation documentation.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_tos-1.2.1.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_tos-1.2.1-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file django_tos-1.2.1.tar.gz.

File metadata

  • Download URL: django_tos-1.2.1.tar.gz
  • Upload date:
  • Size: 11.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for django_tos-1.2.1.tar.gz
Algorithm Hash digest
SHA256 59c77a4796727db6fe2efde1dbbd4b5dfb99e25b24e5612b6a073ad1bebee78d
MD5 7f3080b6561a6bff60c70b2aedba32c1
BLAKE2b-256 7047aa604ac95254468a31434e3fa4ef06cd2b12060a76a727a57a4017981129

See more details on using hashes here.

File details

Details for the file django_tos-1.2.1-py3-none-any.whl.

File metadata

  • Download URL: django_tos-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 16.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for django_tos-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0342a51b1c5d6e8f21cdcfb3dee93634e86e81babccfcb4bd3287c4abf2648b3
MD5 0c07b0e6c2ca60ad7498e56fafb909b1
BLAKE2b-256 a72c22f83cffbd989780fb687b2692b0a2789b02685e8bc8819203e42c7ea21d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page