Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Unable to enter json in django admin

In my model I have the following field –

data_fields = ArrayField(models.JSONField(null=True, blank=True), blank=True, null=True)

In order to test this out, I entered the following in the data_field in the django admin –

[{"key": "name", "label": "Name"}, {"key": "amount", "label": "Amount"}]

But I get an error saying

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Item 1 in the array did not validate: Enter a valid JSON.
Item 2 in the array did not validate: Enter a valid JSON.
Item 3 in the array did not validate: Enter a valid JSON.
Item 4 in the array did not validate: Enter a valid JSON.

I only get this error if there are multiple key-value pairs in the JSON. If there is only one JSON element with one key-value pair, it works. If there are multiple elements in the array, or there are multiple key-value pairs in the JSON field, I get the error above.

Why is this happening, and how do I fix it?

>Solution :

This is one of the many reasons not to use an ArrayField or JSONField in the first place [django-antipatterns]. ArrayFields are, as far as I know, not very well supported in databases nor in Django, and that results in all sorts of querying problems, and problems with forms.

That being said, why not just use a JSONField [Django-doc], after all, a list is a JSON blob, so using:

data_fields = models.JSONField(null=True, blank=True, default=list)

But still, if the structure is fixed, like the JSON blob seems to be, I would advise using an inline:

class Parent(models.Model):
    pass


class ParentDataField(models.Model):
    parent = models.ForeignKey(
        Parent, related_name='data_fields', on_delete=models.CASCADE
    )
    key = models.CharField(max_length=128)
    label = models.CharField(max_length=128)

in fact, we even can ensure that for the same parent, the key only occurs at most once:

class Parent(models.Model):
    pass


class ParentDataField(models.Model):
    parent = models.ForeignKey(
        Parent, related_name='data_fields', on_delete=models.CASCADE
    )
    key = models.CharField(max_length=128)
    label = models.CharField(max_length=128)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=('parent', 'key'), name='unique_key_per_parent'
            )
        ]

and then work with an inline:

from django.contrib import admin


class ParentDataFieldInline(admin.TabularInline):
    model = ParentDataField


class ParentAdmin(admin.ModelAdmin):
    inlines = [
        ParentDataFieldInline,
    ]
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading