Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Produce helpful error messages when default data doesn't match the schema #101

Open
abhishek-compro opened this issue May 5, 2023 · 12 comments
Labels
bug Something isn't working

Comments

@abhishek-compro
Copy link

Sample schema which works on https://bhch.github.io/react-json-form/playground/#8-recursion but doesn't work when using django-jsonform:

{
  "$defs": {
    "and": {
      "type": "object",
      "keys": {
        "and": {
          "type": "array",
          "items": {
            "oneOf": [
              {
                "$ref": "#/$defs/and",
                "title": "and"
              },
              {
                "$ref": "#/$defs/or",
                "title": "or"
              }
            ]
          }
        }
      }
    },
    "or": {
      "type": "object",
      "keys": {
        "or": {
          "type": "array",
          "items": {
            "oneOf": [
              {
                "$ref": "#/$defs/and",
                "title": "and"
              },
              {
                "$ref": "#/$defs/or",
                "title": "or"
              }
            ]
          }
        }
      }
    }
  },
  "oneOf": [
    {
      "$ref": "#/$defs/or",
      "title": "or"
    }
  ]
}
@bhch
Copy link
Owner

bhch commented May 5, 2023

Which version are you on? Check using:

$ python -c "import django_jsonform; print(django_jsonform.__version__)"

@abhishek-compro
Copy link
Author

Which version are you on?

2.17.0

@bhch
Copy link
Owner

bhch commented May 7, 2023

So I did some tests. Seems to work as expected.

Here's an animated GIF:

animated gif


What issues are you getting?

@abhishek-compro
Copy link
Author

abhishek-compro commented May 8, 2023

I was getting the following error:

TypeError: t is undefined
    Re http://localhost:8000/static/django_jsonform/react-json-form.js:1
    g http://localhost:8000/static/django_jsonform/react-json-form.js:1
    _e http://localhost:8000/static/django_jsonform/react-json-form.js:1
    render http://localhost:8000/static/django_jsonform/react-json-form.js:1
    React 13
    render http://localhost:8000/static/django_jsonform/react-json-form.js:1
    initJSONForm http://localhost:8000/static/django_jsonform/index.js:62
    initializeAllForNode http://localhost:8000/static/django_jsonform/index.js:100
    init http://localhost:8000/static/django_jsonform/index.js:105
    <anonymous> http://localhost:8000/static/django_jsonform/index.js:145
    EventListener.handleEvent* http://localhost:8000/static/django_jsonform/index.js:144
    <anonymous> http://localhost:8000/static/django_jsonform/index.js:149
react-dom.production.min.js:141:274

What should I do?

Edit: Got this in Firefox

@bhch
Copy link
Owner

bhch commented May 8, 2023

Try disabling your browser cache.

If this is a production environment, you must also run the collectstatic command to replace old static files with new ones.

@abhishek-compro
Copy link
Author

abhishek-compro commented May 8, 2023

Got this in chrome:

react-dom.production.min.js:141 TypeError: Cannot read properties of undefined (reading 'length')
    at Re (react-json-form.js:1:52698)
    at g (react-json-form.js:1:56760)
    at _e (react-json-form.js:1:57098)
    at a.render (react-json-form.js:1:59517)
    at Te (react-dom.production.min.js:119:308)
    at Ch (react-dom.production.min.js:119:105)
    at Pj (react-dom.production.min.js:233:139)
    at di (react-dom.production.min.js:168:305)
    at Nj (react-dom.production.min.js:168:236)
    at sc (react-dom.production.min.js:168:96)

Try disabling your browser cache.

I did clear the browser cache and reinstalled all the packages in a fresh project and got the same error. How do I disable the cache though?

Its development environment.

To be more precise I am using the following model:

class UserFilter(models.Model):
    filters = JSONField(
        schema={
            "$defs": {
                "and": {
                    "type": "object",
                    "properties": {
                        "and": {
                            "type": "array",
                            "items": {
                                "oneOf": [
                                    {"$ref": "#/$defs/and", "title": "and"},
                                    {"$ref": "#/$defs/or", "title": "or"},
                                ]
                            },
                        }
                    },
                },
                "or": {
                    "type": "object",
                    "properties": {
                        "or": {
                            "type": "array",
                            "items": {
                                "oneOf": [
                                    {"$ref": "#/$defs/and", "title": "and"},
                                    {"$ref": "#/$defs/or", "title": "or"},
                                ]
                            },
                        }
                    },
                },
            },
            "oneOf": [
                {"$ref": "#/$defs/and", "title": "and"},
                {"$ref": "#/$defs/or", "title": "or"},
            ],
        },
        default=dict,
    )
    name = models.CharField(max_length=512, unique=True)

