Opinionated collection of Django and DRF tools that came in handy time and again.
Project description
… wait, why isn’t this part of Django already?
A focused collection of Django and Django REST framework utilities that solve real, recurring problems — the kind you keep re-inventing or copy&pasting in every new project.
$ pip install django-seriously
What’s in the box
PydanticJSONField — typed, validated JSON fields backed by Pydantic
TokenAuthentication — secure, scoped API tokens without the OAuth2 overhead
BaseModel — UUID PKs, timestamps, and guaranteed validation on every save
MinimalUser — email-only user model without the cruft
AdminItemAction — per-row action buttons in Django admin list views
admin_navigation_link — clickable links between related models in admin
Features
PydanticJSONField / ValidatedJSONField
Django’s JSONField is a black box — anything goes in, no guarantees come out. These fields bring schema validation and automatic deserialization using Pydantic v2.
PydanticJSONField — validates and deserializes to a typed Pydantic model instance
ValidatedJSONField — validates structure but keeps the raw Python object
from pydantic import BaseModel
from django_seriously.pydantic.fields import PydanticJSONField
class Address(BaseModel):
street: str
city: str
zip_code: str
class Contact(models.Model):
address = PydanticJSONField(structure=Address)
# Validated and deserialized automatically — no manual parsing needed
contact = Contact.objects.get(pk=pk)
print(contact.address.city) # 'Berlin'
Works seamlessly in:
Django admin (pretty-printed JSON editor)
DRF serializers (auto-detected)
Form validation
Seamless integration with drf-spectacular. OpenAPI3-compliant schemas for those validated JSON fields.
TokenAuthentication
When dealing with OAuth2 is overkill, DRF’s built-in token is just horrible, and django-rest-knox just doesn’t fit your permissioning model.
Security:
Tokens are never stored in plain text — only a PBKDF2 hash is saved
Bearer token format: base64(uuid + random_secret) — UUID for fast DB lookup, secret for verification
Optional: Scopes
Simple usage (just authentication, no scopes):
from django_seriously.authtoken.authentication import TokenAuthentication
class ReportsViewSet(viewsets.ModelViewSet):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
With scope-based permissions:
# settings.py
SERIOUSLY_SETTINGS = {
"AUTH_TOKEN_SCOPES": ["read", "write", "admin"]
}
# views.py
from django_seriously.authtoken.authentication import TokenAuthentication, TokenHasScope
class ReportsViewSet(viewsets.ModelViewSet):
authentication_classes = [TokenAuthentication]
permission_classes = [TokenHasScope]
required_scopes = ['read']
Admin integration: tokens are shown once at creation (copy/paste), then stored only as hashes — just like a good secret manager.
BaseModel
The abstract base model you define in every new project, done properly.
UUID primary key (uuid4) — no sequential ID leakage
Automatic timestamps — immutable created_at, auto-updating updated_at
Validation always runs — overrides save() to call full_clean() every time, not just through forms/admin
That last point matters: Django only runs model validation in forms and the admin by default. Direct .save() calls silently skip your clean() logic. BaseModel closes that gap.
from django_seriously.utils.models import BaseModel
class Article(BaseModel):
title = models.CharField(max_length=200)
# uuid pk, created_at, updated_at included
# full_clean() called automatically on every save()
MinimalUser
Django’s AbstractUser ships with username, first_name, last_name, and other fields that most modern apps don’t need. MinimalAbstractUser strips that down to what you actually use.
Email-based authentication (no username field)
Supports passwordless user creation (magic links, SSO)
Drop-in MinimalUserAdmin included
# models.py
from django_seriously.minimaluser.models import MinimalAbstractUser
from django_seriously.utils.models import BaseModel
class User(BaseModel, MinimalAbstractUser):
# Add your fields here
pass
# admin.py
from django_seriously.minimaluser.admin import MinimalUserAdmin
@admin.register(User)
class UserAdmin(MinimalUserAdmin):
pass
AdminItemAction
Django admin’s built-in actions apply to a selected batch of rows. AdminItemAction puts a context-aware action button directly on each row — and only shows it when the action makes sense for that item.
# admin.py
from django_seriously.utils.admin import AdminItemAction
class UserAdminAction(AdminItemAction[User]):
model_cls = User
actions = [("reset_invitation", "Reset Invitation")]
@classmethod
def is_actionable(cls, obj: User, action: str) -> bool:
if action == "reset_invitation":
return obj.invitation_pending
return False
def perform_action(self, obj: User, action: str) -> None:
if action == "reset_invitation":
send_invitation(obj) # your code
@admin.register(User)
class UserAdmin(ModelAdmin):
list_display = (..., "admin_actions")
def admin_actions(self, obj: User):
return UserAdminAction.action_markup(obj)
# urls.py — item actions must precede regular admin endpoints
urlpatterns = [
path("admin/", AdminItemAction.urls()),
path("admin/", admin.site.urls),
]
Demo
AdminItemAction, admin_navigation_link, MinimalUser, and TokenAuthentication in action:
Requirements
Python >= 3.12
Django >= 4.2
Pydantic >= 2.0
Django REST Framework (optional)
License
Provided by T. Franzel, Licensed under 3-Clause BSD.
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 django_seriously-0.5.0.tar.gz.
File metadata
- Download URL: django_seriously-0.5.0.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4c972a18f3c062613e03696324697e822b642644160a4248efef47571879fb7
|
|
| MD5 |
258391c7dd6aa2e6c929be0d1b2cb53d
|
|
| BLAKE2b-256 |
b3cd582269584bad52711f99380419fbba7cc460fdd6dddce883a2a0f8035dc6
|
File details
Details for the file django_seriously-0.5.0-py3-none-any.whl.
File metadata
- Download URL: django_seriously-0.5.0-py3-none-any.whl
- Upload date:
- Size: 23.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
43629187adf9eed6e5071ae8822922f2e178ad364c3c3047f701463aaea4c479
|
|
| MD5 |
4a548017014b255625c96641b2e73acc
|
|
| BLAKE2b-256 |
daf8df8b0b4d6be19d499e97def76b4c14e17326005c1db1bb90233ecb71d654
|