django-structured-json-field


Namedjango-structured-json-field JSON
Version 0.4.0 PyPI version JSON
download
home_pageNone
SummaryDjango json field empowered by pydantic
upload_time2024-11-26 09:37:50
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords django pydantic django pydantic django json json schema django form
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Django Structured JSON Field [![PyPI](https://img.shields.io/pypi/v/django-structured-json-field?style=flat-square)](https://pypi.org/project/django-structured-json-field) ![Codecov](https://img.shields.io/codecov/c/github/bnznamco/django-structured-field?style=flat-square&logo=codecov&logoSize=auto&cacheSeconds=0) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/lotrekagency/django-structured-field/ci.yml?style=flat-square) [![GitHub](https://img.shields.io/github/license/lotrekagency/django-structured-field?style=flat-square)](./LICENSE)

This is a Django field that allows you to declare the structure of a JSON field and validate it.

## Features

- Define the structure of a JSON field using Pydantic models
- Validate the JSON field against the defined structure
- Use relationships between models inside the JSON field 🤯
- Easily integrate with Django Rest Framework serializers
- Admin editor for the JSON field with autocomplete search for related models 👀

## Installation

```bash
pip install django-structured-json-field
```

## Usage

```python
from django.db import models
from structured.fields import StructuredJSONField
from structured.pydantic.models import BaseModel

# Define this schema as you would do with a Pydantic model
class MySchema(BaseModel):
    name: str
    age: int = None

def init_data():
    return MySchema(name='')

# Create a model with a StructuredJSONField with the schema you defined
class MyModel(models.Model):
    structured_data = StructuredJSONField(schema=MySchema, default=init_data)

```

## Relationships

This field supports relationships between models, you can define them in your schema and they will be treated as normal django relationships. It also supports recursive schemas.

### Recursion

You can define recursive schemas by declaring the attribute type as a string:

```python
from typing import Optional, List

class MySchema(BaseModel):
    name: str
    age: int = None
    parent: Optional['MySchema'] = None
    relateds: List['MySchema'] = []
```

### Foreign Keys

You can also define model relationships in your schema:

```python
from structured.pydantic.fields import ForeignKey

class MySchema(BaseModel):
    name: str
    age: int = None
    fk_field: ForeignKey['MyModel'] = None
```

This will treat the parent field as a normal django ForeignKey.

#### Tip:

You can omit the `ForeignKey` field and just use the model class as the type annotation:

```python
class MySchema(BaseModel):
    name: str
    age: int = None
    fk_field: MyModel = None
```

the field will still be treated as a ForeignKey if the type annotation is a subclass of django `models.Model`.

### ManyToMany

If you need a ManyToMany relationship, you can use the `QuerySet` field:

```python
from structured.pydantic.fields import QuerySet

class MySchema(BaseModel):
    name: str
    age: int = None
    parents: QuerySet['MyModel']
```

`QuerySet` fields will generate a django object manager that will allow you to query the related objects as you would do with a normal django `QuerySet`.

```python
instance = MySchema(name='test', age=10, parents=MyModel.objects.all())
# You can filter the queryset
instance.parents.filter(name='test')
# You can count the queryset
instance.parents.count()
# You can get the first element of the queryset, etc...
instance.parents.first()
```

### Admin integration

The field is integrated with the Django admin, you can use the autocomplete search to select the related models. To allow the autocomplete search you need to include structured.urls in your urls.py file:

```python
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('structured.urls')),
]
```

### Rest Framework integration

You can easily integrate structured fields with Django Rest Framework serializers, just use the `StructuredModelSerializer` as the base class for your serializer:

```python
from rest_framework import serializers
from structured.contrib.rest_framework import StructuredModelSerializer

class MyModelSerializer(StructuredModelSerializer):
    class Meta:
        model = MyModel
        fields = '__all__'
```

Errors generated by pydantic validation will be automatically translated to DRF errors.


### Cache

To prevent the field from making multiple identical queries a caching technique is used. The cache is still a work in progress, please open an issue if you find any problem.
Actually the cache covers all the relations inside a StructuredJSONField, optimizing the queries during the serialization process.

#### Cache engine progress:

- [x] Shared cache between `ForeignKey` fields and `QuerySet` fields
- [x] Shared cache through nested schemas
- [x] Shared cache through nested lists of schemas
- [ ] Shared cache between all `StructuredJSONFields` in the same instance
- [ ] Shared cache between multiple instances of the same model
- [ ] Cache invalidation mechanism

## Settings

You can manage structured field behaviour modifying the `STRUCTURED_FIELD` setting in your `settings.py` file. Here a list of the available settings and their default values:

```python
STRUCTURED_FIELD = {
    'CACHE':{
        'ENABLED': True,
        'SHARED': False # ⚠️ EXPERIMENTAL: this enables a thread-shared cache, it's not recommended to use it in production.
    },
}
```

## Contributing

The project is open to contributions, just open an issue or a PR.

### Running tests

```bash
pip install -r requirements-dev.txt
make test
```

### Running test app

```bash
pip install -r requirements-dev.txt
python manage.py migrate
python manage.py runserver
```

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "django-structured-json-field",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "django, pydantic, django pydantic, django json, json schema, django form",
    "author": null,
    "author_email": "Lotr\u00e8k <gabriele@lotrek.it>",
    "download_url": "https://files.pythonhosted.org/packages/86/e6/e3149513ece019a76506a29fbb6dbbbb13afab7fa4413b3a05c7bc3fd1b9/django_structured_json_field-0.4.0.tar.gz",
    "platform": null,
    "description": "# Django Structured JSON Field [![PyPI](https://img.shields.io/pypi/v/django-structured-json-field?style=flat-square)](https://pypi.org/project/django-structured-json-field) ![Codecov](https://img.shields.io/codecov/c/github/bnznamco/django-structured-field?style=flat-square&logo=codecov&logoSize=auto&cacheSeconds=0) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/lotrekagency/django-structured-field/ci.yml?style=flat-square) [![GitHub](https://img.shields.io/github/license/lotrekagency/django-structured-field?style=flat-square)](./LICENSE)\n\nThis is a Django field that allows you to declare the structure of a JSON field and validate it.\n\n## Features\n\n- Define the structure of a JSON field using Pydantic models\n- Validate the JSON field against the defined structure\n- Use relationships between models inside the JSON field \ud83e\udd2f\n- Easily integrate with Django Rest Framework serializers\n- Admin editor for the JSON field with autocomplete search for related models \ud83d\udc40\n\n## Installation\n\n```bash\npip install django-structured-json-field\n```\n\n## Usage\n\n```python\nfrom django.db import models\nfrom structured.fields import StructuredJSONField\nfrom structured.pydantic.models import BaseModel\n\n# Define this schema as you would do with a Pydantic model\nclass MySchema(BaseModel):\n    name: str\n    age: int = None\n\ndef init_data():\n    return MySchema(name='')\n\n# Create a model with a StructuredJSONField with the schema you defined\nclass MyModel(models.Model):\n    structured_data = StructuredJSONField(schema=MySchema, default=init_data)\n\n```\n\n## Relationships\n\nThis field supports relationships between models, you can define them in your schema and they will be treated as normal django relationships. It also supports recursive schemas.\n\n### Recursion\n\nYou can define recursive schemas by declaring the attribute type as a string:\n\n```python\nfrom typing import Optional, List\n\nclass MySchema(BaseModel):\n    name: str\n    age: int = None\n    parent: Optional['MySchema'] = None\n    relateds: List['MySchema'] = []\n```\n\n### Foreign Keys\n\nYou can also define model relationships in your schema:\n\n```python\nfrom structured.pydantic.fields import ForeignKey\n\nclass MySchema(BaseModel):\n    name: str\n    age: int = None\n    fk_field: ForeignKey['MyModel'] = None\n```\n\nThis will treat the parent field as a normal django ForeignKey.\n\n#### Tip:\n\nYou can omit the `ForeignKey` field and just use the model class as the type annotation:\n\n```python\nclass MySchema(BaseModel):\n    name: str\n    age: int = None\n    fk_field: MyModel = None\n```\n\nthe field will still be treated as a ForeignKey if the type annotation is a subclass of django `models.Model`.\n\n### ManyToMany\n\nIf you need a ManyToMany relationship, you can use the `QuerySet` field:\n\n```python\nfrom structured.pydantic.fields import QuerySet\n\nclass MySchema(BaseModel):\n    name: str\n    age: int = None\n    parents: QuerySet['MyModel']\n```\n\n`QuerySet` fields will generate a django object manager that will allow you to query the related objects as you would do with a normal django `QuerySet`.\n\n```python\ninstance = MySchema(name='test', age=10, parents=MyModel.objects.all())\n# You can filter the queryset\ninstance.parents.filter(name='test')\n# You can count the queryset\ninstance.parents.count()\n# You can get the first element of the queryset, etc...\ninstance.parents.first()\n```\n\n### Admin integration\n\nThe field is integrated with the Django admin, you can use the autocomplete search to select the related models. To allow the autocomplete search you need to include structured.urls in your urls.py file:\n\n```python\nfrom django.urls import path, include\n\nurlpatterns = [\n    path('admin/', admin.site.urls),\n    path('', include('structured.urls')),\n]\n```\n\n### Rest Framework integration\n\nYou can easily integrate structured fields with Django Rest Framework serializers, just use the `StructuredModelSerializer` as the base class for your serializer:\n\n```python\nfrom rest_framework import serializers\nfrom structured.contrib.rest_framework import StructuredModelSerializer\n\nclass MyModelSerializer(StructuredModelSerializer):\n    class Meta:\n        model = MyModel\n        fields = '__all__'\n```\n\nErrors generated by pydantic validation will be automatically translated to DRF errors.\n\n\n### Cache\n\nTo prevent the field from making multiple identical queries a caching technique is used. The cache is still a work in progress, please open an issue if you find any problem.\nActually the cache covers all the relations inside a StructuredJSONField, optimizing the queries during the serialization process.\n\n#### Cache engine progress:\n\n- [x] Shared cache between `ForeignKey` fields and `QuerySet` fields\n- [x] Shared cache through nested schemas\n- [x] Shared cache through nested lists of schemas\n- [ ] Shared cache between all `StructuredJSONFields` in the same instance\n- [ ] Shared cache between multiple instances of the same model\n- [ ] Cache invalidation mechanism\n\n## Settings\n\nYou can manage structured field behaviour modifying the `STRUCTURED_FIELD` setting in your `settings.py` file. Here a list of the available settings and their default values:\n\n```python\nSTRUCTURED_FIELD = {\n    'CACHE':{\n        'ENABLED': True,\n        'SHARED': False # \u26a0\ufe0f EXPERIMENTAL: this enables a thread-shared cache, it's not recommended to use it in production.\n    },\n}\n```\n\n## Contributing\n\nThe project is open to contributions, just open an issue or a PR.\n\n### Running tests\n\n```bash\npip install -r requirements-dev.txt\nmake test\n```\n\n### Running test app\n\n```bash\npip install -r requirements-dev.txt\npython manage.py migrate\npython manage.py runserver\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Django json field empowered by pydantic",
    "version": "0.4.0",
    "project_urls": {
        "Homepage": "https://github.com/lotrekagency/django-structured-json-field"
    },
    "split_keywords": [
        "django",
        " pydantic",
        " django pydantic",
        " django json",
        " json schema",
        " django form"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "25ad37dbb3b8f523e20ae828b3d3d0b1a3e8264b1ab794d03733961151b06dd2",
                "md5": "26b92c777de9b1e73648340a1768dc28",
                "sha256": "14068b60bd5c17d3fb3d84aade3bb604fedebc5c3a1b6c64ee9b22a8c46a2435"
            },
            "downloads": -1,
            "filename": "django_structured_json_field-0.4.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "26b92c777de9b1e73648340a1768dc28",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.8",
            "size": 1955342,
            "upload_time": "2024-11-26T09:37:49",
            "upload_time_iso_8601": "2024-11-26T09:37:49.233882Z",
            "url": "https://files.pythonhosted.org/packages/25/ad/37dbb3b8f523e20ae828b3d3d0b1a3e8264b1ab794d03733961151b06dd2/django_structured_json_field-0.4.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "86e6e3149513ece019a76506a29fbb6dbbbb13afab7fa4413b3a05c7bc3fd1b9",
                "md5": "aa322419a31ab24bf66e1bd0e6f8cd97",
                "sha256": "0fdcd74ff749afa1a58d44f8639f131a017f94c6ef69df3095f96b5359a5fc68"
            },
            "downloads": -1,
            "filename": "django_structured_json_field-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "aa322419a31ab24bf66e1bd0e6f8cd97",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 1936495,
            "upload_time": "2024-11-26T09:37:50",
            "upload_time_iso_8601": "2024-11-26T09:37:50.858871Z",
            "url": "https://files.pythonhosted.org/packages/86/e6/e3149513ece019a76506a29fbb6dbbbb13afab7fa4413b3a05c7bc3fd1b9/django_structured_json_field-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-26 09:37:50",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lotrekagency",
    "github_project": "django-structured-json-field",
    "github_not_found": true,
    "lcname": "django-structured-json-field"
}
        
Elapsed time: 0.35958s