Lightweight Django app to manage legal documents and user acceptance.
Project description
django-legal
django-legal is a lightweight Django app for managing legal documents (Terms of Use, Privacy Policy, etc.) and tracking which versions each user has agreed to.
What the app does
Many sites need users to agree to one or more legal documents, and to re-accept when those documents change.
django-legal provides:
- Document & version management
- Create legal documents in the Django admin.
- Split documents into ordered sections.
- Publish immutable versions with an automatic
X.Y.Zversion label. - Store a hash for each published version.
- User acceptance tracking
- Record which versions each user has accepted.
- Keep a snapshot of the version hash at acceptance time.
- Require re-acceptance for new versions.
- View protection
- A
@legal_requireddecorator that checks whether the user has accepted the latest versions of all required documents. - If not compliant, redirect the user to a central "acceptance gate" page or any custom page designated by the user.
- A
- Minimal templates
- Ships with simple example templates for the acceptance flow and current-version display.
- You are encouraged to override these in your own project.
At a high level, the app answers one question:
"Does the current authenticated user accept the conditions of all required legal documents?"
Installation
Install from PyPI or from your chosen source:
pip install mroudai-django-legal
Ensure all the listed apps are in the INSTALLED_APPS list:
# settings.py
INSTALLED_APPS = [
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
...,
"django_legal",
]
Make sure you have authentication middleware enabled:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
# ...
]
Include the app's URLs (for the acceptance gate and the current version view):
# urls.py
from django.urls import include, path
urlpatterns = [
# ...
path("legal/", include("django_legal.urls")),
]
Run migrations:
python manage.py migrate
Configuration
Most projects can use the defaults. The main optional setting is:
# settings.py
LEGAL_ACCEPTANCE_URL = "/legal/accept/"
If LEGAL_ACCEPTANCE_URL is set, django-legal will redirect non-compliant users to that path (or URL). If it is not set, the app will try to reverse the built-in gate view
named "django_legal:accept", and finally fall back to "/legal/accept/" if URL reversing fails.
The app uses your configured AUTH_USER_MODEL internally, via settings.AUTH_USER_MODEL. It works with the default django.contrib.auth.models.User and with custom user models.
Basic usage
1. Create documents in the admin
- Log into Django admin.
- Create one or more LegalDocument entries (e.g. "Terms of Use", "Privacy Policy").
- Set
is_required=Truefor documents that users must accept so they can access and use the site.
- Set
- Add sections for each document using
LegalDocumentSectionto build up the full text in order. - Publish a new version for each document. This takes a snapshot of the current sections, computes a hash, and assigns an
X.Y.Zversion label.
Once a document has at least one published version, the app can start enforcing acceptance.
2. Protect views with @legal_required
Use the legal_required decorator to enforce that the current user has accepted the latest versions of all required documents.
You will usually combine it with @login_required so only authenticated users reach the legal checks:
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django_legal.decorators import legal_required
@login_required
@legal_required
def dashboard(request):
return render(request, "dashboard.html")
Behaviour:
- If the user is not authenticated,
legal_requiredsimply lets the view run; authentication is left to your own logic. - If the user is authenticated and compliant, the view runs normally.
- If the user is authenticated but missing required acceptances, they are redirected to the acceptance gate URL (see below), with a
nextquery parameter pointing back to the original path.
3. Use the acceptance gate
django-legal ships with a central gate view at django_legal.views.acceptance_gate, exposed by the URL pattern:
path("accept/", acceptance_gate, name="accept")(included viainclude("django_legal.urls")).
Behaviour:
- GET: shows all required legal documents for which the current user has not accepted the latest version. It uses the template
django_legal/acceptance_gate.htmlby default. - POST: records acceptance for all missing current versions for
request.user, then redirects to:- The
nextparameter from the request (if present), or "/"as a fallback.
- The
You can override the gate template by creating your own file at:
templates/
django_legal/
acceptance_gate.html
4. Display the current version of a document
The app provides a simple view to display the latest published version of a document by slug:
- URL pattern:
path("<slug:slug>/current/", current_version_view, name="current_version") - Default template:
django_legal/current_version.html
You can link to this from your own templates, for example:
<a href="{% url 'django_legal:current_version' slug='terms-of-use' %}">
View current Terms of Use
</a>
As with the gate template, you can override current_version.html under templates/django_legal/ in your project.
Version publishing
- Calling
LegalDocument.publish_new_version()returns(version, created). When the current snapshot matches the latest version, it returns the existing version withcreated=False. - Publishing is idempotent and uses a stable hash (slug + version + snapshot) to avoid churn; admin actions already handle this return shape.
Checking compliance in code
If you need to check a user's compliance manually (outside of the decorator), you can call check_user_legal_compliance:
from django_legal.models import check_user_legal_compliance
is_compliant, missing_versions = check_user_legal_compliance(request.user)
if not is_compliant:
# missing_versions is a list of LegalDocumentVersion objects
...
You generally don't need to record acceptances manually, but if you do, you can use the manager on LegalDocumentAcceptance:
from django_legal.models import LegalDocumentAcceptance
LegalDocumentAcceptance.objects.record_acceptance(
user=request.user,
version=version,
ip_address=request.META.get("REMOTE_ADDR"),
user_agent=request.META.get("HTTP_USER_AGENT", ""),
)
Authentication and django-allauth
django-legal builds on Django's standard authentication system:
- It always references the user model via
settings.AUTH_USER_MODEL. - It expects
AuthenticationMiddlewareand session middleware to be enabled. - It works with the default
Usermodel and with custom user models.
When you use django-allauth, no special integration is required:
- allauth signs users in to the same
request.userobject thatdjango-legaluses. - The
@login_requiredand@legal_requireddecorators behave the same way regardless of how the user logged in (username/password, social login, etc.).
In an allauth project you typically have URLs like:
path("accounts/", include("allauth.urls")),
path("legal/", include("django_legal.urls")),
and then decorate any protected views with @login_required and @legal_required as shown above.
Project status
This is an early version of django-legal. The core behaviour is in place, but the API and templates may still evolve. Feedback and contributions are welcome.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mroudai_django_legal-0.1.1.tar.gz.
File metadata
- Download URL: mroudai_django_legal-0.1.1.tar.gz
- Upload date:
- Size: 18.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe00574c1598cd11dc4b0481c961b45e178630c0258be97086da8f5cf1282ca4
|
|
| MD5 |
b3d7356fad242dd86894b1f1a0dd97e5
|
|
| BLAKE2b-256 |
8595d2d9c38fe41412c954e2c122b606b21f8087b9a36ff6ec519e6894febf61
|
File details
Details for the file mroudai_django_legal-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mroudai_django_legal-0.1.1-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc18d21597be4dbb324f248b7038b5fc42c845031cc306ff9d5265f3b46ac0f6
|
|
| MD5 |
3333cce878f4f77d34ce4ff41fdf7b5d
|
|
| BLAKE2b-256 |
4d5ac4f5985a16bf119155b712aa581310e268e4435c6bf1bdc09ce4834afd6a
|