{"id":13625914,"url":"https://github.com/beda-software/drf-writable-nested","last_synced_at":"2025-05-13T16:12:01.835Z","repository":{"id":38421922,"uuid":"82379726","full_name":"beda-software/drf-writable-nested","owner":"beda-software","description":"Writable nested model serializer for Django REST Framework","archived":false,"fork":false,"pushed_at":"2025-03-10T19:55:42.000Z","size":256,"stargazers_count":1110,"open_issues_count":67,"forks_count":119,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-04-19T19:35:51.250Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beda-software.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-18T10:41:03.000Z","updated_at":"2025-04-15T05:35:28.000Z","dependencies_parsed_at":"2024-04-18T17:58:00.354Z","dependency_job_id":"08837755-337b-4455-baf0-8da186c89608","html_url":"https://github.com/beda-software/drf-writable-nested","commit_stats":{"total_commits":194,"total_committers":28,"mean_commits":6.928571428571429,"dds":0.5876288659793815,"last_synced_commit":"b511c6d6a75fc4a40da5f36f1a54a7935d30cce1"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Fdrf-writable-nested","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Fdrf-writable-nested/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Fdrf-writable-nested/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Fdrf-writable-nested/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beda-software","download_url":"https://codeload.github.com/beda-software/drf-writable-nested/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249799065,"owners_count":21326941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T21:02:05.349Z","updated_at":"2025-04-23T21:04:07.968Z","avatar_url":"https://github.com/beda-software.png","language":"Python","funding_links":[],"categories":["Python","Packages"],"sub_categories":["Serialization"],"readme":"DRF Writable Nested\n====================\n![build](https://github.com/beda-software/drf-writable-nested/actions/workflows/build.yaml/badge.svg)\n[![codecov](https://codecov.io/gh/beda-software/drf-writable-nested/branch/master/badge.svg?token=W0po6jnd66)](https://codecov.io/gh/beda-software/drf-writable-nested)\n[![pypi](https://img.shields.io/pypi/v/drf-writable-nested.svg)](https://pypi.python.org/pypi/drf-writable-nested)\n[![pyversions](https://img.shields.io/pypi/pyversions/drf-writable-nested.svg)](https://pypi.python.org/pypi/drf-writable-nested)\n\nThis is a writable nested model serializer for Django REST Framework which\nallows you to create/update your models with related nested data.\n\nThe following relations are supported:\n- OneToOne (direct/reverse)\n- ForeignKey (direct/reverse)\n- ManyToMany (direct/reverse excluding m2m relations with through model)\n- GenericRelation (this is always only reverse)\n\nRequirements\n============\n\n- Python (3.9, 3.10, 3.11, 3.12, 3.13)\n- Django (4.2, 5.0, 5.1, 5.2)\n- djangorestframework (3.14+)\n\nInstallation\n============\n\n```\npip install drf-writable-nested\n```\n\nUsage\n=====\n\nFor example, for the following model structure:\n```python\nfrom django.db import models\n\n\nclass Site(models.Model):\n    url = models.CharField(max_length=100)\n\n\nclass User(models.Model):\n    username = models.CharField(max_length=100)\n\n\nclass AccessKey(models.Model):\n    key = models.CharField(max_length=100)\n\n\nclass Profile(models.Model):\n    sites = models.ManyToManyField(Site)\n    user = models.OneToOneField(User, on_delete=models.CASCADE)\n    access_key = models.ForeignKey(AccessKey, null=True, on_delete=models.CASCADE)\n\n\nclass Avatar(models.Model):\n    image = models.CharField(max_length=100)\n    profile = models.ForeignKey(Profile, related_name='avatars', on_delete=models.CASCADE)\n```\n\nWe should create the following list of serializers:\n\n```python\nfrom rest_framework import serializers\nfrom drf_writable_nested.serializers import WritableNestedModelSerializer\n\n\nclass AvatarSerializer(serializers.ModelSerializer):\n    image = serializers.CharField()\n\n    class Meta:\n        model = Avatar\n        fields = ('pk', 'image',)\n\n\nclass SiteSerializer(serializers.ModelSerializer):\n    url = serializers.CharField()\n\n    class Meta:\n        model = Site\n        fields = ('pk', 'url',)\n\n\nclass AccessKeySerializer(serializers.ModelSerializer):\n\n    class Meta:\n        model = AccessKey\n        fields = ('pk', 'key',)\n\n\nclass ProfileSerializer(WritableNestedModelSerializer):\n    # Direct ManyToMany relation\n    sites = SiteSerializer(many=True)\n\n    # Reverse FK relation\n    avatars = AvatarSerializer(many=True)\n\n    # Direct FK relation\n    access_key = AccessKeySerializer(allow_null=True)\n\n    class Meta:\n        model = Profile\n        fields = ('pk', 'sites', 'avatars', 'access_key',)\n\n\nclass UserSerializer(WritableNestedModelSerializer):\n    # Reverse OneToOne relation\n    profile = ProfileSerializer()\n\n    class Meta:\n        model = User\n        fields = ('pk', 'profile', 'username',)\n```\n\nAlso, you can use `NestedCreateMixin` or `NestedUpdateMixin` from this package\nif you want to support only create or update logic.\n\nFor example, we can pass the following data with related nested fields to our\nmain serializer:\n\n```python\ndata = {\n    'username': 'test',\n    'profile': {\n        'access_key': {\n            'key': 'key',\n        },\n        'sites': [\n            {\n                'url': 'http://google.com',\n            },\n            {\n                'url': 'http://yahoo.com',\n            },\n        ],\n        'avatars': [\n            {\n                'image': 'image-1.png',\n            },\n            {\n                'image': 'image-2.png',\n            },\n        ],\n    },\n}\n\nuser_serializer = UserSerializer(data=data)\nuser_serializer.is_valid(raise_exception=True)\nuser = user_serializer.save()\n```\n\nThis serializer will automatically create all nested relations and we receive a\ncomplete instance with filled data.\n```python\nuser_serializer = UserSerializer(instance=user)\nprint(user_serializer.data)\n```\n\n```python\n{\n    'pk': 1,\n    'username': 'test',\n    'profile': {\n        'pk': 1,\n        'access_key': {\n            'pk': 1,\n            'key': 'key'\n        },\n        'sites': [\n            {\n                'pk': 1,\n                'url': 'http://google.com',\n            },\n            {\n                'pk': 2,\n                'url': 'http://yahoo.com',\n            },\n        ],\n        'avatars': [\n            {\n                'pk': 1,\n                'image': 'image-1.png',\n            },\n            {\n                'pk': 2,\n                'image': 'image-2.png',\n            },\n        ],\n    },\n}\n```\n\nIt is also possible to pass through values to nested serializers from the call\nto the base serializer's `save` method. These `kwargs` must be of type `dict`. E g:\n\n```python\n# user_serializer created with 'data' as above\nuser = user_serializer.save(\n    profile={\n        'access_key': {'key': 'key2'},\n    },\n)\nprint(user.profile.access_key.key)\n```\n\n```python\n'key2'\n```\n\nNote: The same value will be used for all nested instances like default value but with higher priority.\n\n\nTesting\n=======\nTo run unit tests, run:\n```bash\n# Setup the virtual environment\npython3 -m venv envname\nsource envname/bin/activate\n\npip install django\npip install django-rest-framework\npip install -r requirements.txt\n\n# Run tests\npy.test\n```\n\n\nKnown problems with solutions\n=============================\n\n\n##### Validation problem for nested serializers with unique fields on update\nWe have a special mixin `UniqueFieldsMixin` which solves this problem.\nThe mixin moves` UniqueValidator`'s from the validation stage to the save stage.\n\nIf you want more details, you can read related issues and articles:\nhttps://github.com/beda-software/drf-writable-nested/issues/1\nhttp://www.django-rest-framework.org/api-guide/validators/#updating-nested-serializers\n\n###### Example of usage:\n```python\nclass Child(models.Model):\n    field = models.CharField(unique=True)\n\n\nclass Parent(models.Model):\n    child = models.ForeignKey('Child')\n\n\nclass ChildSerializer(UniqueFieldsMixin, serializers.ModelSerializer):\n    class Meta:\n        model = Child\n\n\nclass ParentSerializer(NestedUpdateMixin, serializers.ModelSerializer):\n    child = ChildSerializer()\n\n    class Meta:\n        model = Parent\n```\n\nNote: `UniqueFieldsMixin` must be applied only on serializer\nwhich has unique fields.\n\n###### Mixin ordering\nWhen you are using both mixins\n(`UniqueFieldsMixin` and `NestedCreateMixin` or `NestedUpdateMixin`)\nyou should put `UniqueFieldsMixin` ahead.\n\nFor example:\n```python\nclass ChildSerializer(UniqueFieldsMixin, NestedUpdateMixin,\n        serializers.ModelSerializer):\n```\n\n##### Update problem for nested fields with form-data in `PATCH` and `PUT` methods\nThere is a special problem while we try to update any model object with nested fields\nwithin it via `PUT` or `PATCH` using form-data we can not update it. And it complains\nabout fields not provided. So far, we came to know that this is also a problem in DRF.\nBut we can follow a tricky way to solve it at least for now.\nSee the below solution about the problem\n\nIf you want more details, you can read related issues and articles:\nhttps://github.com/beda-software/drf-writable-nested/issues/106\nhttps://github.com/encode/django-rest-framework/issues/7262#issuecomment-737364846\n\n###### Example:\n```python\n\n# Models\nclass Voucher(models.Model):\n    voucher_number = models.CharField(verbose_name=\"voucher number\", max_length=10, default='')\n    image = models.ImageField(upload_to=\"vouchers/images/\", null=True, blank=True)\n\nclass VoucherRow(models.Model):\n    voucher = models.ForeignKey(to='voucher.Voucher', on_delete=models.PROTECT, verbose_name='voucher',\n                                related_name='voucherrows', null=True)\n    account = models.CharField(verbose_name=\"fortnox account number\", max_length=255)\n    debit = models.DecimalField(verbose_name=\"amount\", decimal_places=2, default=0.00, max_digits=12)\n    credit = models.DecimalField(verbose_name=\"amount\", decimal_places=2, default=0.00, max_digits=12)\n    description = models.CharField(verbose_name=\"description\", max_length=100, null=True, blank=True)\n\n# Serializers for these models\nclass VoucherRowSerializer(WritableNestedModelSerializer):\n    class Meta:\n        model = VoucherRow\n        fields = ('id', 'account', 'debit', 'credit', 'description',)\n\n\nclass VoucherSerializer(serializers.ModelSerializer):\n    voucherrows = VoucherRowSerializer(many=True, required=False, read_only=True)\n    class Meta:\n        model = Voucher\n        fields = ('id', 'participants', 'voucher_number', 'voucherrows', 'image')\n\n```\n\nNow if you want to update `Voucher` with `VoucherRow` and voucher image then you need to do it\nusing form-data via `PUT` or `PATCH` request where your `voucherrows` fields are nested field.\nWith the current implementation of the `drf-writable-nested` doesn't update it. Because it does\nnot support something like-\n\n```text\nvoucherrows[1].account=1120\nvoucherrows[1].debit=1000.00\nvoucherrows[1].credit=0.00\nvoucherrows[1].description='Debited from Bank Account' \nvoucherrows[2].account=1130\nvoucherrows[2].debit=0.00\nvoucherrows[2].credit=1000.00\nvoucherrows[2].description='Credited to Cash Account'\n\n```\nThis is not supported at least for now. So, we can achieve the result in a different way.\nInstead of sending the array fields separately in this way we can convert the whole fields\nalong with values in a `json` string like below and set it as value to the field `voucherrows`.\n\n```json\n\"[{\\\"account\\\": 1120, \\\"debit\\\": 1000.00, \\\"credit\\\": 0.00, \\\"description\\\": \\\"Debited from Bank Account\\\"}, {\\\"account\\\": 1130, \\\"debit\\\": 0.00, \\\"credit\\\": 1000.00, \\\"description\\\": \\\"Credited to Cash Account\\\"}]\"\n```\n\nNow it'll be actually sent as a single field value to the application for the field `voucherrows`.\nFrom your `views` you need to parse it like below before sending it to the serializer-\n\n```python\nclass VoucherViewSet(viewsets.ModelViewSet):\n    serializer_class = VoucherSerializer\n    queryset = serializer_class.Meta.model.objects.all().order_by('-created_at')\n    \n    def update(self, request, *args, **kwargs):\n        request.data.update({'voucherrows': json.loads(request.data.pop('voucherrows', None))})\n        return super().update(request, *args, **kwargs)\n```\nNow, you'll get the `voucherrows` field with data in the right format in your serializers.\nSimilar approach will be also applicable for generic views for django rest framework\n\nAuthors\n=======\n2014-2022, beda.software\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeda-software%2Fdrf-writable-nested","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeda-software%2Fdrf-writable-nested","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeda-software%2Fdrf-writable-nested/lists"}