0

Hello Stackoverflowers!

I've searched for a solution for this for a while, but have not been able to find anything addressing this usecase specifically.

Say we have the following models:

class Machine(models.model):
    machine_name = models.CharField(max_length=30)
    machine_data_template = models.JSONField()

class Event(models.model):
    machine_name = models.ForeignKey(Machine, on_delete=models.CASCADE
    machine_data = models.JSONField()

We have a machine for which there can be multiple events, the details of which are stored as JSON in a JSONField. The JSONField in event should be validated using the json-schema defined in Machine.machine_data_template.

I've looked at various Python/Django implementations of json-schemas, however I have not been able to find a way where we can define custom validation on a per-object basis. For example, solutions such as the one presented by Corwin Cole here defines the validation logic directly in the model, which would mean each instance of event would be subject to the same validation logic regardless of the machine:

MY_JSON_FIELD_SCHEMA = {
    'schema': 'http://json-schema.org/draft-07/schema#',
    'type': 'object',
    'properties': {
        'my_key': {
            'type': 'string'
        }
    },
    'required': ['my_key']
}

class MyModel(models.Model):
    my_json_field = JSONField(
        default=dict,
        validators=[JSONSchemaValidator(limit_value=MY_JSON_FIELD_SCHEMA)]
    )

Does anyone have any suggestion how I can achieve the desired "fully polymorphic" behavior?

BR - K

1 Answers1

0

You can override the Model.clean() method and add custom validation there. You have access to the Event and it's related Machine so can access the schema. Add an example using jsonschema similar to the linked answer

import jsonschema


class Machine(models.Model):
    machine_name = models.CharField(max_length=30)
    machine_data_template = models.JSONField()


class Event(models.Model):
    machine_name = models.ForeignKey(Machine, on_delete=models.CASCADE)
    machine_data = models.JSONField()

    def clean(self):
        try:
            jsonschema.validate(self.machine_data, self.machine_name.machine_data_template)
        except jsonschema.exceptions.ValidationError as e:
            raise ValidationError({'machine_data': str(e)})
Iain Shelvington
  • 31,030
  • 3
  • 31
  • 50
  • Thanks for the input Iain! I think the approach you outlined will work well, I'll update once I try it out. – danaust Mar 02 '21 at 20:46