#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.