nondestructive access to the JSON field
Here's my suggestion for further improvement: if a JSONField is being used to hold various values, like an "additional options" field, as I think is often the case, then the admin form doesn't necessarily know about every possible key. And perhaps the way the form is initialized varies, so that in certain contexts we only want to display and edit a portion of the complete JSON. Therefore, the clean method on an EntangledModelForm should access the JSON fields without reinitializing everything (see here).
One other thing to mention: More support for standard callbacks like get_fields would be great (to customize entangled fields being displayed on an add form vs a change form, for example). The way you've designed things, initially, though - I really like it!
Looking at this again, it's clear to me now that the second comment is incorrect. Since that's taken care of by the admin classes and this is all happening at the form level. So I guess, disregard that part!
can I close this?
The second paragraph being incorrect doesn't change anything about the first. It's a feature request ticket. You can handle it as you like, of course.
If you would like to take a look, I can direct you to the code I wrote after deciding that this library wouldn't work for me. Might be some ideas for you there.
Here's my suggestion for further improvement: if a JSONField is being used to hold various values, like an "additional options" field, as I think is often the case, then the admin form doesn't necessarily know about every possible key. And perhaps the way the form is initialized varies, so that in certain contexts we only want to display and edit a portion of the complete JSON. Therefore, the clean method on an EntangledModelForm should access the JSON fields without reinitializing everything (see here).
But the complete JSONField isn't initialized then, only the fields which are part of entangled_fields are initialized. Maybe I didn't understand well what you mean. Could you please explain it through an example.
Only the fields mentioned as keys in entangled_fields are initialized, but my situation is that some of the JSON keys are unknown - the values in entangled_fields. So when we get here, it wipes away data that is meant to only be inaccessible.
The equivalent, in my adaptation, is here. But as it stands, the use cases we're supporting only somewhat overlaps, I think. (In particular, my version has gotten more complicated recently from changes to help with forms that have dynamic fields, unknown until runtime.)
A concrete example, that doesn't involve plugins or something strange. Let's see. Say you have a polls app, and the choices model has an additional type field. There's a javascript widget that's used on the poll form, for each of these types. On the question model, we might have a JSONField where each key is a choice type, and then the value is some kind of override for how the widget is initialized in case the choice is of that type.
Finally, suppose that there is a special type that only superusers are allowed to override. If the access to the JSON field was nondestructive, it would just be a matter of subclassing and changing the keys mentioned in entangled_fields.
I think this would at least be a great optional feature for the package. For me this implies that a form only updates entangled fields in the json field that are part of the form. Should the json contain additional fields (not part of the form) they (at least optionally) stay unchanged. Right now they are removed from the json field.
A use case might be that different apps use different entangled form fields (say, app1_title, app1_content and app2_ styling). App1 can then have a form that changes title and content and app2 can have a form that changes styling, each leaving the other part of the content untouched.
@johncronan I now believe that I now understood what you need. Well, I can try to implement this.
@fsbraun explained it better than I did! If you get a chance to make those changes, I'll take a look and see if I can switch over in my application.
Although, unfortunately, I suspect it won't be possible. I ran into a problem in Django, itself, namely that if you want to add a non-model field to a ModelForm, it has to be statically declared and visible to the metaclass code, so that Django can throw an error for cases where there's just a typo, or something. I added a pretty hacky solution as an option, to deal with this, and I'm relying on it, because plugins can change the JSON fields at runtime, for certain forms.
If you're interested, I can open a separate issue describing that.
How about building the form dynamically, ie. using type('MyForm', (EntangledModelForm,), {'field1': fields.CharField, ..., 'Meta': SomeMetaClass})?
Anyway, how about writing a playbook with a real example?
Oh it's an open source project. So, I do that kind of thing with (in my case) AdminJSONForm, eg, here and here.
That's a good idea, and it hadn't occurred to me, but seems like a route that would save a lot of trouble. I can try adapting the code that way, when it comes time.
edited to add: by way of explanation, 'admin_fields' is a constructor argument that's a convenience for adding fields onto the form after all the init work is done. The real magic is in the static_fields specification, which is used to recognize and temporarily exclude dynamic fields. It's a bodge - this is the trouble part.