# pydjantic
[![Build Status](https://github.com/ErhoSen/pydjantic/actions/workflows/main.yml/badge.svg)](https://github.com/ErhoSen/pydjantic/actions)
[![codecov](https://codecov.io/gh/ErhoSen/pydjantic/branch/master/graph/badge.svg?token=BW5A0V3CR3)](https://codecov.io/gh/ErhoSen/pydjantic)
[![pypi](https://img.shields.io/pypi/v/pydjantic.svg)](https://pypi.org/project/pydjantic/)
[![versions](https://img.shields.io/pypi/pyversions/pydjantic.svg)](https://github.com/erhosen-libs/pydjantic)
[![license](https://img.shields.io/github/license/erhosen/pydjantic.svg)](https://github.com/erhosen-libs/pydjantic/blob/master/LICENSE)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
Use Pydantic Settings in your Django application.
![Pydjantc django settings](https://github.com/erhosen-libs/pydjantic/raw/master/images/pydjantic.png "Pydjantc django settings")
## Introduction
If you are tired of the mess in your Django Settings - I feel your pain:
* Ridiculously long `settings.py` file, with ASCII-art separation
* `from common import *` Python [anti-pattern](https://www.geeksforgeeks.org/why-import-star-in-python-is-a-bad-idea/)
* `try: <import> except: ImportError` Python [anti-pattern](https://stackoverflow.com/questions/14050281/how-to-check-if-a-python-module-exists-without-importing-it)
* `base.py`, `production.py`, `local.py`, `domain.py` - bunch of unrelated modules that override each other
* [django-environ](https://github.com/joke2k/django-environ) library, that do even worse...
On the other hand we have [Pydantic Settings](https://pydantic-docs.helpmanual.io/usage/settings/),
which is de-facto standard for all non-django projects.
If you love Pydantic settings management approach, **Pydjantic** is a right tool for you.
**Pydjantic** allows you to define your settings in familiar way - just inherit from `BaseSettings`:
```py
from typing import List
from pydantic import BaseSettings, Field
from pydantic.fields import Undefined
from pydjantic import to_django
class GeneralSettings(BaseSettings):
SECRET_KEY: str = Field(default=Undefined, env='DJANGO_SECRET_KEY')
DEBUG: bool = Field(default=False, env='DEBUG')
INSTALLED_APPS: List[str] = [
'django.contrib.admin',
'django.contrib.auth',
]
LANGUAGE_CODE: str = 'en-us'
USE_TZ: bool = True
class StaticSettings(BaseSettings):
STATIC_URL: str = '/static/'
STATIC_ROOT: str = 'staticfiles'
class SentrySettings(BaseSettings):
SENTRY_DSN: str = Field(default=Undefined, env='SENTRY_DSN')
class ProjectSettings(GeneralSettings, StaticSettings, SentrySettings):
pass
to_django(ProjectSettings())
```
You can create as many classes/modules as you want, to achieve perfect settings' management.
Divide your settings by domains, and then create final `ProjectSettings` class, that inherits from these domains.
Provide the instance of `ProjectSettings` to `to_django` function.
That's all, your django settings will work as expected.
## Installation
Install using `pip install -U pydjantic` or `poetry add pydjantic`.
## Example
In the `/demo` directory you can find a [working Django app](https://github.com/erhosen-libs/pydjantic/tree/master/demo) with [pydjantic settings](https://github.com/erhosen-libs/pydjantic/blob/master/demo/demo/settings.py).
## Database configuration
**Pydjantic** comes with a special helper for managing DB configs - `BaseDBConfig`. See example below:
```python
from pydantic import Field, PostgresDsn
from pydjantic import BaseDBConfig
class DatabaseConfig(BaseDBConfig):
default: PostgresDsn = Field(default="postgres://user:password@hostname:5432/dbname", env="DATABASE_URL")
db_settings = DatabaseConfig()
assert db_settings.default == {
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'HOST': 'hostname',
'NAME': 'dbname',
'PASSWORD': 'password',
'PORT': 5432,
'USER': 'user',
}
```
Also, you can define database configurations directly:
```python
from pydantic import BaseSettings, Field
class PostgresDB(BaseSettings):
ENGINE: str = 'django.db.backends.postgresql_psycopg2'
HOST: str = Field(default='localhost', env='DATABASE_HOST')
NAME: str = Field(default='dbname', env='DATABASE_NAME')
PASSWORD: str = Field(default='password', env='DATABASE_PASSWORD')
PORT: int = Field(default=5432, env='DATABASE_PORT')
USER: str = Field(default='user', env='DATABASE_USER')
OPTIONS: dict = Field(default={}, env='DATABASE_OPTIONS')
CONN_MAX_AGE: int = Field(default=0, env='DATABASE_CONN_MAX_AGE')
class DatabaseConfig(BaseSettings):
default = PostgresDB()
```
Or mix these approaches:
```python
class DatabaseConfig(BaseDBConfig):
default = Field(default="postgres://user:password@hostname:5432/dbname")
replica = PostgresDB()
```
For more examples see [tests](tests/test_db_config.py).
Transformation from dsn to django format is done by [dj-database-url](https://pypi.org/project/dj-database-url/) library.
Raw data
{
"_id": null,
"home_page": "https://github.com/ErhoSen/pydjantic",
"name": "pydjantic",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": "pydantic, django, PydanticSettings, settings",
"author": "Vladimir Vyazovetskov",
"author_email": "erhosen@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/75/48/02dee566b03d11c650a1d7332d29f72f992ee3d8f0221802c535ad8e070e/pydjantic-1.1.5.tar.gz",
"platform": null,
"description": "# pydjantic\n[![Build Status](https://github.com/ErhoSen/pydjantic/actions/workflows/main.yml/badge.svg)](https://github.com/ErhoSen/pydjantic/actions)\n[![codecov](https://codecov.io/gh/ErhoSen/pydjantic/branch/master/graph/badge.svg?token=BW5A0V3CR3)](https://codecov.io/gh/ErhoSen/pydjantic)\n[![pypi](https://img.shields.io/pypi/v/pydjantic.svg)](https://pypi.org/project/pydjantic/)\n[![versions](https://img.shields.io/pypi/pyversions/pydjantic.svg)](https://github.com/erhosen-libs/pydjantic)\n[![license](https://img.shields.io/github/license/erhosen/pydjantic.svg)](https://github.com/erhosen-libs/pydjantic/blob/master/LICENSE)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n\nUse Pydantic Settings in your Django application.\n\n![Pydjantc django settings](https://github.com/erhosen-libs/pydjantic/raw/master/images/pydjantic.png \"Pydjantc django settings\")\n\n## Introduction\n\nIf you are tired of the mess in your Django Settings - I feel your pain:\n* Ridiculously long `settings.py` file, with ASCII-art separation\n* `from common import *` Python [anti-pattern](https://www.geeksforgeeks.org/why-import-star-in-python-is-a-bad-idea/)\n* `try: <import> except: ImportError` Python [anti-pattern](https://stackoverflow.com/questions/14050281/how-to-check-if-a-python-module-exists-without-importing-it)\n* `base.py`, `production.py`, `local.py`, `domain.py` - bunch of unrelated modules that override each other\n* [django-environ](https://github.com/joke2k/django-environ) library, that do even worse...\n\nOn the other hand we have [Pydantic Settings](https://pydantic-docs.helpmanual.io/usage/settings/),\nwhich is de-facto standard for all non-django projects.\n\nIf you love Pydantic settings management approach, **Pydjantic** is a right tool for you.\n\n**Pydjantic** allows you to define your settings in familiar way - just inherit from `BaseSettings`:\n```py\nfrom typing import List\n\nfrom pydantic import BaseSettings, Field\nfrom pydantic.fields import Undefined\nfrom pydjantic import to_django\n\nclass GeneralSettings(BaseSettings):\n SECRET_KEY: str = Field(default=Undefined, env='DJANGO_SECRET_KEY')\n DEBUG: bool = Field(default=False, env='DEBUG')\n INSTALLED_APPS: List[str] = [\n 'django.contrib.admin',\n 'django.contrib.auth',\n ]\n LANGUAGE_CODE: str = 'en-us'\n USE_TZ: bool = True\n\n\nclass StaticSettings(BaseSettings):\n STATIC_URL: str = '/static/'\n STATIC_ROOT: str = 'staticfiles'\n\n\nclass SentrySettings(BaseSettings):\n SENTRY_DSN: str = Field(default=Undefined, env='SENTRY_DSN')\n\n\nclass ProjectSettings(GeneralSettings, StaticSettings, SentrySettings):\n pass\n\n\nto_django(ProjectSettings())\n```\nYou can create as many classes/modules as you want, to achieve perfect settings' management.\nDivide your settings by domains, and then create final `ProjectSettings` class, that inherits from these domains.\n\nProvide the instance of `ProjectSettings` to `to_django` function.\nThat's all, your django settings will work as expected.\n\n## Installation\n\nInstall using `pip install -U pydjantic` or `poetry add pydjantic`.\n\n## Example\nIn the `/demo` directory you can find a [working Django app](https://github.com/erhosen-libs/pydjantic/tree/master/demo) with [pydjantic settings](https://github.com/erhosen-libs/pydjantic/blob/master/demo/demo/settings.py).\n\n## Database configuration\n\n**Pydjantic** comes with a special helper for managing DB configs - `BaseDBConfig`. See example below:\n```python\nfrom pydantic import Field, PostgresDsn\nfrom pydjantic import BaseDBConfig\n\n\nclass DatabaseConfig(BaseDBConfig):\n default: PostgresDsn = Field(default=\"postgres://user:password@hostname:5432/dbname\", env=\"DATABASE_URL\")\n\ndb_settings = DatabaseConfig()\nassert db_settings.default == {\n 'CONN_MAX_AGE': 0,\n 'ENGINE': 'django.db.backends.postgresql_psycopg2',\n 'HOST': 'hostname',\n 'NAME': 'dbname',\n 'PASSWORD': 'password',\n 'PORT': 5432,\n 'USER': 'user',\n}\n```\n\nAlso, you can define database configurations directly:\n```python\nfrom pydantic import BaseSettings, Field\n\nclass PostgresDB(BaseSettings):\n ENGINE: str = 'django.db.backends.postgresql_psycopg2'\n HOST: str = Field(default='localhost', env='DATABASE_HOST')\n NAME: str = Field(default='dbname', env='DATABASE_NAME')\n PASSWORD: str = Field(default='password', env='DATABASE_PASSWORD')\n PORT: int = Field(default=5432, env='DATABASE_PORT')\n USER: str = Field(default='user', env='DATABASE_USER')\n OPTIONS: dict = Field(default={}, env='DATABASE_OPTIONS')\n CONN_MAX_AGE: int = Field(default=0, env='DATABASE_CONN_MAX_AGE')\n\nclass DatabaseConfig(BaseSettings):\n default = PostgresDB()\n```\n\nOr mix these approaches:\n```python\nclass DatabaseConfig(BaseDBConfig):\n default = Field(default=\"postgres://user:password@hostname:5432/dbname\")\n replica = PostgresDB()\n```\n\nFor more examples see [tests](tests/test_db_config.py).\n\nTransformation from dsn to django format is done by [dj-database-url](https://pypi.org/project/dj-database-url/) library.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Pydantic Settings for Django",
"version": "1.1.5",
"project_urls": {
"Homepage": "https://github.com/ErhoSen/pydjantic",
"Repository": "https://github.com/ErhoSen/pydjantic"
},
"split_keywords": [
"pydantic",
" django",
" pydanticsettings",
" settings"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d8686389063f3d61284603882a62f0fe8c92f007d18845cb3b6c2ed2a45465bc",
"md5": "f9b5d241d75ecf01bccce56635353bfa",
"sha256": "1a9aea29442dff1a203d53deec560fe24e26ed2162988b6fc5f21cb849e8a16d"
},
"downloads": -1,
"filename": "pydjantic-1.1.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "f9b5d241d75ecf01bccce56635353bfa",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 6036,
"upload_time": "2024-05-24T20:19:28",
"upload_time_iso_8601": "2024-05-24T20:19:28.383327Z",
"url": "https://files.pythonhosted.org/packages/d8/68/6389063f3d61284603882a62f0fe8c92f007d18845cb3b6c2ed2a45465bc/pydjantic-1.1.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "754802dee566b03d11c650a1d7332d29f72f992ee3d8f0221802c535ad8e070e",
"md5": "a4cd8cb1205a697059c70b1e774e0bb3",
"sha256": "28cfb365d48426cb911061fc8fb8b0dee69c1aa410a72c8d6ff8051d19ad0b2c"
},
"downloads": -1,
"filename": "pydjantic-1.1.5.tar.gz",
"has_sig": false,
"md5_digest": "a4cd8cb1205a697059c70b1e774e0bb3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 4632,
"upload_time": "2024-05-24T20:19:29",
"upload_time_iso_8601": "2024-05-24T20:19:29.715126Z",
"url": "https://files.pythonhosted.org/packages/75/48/02dee566b03d11c650a1d7332d29f72f992ee3d8f0221802c535ad8e070e/pydjantic-1.1.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-24 20:19:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ErhoSen",
"github_project": "pydjantic",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pydjantic"
}