Django DataclassConf
A simple Django package setting loader that utilizes dataclasses for type hinting and type checking.
Bring modern Python typing, robust validation, and full IDE autocomplete to your Django configurations.
django-dataclassconf allows you to bind your Django settings cleanly to structured standard Python dataclasses. Powered by dacite, it automatically catches dynamic setting updates while ensuring your configuration layer stays type-safe and isolated.
But Why?
-
Fail-Fast Validation: Catch bad configuration types or missing values instantly during server startup or container deployment rather than hitting silent runtime crashes mid-request.
-
Full IDE Autocomplete: Say goodbye to blind
getattr(settings, "MY_SETTING")calls. Enjoy full hovering type definitions and autocompletion in VS Code, PyCharm, and MyPy. -
Dual Format Normalization: Merges flat environment styles (
PREFIX_TIMEOUT = 30) and structured dictionary blocks (PREFIX = {"TIMEOUT": 30}) into a single unified object seamlessly. -
Test-Safe Isolation: Fully supports Django's test suite cycles. When settings are overridden dynamically in unit tests, your dataclasses mutate cleanly in-place and revert automatically.
Usage
1. Define Your Configuration Dataclass
Create a file named config.py (or any name you prefer tbh) within your application or package.
Inherit from BaseConfig and define your variables.
from dataclasses import dataclass
from django_dataclassconf.conf import BaseConfig, config_loader
@dataclass
class MyPackageConfig(BaseConfig):
DOCUMENTS_ROOT_PATH: str = '/the/default/path/'
MAX_FILE_SIZE: int = 10000
_prefix = 'MY_PACKAGE'
package_config = MyPackageConfig()
Note: Make sure to instantiate your config class for it to properly catch the settings and you can then access those settings via its instance.
2. Subscribe to the Configuration Loader
For your dataclass to grab configuration data from Django's settings.py on startup and capture updates during tests, subscribe your instance into config_loader inside your app's initialization hook:
# my_app/apps.py
class MyAppConfig(AppConfig):
name = 'my_app'
def ready(self):
from django_dataclassconf.conf import config_loader
from .config import package_config
config_loader.subscribe(package_config)
3. Access Your Settings Anywhere
The core practice is to import your configuration instance directly instead of using the global django.conf.settings object, to get full type safety and IDE autocomplete.
# my_app/views.py
from django.http import HttpResponse
from my_app.config import package_config
def my_view(request):
...
# Your IDE now natively autocompletes these fields
if file_size > package_config.MAX_FILE_SIZE:
return HttpResponse(
{'detail': 'File size has exceeded the maximum size limit!'},
status = 400
)
Extras
Nested Dataclasses
Your configuration dataclass can also contain nested dataclasses.
You only need to inherit BaseConfig on the root configuration dataclass.
from dataclasses import dataclass, field
from django_dataclassconf.conf import BaseConfig, config_loader
@dataclass
class DocumentPreview:
preview_page_count: int = 10
strip_cover_page: bool = False
@dataclass
class MyPackageConfig(BaseConfig):
DOCUMENTS_ROOT_PATH: str = '/the/default/path/'
PREVIEW: DocumentPreview = field(default_factory=DocumentPreview)
_prefix = 'MY_PACKAGE'
configuration = MyPackageConfig()
config_loader.subscribe(configuration)
Which maps to this in settings.py:
MY_PACKAGE = {
'DOCUMENTS_ROOT_PATH': '/custom/path/',
'PREVIEW': {
'preview_page_count': 12,
'strip_cover_page': True
},
}
Built-in Field Types
Importable
For settings that hold a dotted import path to a class, instance, or callable in another module, annotate them with Importable from fields/types.py. The import is deferred — nothing is resolved until you explicitly call .resolve().
from dataclasses import dataclass
from django_dataclassconf.fields import Importable
import typing
from .models import Segment
@dataclass
class MyConfig(BaseConfig):
SEGMENTER_FUNC: Importable[typing.Callable] = 'myapp.utils.segment_audio'
SEGMENT_SERIALIZER_CLASS: Importable[typing.Type[Serializer]] = 'myapp.serializers.SegmentSerializer'
SEGMENT_MODEL: Importable[typing.Type[Segment]] = 'myapp.Segment'
_prefix = 'MY_PACKAGE'
configuration = MyConfig()
Call .resolve() when you need the actual object. It validates the type on first call and caches the result:
# Raises ImportError if the path is invalid, or TypeError if the
# resolved object does not match the annotated type.
try:
segment_model = configuration.SEGMENT_MODEL.resolve()
except ImportError as ie:
print(f'Could not import SEGMENT_MODEL: {ie}')
except TypeError as te:
print(f'Imported value has different type than expected: {te}')
Path
For settings that hold a filesystem path, annotate them with Path from fields/types.py. The raw value may be a str or any os.PathLike; calling .resolve() validates it and returns a pathlib.Path.
from dataclasses import dataclass
from django_dataclassconf.fields import Path
@dataclass
class MyConfig(BaseConfig):
DOCUMENTS_ROOT: Path[str] = '/the/default/path/'
_prefix = 'MY_PACKAGE'
configuration = MyConfig()
Call .resolve() to get the pathlib.Path:
# Returns pathlib.Path('/the/default/path/')
root = configuration.DOCUMENTS_ROOT.resolve()
document = root / 'report.pdf'
Note:
Pathintentionally shares its name withpathlib.Path. Import it under an alias (e.g.from django_dataclassconf.fields import Path as PathField) if you also needpathlib.Pathin the same module.
Custom Field Types
Introduced in version 0.3.0.
You can define your own field types with custom validation and transformation logic by two ways.
Decorator
Introduced in version 0.5.0, a simple way to customize a field type is by using a builder function:
field_type— a decorator that automatically subclassesFieldGenericandField.create_field_type— a function that performs the same thing asfield_type.
Subclasses
Introduced in version 0.3.0, by subclassing three base classes from fields/bases.py: FieldValue, FieldGeneric, and Field.
Each custom field type requires three pieces:
FieldValuesubclass — holds the raw value, implementsvalidate()(raises on invalid input) andresolve()(returns the final value).FieldGenericsubclass — the runtime object produced byYourField[T]. Implementsinstanciate()to construct theFieldValue.Fieldsubclass — the annotation class used in dataclass definitions. Points at theFieldGenericvia_generic_class.
Simple Example: Email Field (Decorator)
The simplified way of defining your own field type is by using the field_type decorator in fields/decorators.py.
from django_dataclassconf.fields import field_type, FieldValue
import re
@field_type()
class Email(FieldValue):
def validate(self):
email_pattern = r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
if not re.match(email_pattern, self.value):
raise ValueError(f'Email value {self.value} is not a valid email address')
def __str__(self):
return self.value
def __eq__(self, value):
if isinstance(value, str):
return self.value == value
return super().__eq__(value)
# Email here serves as FieldValue subclass on static checkers but
# it is a subclass of Field during runtime
Alternatively, you may also use the builder function that the decorator uses internally which is create_field_type function located in fields/utils.py.
from django_dataclassconf.fields import FieldValue, create_field_type
import re
class EmailValue(FieldValue):
... # implementation here
Email = create_field_type(EmailValue, 'Email')
# EmailValue here stays as FieldValue subclass and
# Email is a subclass of Field
Use it in your configuration dataclass the same way as any built-in field type:
@dataclass
class MyConfig(BaseConfig):
ADMIN_EMAIL: Email[str] = 'admin@example.com'
_prefix = 'MY_APP'
Call .resolve() to get the validated value, or check .is_valid if you want a boolean without raising:
# Raises ValueError if the configured value is not a valid email address
admin_email = my_config.ADMIN_EMAIL.resolve()
# Non-raising check
if my_config.ADMIN_EMAIL.is_valid:
...
Advanced Example: Deprecated Field (Subclass)
A more controlled way to create your custom field type is by subclassing the classes FieldValue, FieldGeneric, and Field. An example will follow which is a field that emits a DeprecationWarning when validated, useful for marking settings that are still supported but scheduled for removal.
from django_dataclassconf.fields import Field, FieldGeneric, FieldValue
import warnings
import typing
class DeprecatedValue(FieldValue):
def validate(self):
if not isinstance(self.value, self.inner_type):
raise TypeError(
f'Instance {self.value} is not of type {self.inner_type.__name__}'
)
warnings.warn('This setting is deprecated', DeprecationWarning, stacklevel=2)
# The following subclasses can be customized as much as you like
class _DeprecatedGeneric(FieldGeneric):
_value_class = DeprecatedValue
def instantiate(self, value):
# you may add anything here
return super().instantiate(value)
class _DeprecatedField(Field):
_generic_class = _DeprecatedGeneric
if typing.TYPE_CHECKING:
Deprecated = DeprecatedValue
else:
Deprecated = _DeprecatedField
Note: A convention in naming your custom fields would to name
ObjValuefor subclass ofFieldValue,_ObjGenericfor subclass ofFieldGeneric, and_ObjFieldfor subclass ofField. When using the decoratorfield_type, you may name yourFieldValuesubclass without the..Valuesuffix. When using the builder functioncreate_field_type, add the..Valuesuffix on the subclass ofFieldValue.
License
This project is licensed under the MIT License — see the LICENSE file for details.
Metadata
Release files for django-dataclassconf 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| django_dataclassconf-0.5.0.tar.gz | 17.2 kB | With provenance | Details for django_dataclassconf-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| django_dataclassconf-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for django_dataclassconf-0.5.0-py3-none-any.whl |
Total release size: 33.0 kB
Release files / django_dataclassconf-0.5.0.tar.gz
| Download URL | django_dataclassconf-0.5.0.tar.gz |
|---|---|
| Size | 17.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
da6a116e3946da6ec9f950a08e32d74a742788847a6f38400392b1b36ebc9370
|
|
BLAKE2b-256 checksum How to use checksums |
9a26dba39f90ead44c33f7d63bf29baae28d92c6ff669a497df7d80b272401ac
|
| 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 Sep 6, 2026.
Transparency logRelease files / django_dataclassconf-0.5.0-py3-none-any.whl
| Download URL | django_dataclassconf-0.5.0-py3-none-any.whl |
|---|---|
| Size | 15.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5612b19884985c4cb9db64becbdbb19c2ee8272a56581e02bed507811df91fdc
|
|
BLAKE2b-256 checksum How to use checksums |
209f4c6ca1a9ee3bd1612973451b4c7f60c58b87fd385307009ada310eec42c9
|
| 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 Sep 6, 2026.
Transparency logSecurity for django-dataclassconf 0.5.0
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.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for django_dataclassconf-0.5.0.tar.gz
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 Sep 6, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.