#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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
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.

Reply via email to