django-launchpad
Renderer-independent navigation and application launchpads for Django.
Every Django application eventually needs navigation: a sidebar, a dashboard, a mobile menu, an account menu, an application launcher, or a command palette.
Most projects build each surface separately.
django-launchpad models them as different presentations of the same
navigation system.
- PyPI: https://pypi.org/project/django-launchpad/
- Source: https://github.com/fifoa-labs/django-launchpad
- License: MIT
Define destinations once. Compose them into named launchpads. Apply user-aware visibility. Resolve the result into a renderer-neutral tree. Then present that tree however your application needs.
NavigationLink
│
▼
LaunchpadNode
│
▼
Launchpad
│
▼
ResolvedLaunchpad
│
├── Sidebar
├── Dashboard cards
├── Top navigation
├── Mobile menu
├── Footer
└── Command palette
The package solves navigation structure, policy, resolution, and optional configuration caching.
Your project owns the user interface.
Why Launchpad?
Navigation often begins as a few hard-coded links and gradually grows into duplicated logic spread across templates, context processors, views, permission checks, and frontend components.
Common problems follow:
- The same destination is defined repeatedly.
- Sidebars and dashboards drift out of sync.
- Permission checks differ between renderers.
- Active-state logic is duplicated.
- Project-specific templates become responsible for data loading.
- Changing navigation requires editing application code.
- A destination cannot be reused with different labels or placement rules.
- Navigation configuration is queried on every request even though it changes rarely.
Launchpad separates the problem into durable layers:
- NavigationLink — the canonical destination.
- LaunchpadNode — one placement of a destination or structural item.
- Launchpad — a named composition of nodes.
- Reader — resolves stored configuration into renderer-neutral data.
- Renderer — remains entirely project-owned.
The same destination can appear in multiple launchpads with different titles, hierarchy, ordering, visibility, metadata, icons, and enabled states—without duplicating the destination itself.
Core Concepts
NavigationLink
A NavigationLink represents a reusable destination.
Examples:
- A Django named URL such as
reports:index - A relative path such as
/documentation/ - An external HTTPS URL
- A
mailto:ortel:link - A context-aware detail URL resolved at render time
A link defines canonical information such as:
- stable code
- title and short title
- description, tooltip, and ARIA label
- destination and URL arguments
- query parameters and fragment
- target,
rel, and download behavior - icon descriptor
- enabled state and disabled reason
- active-match strategy
- visibility policy
- search aliases
- renderer-neutral metadata
A NavigationLink does not decide where it appears.
Launchpad
A Launchpad is a named, renderer-independent navigation composition.
Typical codes include:
primary_navigationhomepageaccount_menumobile_navigationreport_actionscommand_palette
Templates, tests, fixtures, and application code address a Launchpad by
its stable code.
LaunchpadNode
A LaunchpadNode places something inside a Launchpad tree.
A node can be:
- Link — a placement of a
NavigationLink - Section — a structural grouping node
- Separator — a structural divider
Nodes can be nested and ordered. A placement may override the linked destination's presentation without changing the canonical link.
Supported placement overrides include:
- code
- title and short title
- description and tooltip
- ARIA label
- call-to-action label
- icon
- enabled state and disabled reason
- visibility policy
- metadata
Link-level visibility and node-level visibility are both enforced.
This means the link can define a global minimum policy, while an individual placement may restrict visibility further.
Resolution Pipeline
get_launchpad() resolves stored configuration into a
ResolvedLaunchpad tree suitable for any renderer.
The reader:
- Normalizes the requested Launchpad code.
- Loads stable Launchpad configuration from the database or optional persistent cache.
- Loads active nodes and related navigation links efficiently.
- Builds or reuses the request-scoped visibility context.
- Applies node visibility.
- Applies linked
NavigationLinkvisibility. - Resolves context-aware URLs.
- Applies placement overrides.
- Builds the parent-child tree.
- Removes empty sections.
- Removes leading, trailing, and duplicate separators.
- Computes active state for links and their ancestors.
- Returns renderer-neutral data.
Missing or inactive Launchpads fail safely and return an empty
ResolvedLaunchpad rather than raising during template rendering.
Reader Public API
The internal reader implementation is split into focused modules, while the public API remains intentionally small:
from launchpad.readers import (
ResolvedLaunchpad,
ResolvedNode,
get_launchpad,
)
Cache snapshots, database loaders, tree construction, and resolution internals are implementation details and are not part of the supported public reader API.
Features
- Renderer-independent navigation architecture
- Reusable canonical destinations
- Named Launchpad compositions
- Arbitrarily nested node trees
- Link, section, and separator nodes
- Placement-specific presentation overrides
- Public, authenticated, staff, superuser, and private audiences
- Explicit user and group visibility
- Django permission gates
allandanypermission modes- Scheduled visibility windows
- Registered runtime visibility rules
- Named Django URLs and validated raw URLs
- Positional and keyword URL arguments
- Query parameters and fragments
- Context-aware URL values
- Active matching by path or Django view name
- Disabled links that remain visible but non-navigable
- Renderer-neutral metadata
- Generic recursive tree renderer
- Generic semantic card renderer
- Optional responsive row-balancing helper for Bootstrap-style card grids
- Optional persistent configuration caching
- Generation-based cache invalidation
- Configurable Django cache alias
- Request-scoped visibility-context reuse
- Transaction-safe cache invalidation
- Django admin integration
- Fully typed package with
py.typed - Strict mypy validation
- 100% statement and branch coverage
Installation
Install from PyPI:
python -m pip install django-launchpad
With uv:
uv add django-launchpad
Add Launchpad to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"launchpad.apps.LaunchpadConfig",
]
Run migrations:
python manage.py migrate
No package settings are required for normal operation.
Persistent configuration caching is optional and disabled by default.
Quick Start
Launchpad configuration can be created through Django admin, fixtures, migrations, the Django shell, or application code.
The following example creates one canonical destination and places it in a primary navigation Launchpad.
from launchpad.models import Launchpad, LaunchpadNode, NavigationLink
reports_link = NavigationLink.objects.create(
code="reports",
title="Reports",
description="View operational reports.",
url_type=NavigationLink.URLType.NAMED,
url_value="reports:index",
audience=NavigationLink.Audience.AUTHENTICATED,
)
primary_navigation = Launchpad.objects.create(
code="primary_navigation",
title="Primary Navigation",
)
LaunchpadNode.objects.create(
launchpad=primary_navigation,
kind=LaunchpadNode.Kind.LINK,
navigation_link=reports_link,
audience=LaunchpadNode.Audience.PUBLIC,
sort_order=1000,
)
The node is public at the placement level, but the linked destination still requires an authenticated user. Both policies must pass.
Resolve in Python
from launchpad.readers import get_launchpad
navigation = get_launchpad(
"primary_navigation",
request=request,
)
The result is a ResolvedLaunchpad containing renderer-neutral
ResolvedNode objects.
Resolve in a Template
{% load launchpad_tags %}
{% get_launchpad "primary_navigation" as navigation %}
Render the bundled generic tree:
{% include "launchpad/generic/tree.html" with launchpad=navigation only %}
Or render the same resolved Launchpad as semantic cards:
{% include "launchpad/generic/cards.html" with launchpad=navigation only %}
Or pass the same navigation object to a project-owned renderer.
Built-In Reference Renderers
Launchpad ships two lightweight reference renderers:
launchpad/generic/tree.html
launchpad/generic/cards.html
They are optional.
A consuming project may use either renderer directly, override them through normal Django template resolution, or ignore them completely and provide its own theme-specific templates.
Generic Tree Renderer
Use the tree renderer when the Launchpad should preserve its hierarchy:
{% load launchpad_tags %}
{% get_launchpad "primary_navigation" as navigation %}
{% include "launchpad/generic/tree.html" with launchpad=navigation only %}
The tree renderer supports nested sections, links, separators, icons, active and disabled state, accessibility attributes, recursive children, and empty Launchpads.
It emits neutral launchpad-* CSS hooks and does not ship CSS or JavaScript.
Generic Card Renderer
Use the card renderer when resolved navigation should be presented as a collection of semantic cards:
{% load launchpad_tags %}
{% get_launchpad "homepage" as navigation %}
{% include "launchpad/generic/cards.html" with launchpad=navigation only %}
The card renderer supports:
- top-level links
- link children contained in sections
- icons
- titles and descriptions
- CTA labels
- active and disabled state
- target,
rel, and download attributes - tooltip and ARIA metadata
- empty Launchpads
Sections remain structural: their link children become cards rather than the section itself becoming a card.
Separators are intentionally ignored because they do not have a natural card representation.
The generic card renderer uses semantic classes such as:
launchpad-cards
launchpad-card
launchpad-card-header
launchpad-card-icon
launchpad-card-title
launchpad-card-description
launchpad-card-action
launchpad-card-link
It does not depend on Bootstrap, Tailwind CSS, Phoenix, or another theme.
Optional Configuration Caching
Launchpad configuration is naturally read-heavy and write-light.
A primary navigation tree may be resolved on nearly every request while the underlying Launchpad, nodes, links, user assignments, and group assignments change only occasionally.
django-launchpad therefore provides optional persistent caching for
stable Launchpad configuration.
Caching is disabled by default.
Enable it explicitly:
LAUNCHPAD_CACHE_ENABLED = True
Default cache settings are:
LAUNCHPAD_CACHE_ENABLED = False
LAUNCHPAD_CACHE_ALIAS = "default"
LAUNCHPAD_CACHE_TIMEOUT = 900
All three settings are optional.
LAUNCHPAD_CACHE_ENABLED
Controls persistent configuration caching.
LAUNCHPAD_CACHE_ENABLED = True
Default:
False
When disabled, the normal ORM-backed reader path is used.
LAUNCHPAD_CACHE_ALIAS
Selects the Django cache alias Launchpad should use:
LAUNCHPAD_CACHE_ALIAS = "default"
A project may dedicate a separate cache:
CACHES = {
"default": {
# ...
},
"launchpad": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
},
}
LAUNCHPAD_CACHE_ENABLED = True
LAUNCHPAD_CACHE_ALIAS = "launchpad"
LAUNCHPAD_CACHE_TIMEOUT
Controls how long stable configuration snapshots remain physically stored:
LAUNCHPAD_CACHE_TIMEOUT = 900
The default is 15 minutes.
A timeout of 0 follows Django cache semantics and effectively prevents
cached configuration values from being retained.
Negative values are rejected as configuration errors.
What Is Cached?
Persistent caching stores stable configuration snapshots containing data such as:
- Launchpad identity and metadata
- active Launchpad nodes
- parent relationships
- canonical NavigationLink configuration
- placement overrides
- visibility policy fields
- explicit user IDs
- explicit group IDs
Snapshots contain cache-safe data rather than live querysets.
What Is Not Cached?
ResolvedLaunchpad objects are not persistently cached.
User-, request-, time-, and context-sensitive behavior continues to run on every call, including:
- current user visibility
- scheduled visibility windows
- context-aware URL references
- current path
- resolved Django view name
- query-parameter matching
- active-state calculation
- ancestor active-state propagation
This boundary allows Launchpad to cache the expensive, stable configuration layer without freezing request-specific behavior.
Runtime Visibility Rules
Configurations containing registered runtime visibility rules deliberately stay on the live ORM path.
Runtime rules may depend on receiving real Django model instances through
their obj argument. Launchpad therefore does not persist those
configurations as cache snapshots.
This preserves the existing runtime-rule contract.
Request-Scoped Visibility Reuse
Persistent caching is only one part of reader efficiency.
During a single HTTP request, several Launchpads may be resolved:
primary_navigation
home
account_menu
Group membership and Django permission collection are user-derived and do not need to be rebuilt separately for every Launchpad.
Launchpad therefore memoizes the expensive base VisibilityContext on the
request object and attaches a fresh runtime extra_context mapping to each
read.
This is request-scoped memoization, not persistent caching.
Cache Invalidation
Launchpad uses generation-based invalidation.
Conceptually:
django-launchpad:f1:gABC:configuration:home
After a configuration change:
django-launchpad:f1:gXYZ:configuration:home
Existing entries become unreachable immediately and disappear naturally according to their cache timeout.
Launchpad does not depend on Redis-specific wildcard deletion or
delete_pattern().
Automatic Invalidation
Configuration cache invalidation is triggered automatically after:
LaunchpadsaveLaunchpaddeleteNavigationLinksaveNavigationLinkdeleteLaunchpadNodesaveLaunchpadNodedeleteNavigationLink.usersadd/remove/clearNavigationLink.groupsadd/remove/clearLaunchpadNode.usersadd/remove/clearLaunchpadNode.groupsadd/remove/clear
Invalidation uses transaction.on_commit().
This means a new cache generation is not exposed until the database mutation that caused it has committed successfully.
A rolled-back transaction does not invalidate the cache.
Bulk Updates and Direct SQL
Operations that bypass Django model signals also bypass automatic invalidation.
Examples include:
NavigationLink.objects.filter(...).update(...)
and direct SQL.
In those cases, explicitly invalidate configuration:
from launchpad.cache import invalidate_configuration_cache
NavigationLink.objects.filter(...).update(active=False)
invalidate_configuration_cache()
Multi-Process Deployments
For multi-process production deployments, use a shared cache backend such as Redis or Memcached.
Django's local-memory cache is process-local. It is useful for development and testing, but it cannot provide cross-process cache sharing or invalidation.
Optional Responsive Row Balancing
Some responsive card grids look awkward when the real items wrap onto another row and leave that final row partially empty.
Launchpad provides an optional launchpad_pad template helper for this
presentation concern.
The helper does not add fake nodes to the resolved Launchpad.
Instead, it returns either:
- one render-only balancing placeholder descriptor, or
Nonewhen no breakpoint requires balancing.
Example:
{% load launchpad_tags %}
{% get_launchpad "home" as navigation %}
{% launchpad_pad navigation.nodes as padding %}
{% if padding %}
<div class="{{ padding.classes }}">
{{ padding.title }}
</div>
{% endif %}
When Does Padding Appear?
Padding is needed only when both conditions are true at a responsive breakpoint:
- the real items have wrapped beyond the first row, and
- the final row is incomplete.
If all real items fit on one row, there is nothing to balance.
If the final row is already complete, there is nothing to balance.
The default responsive grid is:
xs: 1 column
sm: 2 columns
md: 3 columns
lg: 4 columns
xl: 6 columns
Three real items behave like:
xs → 1 / 1 / 1 no placeholder
sm → 2 / 1 placeholder fills the remaining slot
md → 3 no placeholder
lg → 3 no placeholder
xl → 3 no placeholder
Sixteen real items behave like:
xs → complete single-column rows no placeholder
sm → complete two-column rows no placeholder
md → 3 / 3 / 3 / 3 / 3 / 1 placeholder fills 2 slots
lg → 4 / 4 / 4 / 4 no placeholder
xl → 6 / 6 / 4 placeholder fills 2 slots
Responsive Width
The balancing placeholder expands across exactly the unused portion of the final row.
For a Bootstrap-style twelve-unit grid:
16 items at md / 3 columns
→ final row has 1 of 3 items
→ 2 columns are missing
→ placeholder spans 8 of 12 grid units
16 items at xl / 6 columns
→ final row has 4 of 6 items
→ 2 columns are missing
→ placeholder spans 4 of 12 grid units
Bootstrap-Compatible Helper
The current launchpad_pad helper emits Bootstrap-compatible responsive
display and column classes such as:
d-none
d-sm-block
col-sm-6
d-md-none
d-lg-none
d-xl-none
This helper is optional.
The core Launchpad models, readers, visibility engine, cache, generic tree renderer, and generic card renderer do not require Bootstrap.
Projects using another frontend system may ignore launchpad_pad and
implement balancing in their own renderer.
Placeholder Contract
The render-only placeholder exposes presentation values such as:
is_placeholder = True
title = "More to Explore"
description = "New tools, reports, and operational insights will appear here."
url = "#"
enabled = False
icon = {"kind": "emoji", "value": "✨"}
classes = "<responsive Bootstrap-compatible classes>"
A placeholder is:
- not a
NavigationLink - not a
LaunchpadNode - not stored in the database
- not part of persistent caching
- not evaluated by the visibility engine
- not part of the canonical navigation tree
- not navigable
The original navigation.nodes collection is never modified.
Recommended Usage
The balancing helper is most useful inside a theme-specific card renderer that already knows its responsive grid:
{% for node in navigation.nodes %}
{# render real cards #}
{% endfor %}
{% launchpad_pad navigation.nodes as padding %}
{% if padding %}
<div class="{{ padding.classes }}">
{# render the optional balancing card #}
</div>
{% endif %}
Page templates can then remain simple:
{% load launchpad_tags %}
{% get_launchpad "home" as navigation %}
{% include "navigation/cards.html" with navigation=navigation only %}
Custom Rendering
Launchpad deliberately does not choose a visual framework.
The package does not require:
- Bootstrap
- Tailwind CSS
- Phoenix
- Bulma
- Material UI
- AdminLTE
- JavaScript navigation libraries
The bundled generic renderers use neutral launchpad-* classes and provide
reference implementations for tree and card presentations. They do not ship
a theme, CSS, or JavaScript.
A consuming project may create any renderer it needs:
templates/
└── navigation/
├── sidebar.html
├── dashboard_cards.html
├── mobile_menu.html
└── command_palette.html
Example:
{% load launchpad_tags %}
{% get_launchpad "homepage" as homepage_navigation %}
{% include "navigation/dashboard_cards.html" with launchpad=homepage_navigation only %}
Renderers receive resolved data, not ORM query responsibilities.
Resolved Node Data
A ResolvedNode exposes values such as:
kindcodelink_codetitleshort_titledescriptiontooltiparia_labelcta_labelurltargetreldownloadiconenableddisabled_reasonis_activemetadatachildren
Convenience properties include:
is_linkis_sectionis_separatorhas_children
Visibility
Launchpad visibility controls whether a navigation object is shown.
It does not replace authorization in the destination view.
Destination views must continue to enforce their own permissions.
Audiences
Each visibility-aware link or node has a base audience:
publicauthenticatedstaffsuperuserprivate
These values express different policies.
For example, a destination that should be visible to every signed-in user should normally use:
link.audience = NavigationLink.Audience.AUTHENTICATED
A private object with no explicit users, groups, or permission grant is
intentionally hidden from ordinary users.
Additional user, group, permission, schedule, and runtime-rule constraints may refine the base policy.
Explicit Users and Groups
Private navigation can be granted to selected users or groups:
link.users.add(user)
link.groups.add(group)
Permission gates still apply when configured.
Permission Gates
Permissions use standard Django permission strings:
link.permissions_required = [
"reports.view_report",
"reports.export_report",
]
Require every permission:
link.permissions_mode = NavigationLink.PermissionMode.ALL
Require any one permission:
link.permissions_mode = NavigationLink.PermissionMode.ANY
Permissions are gates, not optional alternate grants. An explicitly assigned user still fails visibility when a configured permission gate fails.
Permission-only visibility is supported:
link.audience = NavigationLink.Audience.PRIVATE
link.permissions_required = ["reports.view_report"]
In this configuration, the permission itself may grant visibility.
Scheduled Visibility
Use visible_from and visible_until to make links or placements visible
only during a time window.
Inactive or scheduled-off objects remain hidden from everyone, including superusers.
Runtime Visibility Rules
Runtime rules support application-specific visibility that cannot be expressed through stored fields alone.
Register a rule under a safe code:
from launchpad.visibility import register_visibility_rule
@register_visibility_rule("has_reports_access")
def has_reports_access(*, obj, user, request, context) -> bool:
return bool(
user
and user.is_authenticated
and context.get("reports_enabled")
)
Store only the rule code:
link.visibility_rule = "has_reports_access"
Launchpad never stores or imports arbitrary Python paths from the database.
Missing rules and rule exceptions fail closed and hide the object.
URL Resolution
Named Django URLs
link.url_type = NavigationLink.URLType.NAMED
link.url_value = "people:detail"
link.url_kwargs = {"pk": 42}
Raw URLs
Supported raw URL forms include:
- relative paths
httphttpsmailtotel
Unsafe and unsupported values are rejected, including:
javascript:data:vbscript:- protocol-relative URLs
- unsupported schemes
#as a disabled-link substitute
Use enabled=False for disabled navigation.
Query Parameters and Fragments
link.query_params = {
"tab": "monthly",
"tag": ["finance", "operations"],
}
link.fragment = "summary"
Existing query parameters are preserved.
Context-Aware Values
URL arguments, keyword arguments, and query parameters may resolve values at runtime.
Supported roots:
@user@request@context
Example:
link.url_type = NavigationLink.URLType.NAMED
link.url_value = "people:detail"
link.url_kwargs = {
"pk": "@context.person.pk",
}
link.query_params = {
"next": "@request.path",
"viewer": "@user.username",
}
In a template:
{% get_launchpad "person_actions" person=person as navigation %}
Context traversal reads attributes and dictionary keys. Callables are not invoked. Missing values fail closed to an empty string.
Active Navigation
Links can determine whether they represent the current request.
Supported strategies:
autononeexact_pathpath_prefixview_nameview_prefix
auto prefers named-view matching for named URLs and then falls back to
path matching.
Configured query parameters also participate in active-state matching.
When a descendant is active, its resolved ancestors are marked active as well, allowing renderers to expand the appropriate sections.
Disabled Navigation
Disabled destinations may remain visible while becoming non-navigable.
link.enabled = False
link.disabled_reason = "Coming soon."
A placement can override the canonical enabled state:
node.enabled_override = False
node.disabled_reason_override = "Unavailable in this workspace."
Disabled nodes resolve to #, and the generic renderers emit non-clickable
markup with aria-disabled="true".
Icons
Launchpad stores renderer-neutral icon descriptors.
Supported descriptors:
noneemojifafe
Example:
link.icon_type = NavigationLink.IconType.EMOJI
link.emoji = "📊"
Or:
link.icon_type = NavigationLink.IconType.FA
link.icon_class = "fa-solid fa-chart-line"
The package does not bundle Font Awesome, Feather, or any other icon library. Renderers decide how descriptors are presented.
Django Admin
Launchpad registers all three models with Django admin:
NavigationLinkLaunchpadLaunchpadNode
The admin provides:
- structured fieldsets
- search and filtering
- related-object autocomplete
- inline node editing inside a Launchpad
- direct node editing for larger trees
- resolved-value inspection
- automatic
created_byassignment - optimized changelist querysets
Django admin is a management interface, not a rendering requirement.
Template Tags
Templates load the complete Launchpad tag library with:
{% load launchpad_tags %}
The tag implementation is internally split into focused modules, but the template-facing API remains a single library.
get_launchpad
Resolve a Launchpad:
{% get_launchpad "primary_navigation" as navigation %}
Supply an explicit user when needed:
{% get_launchpad "primary_navigation" user=request.user as navigation %}
Pass runtime context values:
{% get_launchpad "person_actions" person=person as navigation %}
launchpad_pad
Build an optional responsive balancing descriptor:
{% launchpad_pad navigation.nodes as padding %}
The helper never changes the resolved Launchpad or its node collection.
Public Python API
Models:
from launchpad.models import Launchpad, LaunchpadNode, NavigationLink
Reader:
from launchpad.readers import (
ResolvedLaunchpad,
ResolvedNode,
get_launchpad,
)
Visibility:
from launchpad.visibility import (
VisibilityContext,
build_user_context,
get_visibility_rule,
is_visible,
register_visibility_rule,
)
Cache invalidation for signal-bypassing bulk operations:
from launchpad.cache import invalidate_configuration_cache
Template usage:
{% load launchpad_tags %}
{% get_launchpad "primary_navigation" as navigation %}
{% launchpad_pad navigation.nodes as padding %}
What Launchpad Does Not Do
Launchpad intentionally does not:
- replace authorization in Django views
- generate project views or URL patterns
- require a frontend framework
- require Bootstrap
- ship an opinionated visual theme
- bundle CSS or JavaScript
- bundle icon libraries
- store executable Python import paths
- force navigation definitions into code or templates
- assume a specific user model
- require django-allauth
- require Django REST Framework
- require Redis
- require persistent caching
- persist presentation placeholders
The optional responsive padding helper emits Bootstrap-compatible classes, but using that helper is not required.
It is a focused Django application for navigation data, policy, resolution, composition, optional configuration caching, and lightweight reference rendering.
Custom User Models and django-allauth
User relationships use settings.AUTH_USER_MODEL.
Launchpad works with:
- Django's built-in user model
- custom
AbstractUsermodels - custom
AbstractBaseUsermodels - django-allauth with the project's configured user model
The visibility engine relies only on Django's standard authentication interface, including:
is_authenticatedis_staffis_superusergroupsget_all_permissions()
Supported Versions
| Python | Django 5.2 | Django 6.0 |
|---|---|---|
| 3.11 | Yes | No |
| 3.12 | Yes | Yes |
| 3.13 | Yes | Yes |
| 3.14 | Yes | Yes |
Package metadata currently allows:
Python >= 3.11
Django >= 5.2, < 6.1
Quality
django-launchpad is developed with the same quality standards used across
FIFOA Labs packages.
- Ruff formatting and linting
- Strict mypy validation across source and tests
django-stubs- Pytest and pytest-django
- 100% statement coverage
- 100% branch coverage
- CI across supported Python and Django combinations
- Django system checks
- Migration drift checks
- Migration application smoke testing
- Source and wheel distribution validation
- Required wheel-content validation
- Clean-wheel installation testing
- Typed distribution via
py.typed - PyPI Trusted Publishing
Project Status
django-launchpad is suitable for integration and real-world use, but its
public API remains pre-1.0 and may continue to evolve as the package is adopted
by additional Django projects.
Recent development has added:
- optional configuration caching
- request-scoped visibility reuse
- automatic transaction-safe cache invalidation
- modular reader internals
- split template-tag internals behind the same
{% load launchpad_tags %}API - optional responsive row balancing
- a generic semantic card renderer alongside the existing generic tree renderer
Semantic versioning is used:
- patch releases fix bugs and documentation and may refine existing behavior
- minor
0.xreleases may add features or refine pre-1.0 APIs 1.0.0will mark a stable public compatibility commitment
See the PyPI badge and CHANGELOG.md for the currently released version.
Contributing
Issues and pull requests are welcome.
Before submitting changes, run:
make check
make coverage
make build
make check-dist
make install-wheel
For the full local release validation pipeline:
make release-check
See CONTRIBUTING.md for project guidelines.
License
django-launchpad is released under the MIT License.
See LICENSE for the full license text.
Built and maintained by FIFOA Labs.
Metadata
Release files for django-launchpad 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_launchpad-0.2.1.tar.gz | 58.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_launchpad-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 121.7 kB
Release files / django_launchpad-0.2.1.tar.gz
| Download URL | django_launchpad-0.2.1.tar.gz |
|---|---|
| Size | 58.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b9c578657912015dadad25dc94ad968cd3d9b598d38caabf7bc4c2b63d7b84f
|
|
BLAKE2b-256 checksum How to use checksums |
64fa15f35be6ff6299ed54c5a5730f583a6ee5dec0dcb7feb02ed969ba170c17
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.
Transparency logRelease files / django_launchpad-0.2.1-py3-none-any.whl
| Download URL | django_launchpad-0.2.1-py3-none-any.whl |
|---|---|
| Size | 63.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
07f7c36f3c82d1b15368905ab6e518626a70c8912ce5930d6527dd2147a9259f
|
|
BLAKE2b-256 checksum How to use checksums |
5817224d9e17a62bc4c9d4a5137dacd88af0122f5364ee8812dfe2649acfe69d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.
Transparency log