#16508: Provide real support for virtual fields
-------------------------------------+-------------------------------------
Reporter: vzima | Owner: pirosb3
Type: New feature | Status: assigned
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by koniiiik):
* cc: michal.petrucha@… (added)
Comment:
I have recently started to dust off my old code from GSoC 2013, where my
first step was pretty much this. Let me summarize my take on this. (I'm
sorry, this is going to be a bit long, but I'm trying to organize my
thoughts on how to approach this entire thing.)
My implementation from a few years ago matches the description from
comment:5 (as far as the conceptual handling of `ForeignKey` goes), and
also comment:7 (when it comes to the actual class hierarchy). And yeah,
comment:9 is also mostly spot-on, except for the last sentence – the ORM
or migrations certainly can't ignore `ForeignKey` once it becomes virtual;
instead, migrations will have to hide any auto-generated auxiliary
concrete fields to make migrations backwards-compatible.
I think that before we start working on `ForeignKey` and break the entire
ORM, it would be kind of nice to just get the more general `VirtualField`
in. The code for just the VirtualField class without any changes to
`ForeignKey` and friends can be seen in
[[https://github.com/koniiiik/django/compare/1116df0751cc0d5862590b08adfffe7bacd6bf43...koniiiik:349796f37998e02e34a2b47ab5f3e763ae60140f|this
Github comparison]]. After that I implemented the virtual `ForeignKey`
change, but up to that point, it was pretty isolated and self-contained.
Key observations from my implementation: `GenericForeignKey` and
`GenericRelation` are handled specially in
1. model instance initialization (using the `pre_init` signal),
2. they are kind of special cased in deletion cascading, and
3. they are cloned in every model subclass.
Number 1 was fixed by making `Model.__init__` consider virtual fields when
processing keyword arguments. This made it possible to remove the usage of
`pre_init` from `GenericForeignKey`.
Number 2 I'm not entirely certain about right now; I haven't yet found the
time to fully understand how this is handled after Daniel's `_meta`
refactor, but there used to be a few caches of arbitrary collections of
relationship objects. I handled this by including `GenericRelation` in
those collections, which meant it was no longer necessary to special-case
`_meta.virtual_fields` just to reach `GenericRelation`s. I guess these
days this could be achieved by making sure `GenericRelation` appears in
`_meta.related_objects`, but I'd need to study this a bit further to be
certain. (Daniel, do you have any insight here? Can we even to that now
without breaking backwards compatibility?)
Number 3 is a peculiarity of `GenericRelation`. The problem here is that
it needs a reference to the current model in order to use the correct
content type, which means it really does need to be cloned in every
subclass, even in concrete model inheritance (otherwise it would use the
parent's content type).
Right now, all virtual fields are cloned in concrete inheritance, but that
doesn't make any sense for other virtual fields, like `ForeignKey`, or
`CompositeField`, or whatever. Those should be handled just like any other
field, as far as inheritance is concerned. This doesn't really have
anything to do with `GenericRelation` being a virtual field, instead, a
more fitting name for this particular concept would be something like
“private” field (or “local private”, as I named it in my 2013's branch).
After all, we already do have support for other virtual fields that do not
land in `_meta.virtual_fields`. (`ForeignObject`, although AFAIK it is not
a public API, but still.)
With all that being said, I would like to get the ball rolling by offering
[[https://github.com/django/django/pull/6329|PR 6329]] which implements
number 3 above, the rename of `_meta.virtual_fields` to
`_meta.private_fields`.
In the meantime I'll go investigate what to do about the rest of the
changes in that range of commits I linked above.
--
Ticket URL: <https://code.djangoproject.com/ticket/16508#comment:10>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/063.a964feb8f810464d71880454b0274878%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.