make it simpler to access schema through foreign key relation
Hey, thanks for this library. I have a use-case that I believe is fairly normal as I've had to do the same thing in multiple different situations/projects. Using your library I've had to do some workarounds to get there.
The setup is this: I have to store annual surveys in the database. The surveys are always have a few fields that always need to be included (name, date, etc.) and other fields that change every year. So I create two models in the database:
class SurveyType(models.Model):
name = models.CharField(max_length=255)
schema = models.JSONField(default=dict)
def __str__(self):
return self.name
class SurveyEntry(models.Model):
participant_name = models.Charfield(max_length=255)
date = models.DateField()
survey_type = models.ForeignKey(
SurveyType,
on_delete=models.CASCADE,
)
survey_data = jsonformJSONField(schema=lambda instance: instance.survey_type.schema)
This looks good, but it won't work as initially when entering a new SurveyEntry, no survey_type has been defined. It would be good if there was a way to handle that. The work around I found was to do this to SurveyEntry:
class SurveyEntry(models.Model):
participant_name = models.Charfield(max_length=255)
date = models.DateField()
survey_type = models.ForeignKey(
SurveyType,
on_delete=models.CASCADE,
)
survey_data = jsonformJSONField(
schema=lambda instance=None: instance.survey_type.schema
if instance and hasattr(instance, "survey_type")
else {"type": "object", "properties": {}},
null=True,
blank=True,
)
def save(self, *args, **kwargs):
if not bool(self.survey_data):
# This was likely based on the default schema. Remove again.
self.survey_data = None
return super().save(*args, **kwargs)
I wouldn't call it a workaround. Since you've got a callable schema, it's your responsibility to handle the errors within that callable.
As the callable is your written code, I don't think the field should automatically handle the exceptions raised in it.
ok, how about adding something to the documentation about it then? Then others can benefit from me having researched this once already.
I'll update the docs. Thank you for your suggestions.
I have to use form to make it works
class FlowerPackForm(forms.ModelForm):
class Meta:
model = FlowerPack
exclude = ["is_removed"]
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
instance = kwargs.get("instance", None)
if instance and hasattr(instance, "sku"):
self.fields["attributes"].widget.schema = instance.sku.attribute_schema
I have try to modify the model meta field but it seams have cache, so it not allways work.
class FlowerPack(BaseModel):
sku = models.ForeignKey(Sku, models.CASCADE, related_name="packs")
attributes = JSONField(
schema={"type": "object", "properties": {}},
null=True,
blank=True,
verbose_name="SKU 属性列表",
)
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
if hasattr(self, "sku"):
field = self._meta.get_field("attributes")
field.schema = self.sku.attribute_schema