Reusable Django Workflows
Project description
django-workflows
Reusable Django service helpers for common account flows:
- Registration and verification-code email flow
- Forgot-password code flow
- Reset-code validation and lockout handling
- Transport-neutral email utility with recipient validation
Installation
Install from PyPI:
pip install BmorricalDjangoWorkflows==1.2.3
In requirements.txt, pin it directly:
BmorricalDjangoWorkflows==1.2.3
Note: distribution name is BmorricalDjangoWorkflows, while imports remain under django_workflows.
Host Project Requirements
This package expects the host Django project to provide:
- A Django user model available through
django.contrib.auth.get_user_model() - A user meta model referenced by
WORKFLOWS["USER_META_MODEL"] - A user manager
create_user(...)method that acceptsusername, because this package explicitly setsusername=email
The user meta model should include at least:
userrelationverify_codefieldverify_timefieldattemptsfield
Optional (used if present):
force_password_reset
Django Settings
Add a WORKFLOWS dict in your Django settings.
WORKFLOWS = {
# Required in most projects unless your model path matches the default.
"USER_META_MODEL": "users.models_user_meta.UserMeta",
# Optional settings with defaults shown.
"COMPANY_NAME": "My Company",
"ENABLE_EMAIL_DELIVERY": False,
"RESET_CODE_TTL_MINUTES": 10,
"MAX_VERIFY_ATTEMPTS": 3,
}
Notes:
USER_META_MODELmust be a dotted import path such asmyapp.models.UserMeta.- If
ENABLE_EMAIL_DELIVERYis true, configure the email transport environment variables used by the mail service.
Email Delivery Environment Variables
When email delivery is enabled, set:
ENABLE_EMAIL_DELIVERY=trueEMAIL_DELIVERY_PROVIDER=mailgun|mailpit|smtp|disabledEMAIL_FROM="My Company <no-reply@example.com>"
For the mailgun provider, also set:
EMAIL_API_KEYEMAIL_DOMAIN
Optional:
BCC_RECIPIENTSas a comma-separated listEMAIL_LOG_RESPONSE_TEXT=trueto log response bodies at debug level
Example:
ENABLE_EMAIL_DELIVERY=true
EMAIL_DELIVERY_PROVIDER=mailgun
EMAIL_FROM="My Company <no-reply@example.com>"
EMAIL_DOMAIN="mg.example.com"
EMAIL_API_KEY="key-example"
BCC_RECIPIENTS="audit@example.com,ops@example.com"
If BCC_RECIPIENTS is not set, no static BCC recipients are added.
Old To New Env Mapping
If a consuming app previously used the Mailgun-specific names, update them as follows:
MAILGUN_COMPANY_NAME->EMAIL_FROMENABLE_MAILGUN->ENABLE_EMAIL_DELIVERYMAILGUN_LOG_RESPONSE_TEXT->EMAIL_LOG_RESPONSE_TEXTMAILGUN_API_KEY->EMAIL_API_KEYMAILGUN_DOMAIN->EMAIL_DOMAINMAILGUN_BCC_RECIPIENTS->BCC_RECIPIENTS
Built-In Defaults
If a consuming app does not define one of these values in .env, the package now defaults to:
ENABLE_EMAIL_DELIVERY=FalseEMAIL_API_KEY=""EMAIL_DOMAIN=""EMAIL_DELIVERY_PROVIDER=""DEVELOPMENT_MODE=FalseDEFAULT_FROM_EMAIL=""BCC_RECIPIENTS=""EMAIL_LOG_RESPONSE_TEXT=False
Additional behavior:
EMAIL_FROMfalls back toDEFAULT_FROM_EMAILwhenEMAIL_FROMis unset.- If
EMAIL_DELIVERY_PROVIDERis blank, the package resolves the transport from the other flags: - If
ENABLE_EMAIL_DELIVERY=true, it defaults to themailguntransport. - If
DEVELOPMENT_MODE=true, it defaults to thesmtptransport. - Otherwise delivery remains disabled.
Practical implication:
- Production apps using Mailgun should set
ENABLE_EMAIL_DELIVERY,EMAIL_FROM,EMAIL_API_KEY, andEMAIL_DOMAIN. - Local apps using Mailpit should usually set
EMAIL_DELIVERY_PROVIDER=mailpit,EMAIL_FROM, and the Django SMTP settings shown below. - Apps that do not want this package to send email can omit everything and leave delivery disabled.
Django Email Backend Settings
If a consuming app uses EMAIL_DELIVERY_PROVIDER=smtp or EMAIL_DELIVERY_PROVIDER=mailpit, it should configure Django's email backend in settings.py.
import os
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL")
EMAIL_HOST = os.getenv("EMAIL_HOST", "localhost")
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "25"))
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "")
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "False") == "True"
EMAIL_USE_SSL = os.getenv("EMAIL_USE_SSL", "False") == "True"
Notes:
- This is only needed for the
smtpandmailpitproviders. mailpitcommonly listens on port1025, so setEMAIL_PORTaccordingly in local development.- If you set
EMAIL_FROM, that value is preferred by this package. Otherwise it falls back toDEFAULT_FROM_EMAIL.
Example Usage
from django_workflows.users.services.auth_flow import (
register_user_and_send_verification_email,
send_forgot_password_code,
verify_reset_code,
change_password,
)
result = register_user_and_send_verification_email(
email="person@example.com",
first_name="First",
last_name="Last",
password="example-password",
)
forgot = send_forgot_password_code("person@example.com")
verify = verify_reset_code(email="person@example.com", code="AB12CD")
changed = change_password(
email="person@example.com",
password="new-password",
password_verify="new-password",
)
Direct Email Service Usage
Attachment tuple shape:
(filename, file_bytes_or_file_object, mimetype)
Example attachment entry:
("report.pdf", pdf_bytes, "application/pdf")
from django_workflows.services.email import send_email
response = send_email(
to=["primary@example.com", "secondary@example.com"],
subject="Welcome",
html="<p>Thanks for joining.</p>",
cc="manager@example.com",
bcc=["audit@example.com"],
attachments=[("report.pdf", pdf_bytes, "application/pdf")],
)
# Optional: explicit runtime override for enablement
send_email(
to="user@example.com",
subject="Dry run",
html="<p>This will not send.</p>",
enabled=False,
)
Local Development
Run tests:
make test
Run tests with coverage:
make test-coverage
CI runs tests on push and pull requests using .github/workflows/tests.yml.
Troubleshooting
ImproperlyConfigured for USER_META_MODEL
Error example:
WORKFLOWS['USER_META_MODEL'] must be a dotted path like 'myapp.models.UserMeta'.
Fix:
- Set
WORKFLOWS["USER_META_MODEL"]to a valid dotted import path. - Verify the target model is importable by Django at runtime.
UserMeta field errors
If you see attribute errors around verification state, confirm your user meta model provides:
verify_codeverify_timeattempts
Email delivery not sending
Check:
ENABLE_EMAIL_DELIVERY=trueEMAIL_DELIVERY_PROVIDEREMAIL_FROMorDEFAULT_FROM_EMAILEMAIL_API_KEYandEMAIL_DOMAINwhen using the Mailgun provider
No static BCC recipients applied
This is expected unless you set BCC_RECIPIENTS.
Release
Create a release tag:
./release.sh 0.1.0
After release, update the package version in your consuming application's dependency files.
Tag pushes like v1.2.3 trigger .github/workflows/publish.yml, which publishes to PyPI.
Publishing To PyPI (Maintainer Steps)
- Check whether the target package name is available.
curl -I https://pypi.org/pypi/BmorricalDjangoWorkflows/json
If this returns 404, the name is usually available.
-
Create a PyPI account: https://pypi.org/account/register/
-
Create a PyPI API token: PyPI Account -> Account settings -> API tokens.
-
Add repository secret in GitHub:
- Name:
PYPI_API_TOKEN - Value: your PyPI token (starts with
pypi-)
- Bump and tag a release:
./release.sh 1.2.3
-
Confirm the workflow run succeeded and the package appears on PyPI.
-
Update consuming applications:
BmorricalDjangoWorkflows==1.2.3
If upload fails because the name is already taken, change name= in setup.py, bump version, and release again.
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 bmorricaldjangoworkflows-2.0.3.tar.gz.
File metadata
- Download URL: bmorricaldjangoworkflows-2.0.3.tar.gz
- Upload date:
- Size: 14.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bc77940ec1247c8a57a5607283ed86eadd84f284f0d8e0df644f10abe327ee4
|
|
| MD5 |
bab9790c98e93efb726ebc812f3e00e0
|
|
| BLAKE2b-256 |
e4c530034c0e32eaf8af3d06d1500a69798dd10458b23445917131b11f73df9c
|
File details
Details for the file bmorricaldjangoworkflows-2.0.3-py3-none-any.whl.
File metadata
- Download URL: bmorricaldjangoworkflows-2.0.3-py3-none-any.whl
- Upload date:
- Size: 17.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8e320ce39fde3c241d4ef41f2b6c1025c04b6dc7a00fc6ef62b8cd5cdf07e3b
|
|
| MD5 |
05a9dd1185d7f9ef845645922a0f0368
|
|
| BLAKE2b-256 |
4eca1931191c0a2f953ca4a9de26a74934bc1888222e007a3f11268689f5be75
|