What are you using?

@bhch
Copy link
Owner

bhch commented May 8, 2023

default=dict is what's causing the problem.

The widget is receiving {} as the default data which doesn't match any subschemas listed under oneOf.

To fix it, you should:

  • either stop providing a default value. The widget will automatically create appropriate empty data, so I don't think you should worry about it.
  • or if you must, then the default value must match at least one of the subschemas, e.g.: default={"and": []}.

Anyway, I'll mark this issue as a bug because the widget should handle this type of cases more gracefully and should produce helpful error messages.

@bhch bhch added the bug Something isn't working label May 8, 2023
@bhch bhch changed the title Support for infinite recursion Produce helpful error messages when default data doesn't match the schema May 8, 2023
@abhishek-compro
Copy link
Author

That worked. Thanks!!

@sgocg
Copy link

sgocg commented Nov 27, 2023

I'm running into a similar issue (at least the stacktrace is the same as mentioned in #101 (comment)) when adding a new array field to the schema.

A minimal version of my schema looks as follows:

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
  }
}

If I update the schema to the following value:

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "tags": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}

... for existing values in the database (eg. {"name": "Example"}) the admin widget doesn't render and shows this message instead: (!) TypeError: Cannot read properties of undefined (reading 'length').

Interestingly, this only happens if the type of tags is array. If set the type to something else (eg. string), the admin widget renders fine and it's also possible to update the tags value using the widget. I tried providing a default value in the schema but unfortunately it didn't help.

@bhch
Copy link
Owner

bhch commented Nov 28, 2023

@sgocg Hi, I just tested the scenario you mentioned. It's working completely fine for me. I tested with the latest version (2.21.0).

Which version are you using?

@sgocg
Copy link

sgocg commented Nov 28, 2023

Thanks for testing it out. And apologies that the previous schema wasn't fully representative. I tried pasting a (much too) simplified version of the schema as my original schema is quite large.

In any case, I was able to simplify it differently now. Here's the original schema:

{
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "title": "Example",
      "oneOf": [
        {
          "title": "Table",
          "properties": {
            "type": {
              "type": "string",
              "default": "table",
              "widget": "hidden"
            },
            "columns": {
              "title": "Columns",
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "title": "Header"
                  },
                  "type": {
                    "type": "string",
                    "title": "Type",
                    "choices": [
                      "string",
                      "number",
                      "integer",
                      "boolean"
                    ],
                    "default": "string",
                    "required": true
                  },
                  "default": {
                    "type": "array",
                    "title": "Prepopulate rows (EN)",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      ]
    }
  }
}

If I update the schema to this:

{
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "title": "Example",
      "oneOf": [
        {
          "title": "Table",
          "properties": {
            "type": {
              "type": "string",
              "default": "table",
              "widget": "hidden"
            },
            "columns": {
              "title": "Columns",
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "title": "Header"
                  },
                  "type": {
                    "type": "string",
                    "title": "Type",
                    "choices": [
                      "string",
                      "number",
                      "integer",
                      "boolean"
                    ],
                    "default": "string",
                    "required": true
                  },
                  "default": {
                    "type": "array",
                    "title": "Prepopulate rows (EN)",
                    "items": {
                      "type": "string"
                    }
                  },
                  "default_de": {
                    "type": "array",
                    "title": "Prepopulate rows (DE)",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      ]
    }
  }
}

... i.e. add the default_de property, the admin widget doesn't render with the following message:
Screenshot 2023-11-28 at 10 02 20 AM

In the database I'm using the following value:

{
  "data": {
    "type": "table",
    "columns": [
      {
        "type": "string",
        "title": "Column 1",
        "default": [
          "first",
          "second",
          "third"
        ]
      },
      {
        "type": "number",
        "title": "Column 2",
        "default": []
      },
      {
        "type": "string",
        "title": "Column 3",
        "default": []
      }
    ]
  }
}

I was using 2.17.0 earlier but upgraded to 2.21.0 but the problem still persists.

@bhch
Copy link
Owner

bhch commented Nov 28, 2023

@sgocg I am able to reproduce the error now. It's a separate issue altogether. Will be tracked in #131.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants