Hello,

As part of my GSoC work [1] I did a refactor of ForeignKey whereby I
turned it into a virtual field which creates an auxiliary concrete
field to hold the raw value.

As part of this, there are several changes that I did in Model._meta:

1) There are now more fields in _meta.fields, obviously. For each
   ForeignKey there is now an extra field with `_id` appended to its
   name. This extra field is not editable nor serializable, which
   means things like serialization, ModelForms or the admin just
   ignore it, however, I have no idea what other things people use
   _meta.fields for and it might cause problems for third-party
   projects.

2) I ditched _meta.virtual_fields and put all fields into local_fields
   instead. The reason is simple, since ForeignKey is now virtual, in
   a lot of places where local_fields is accessed, I'd have to search
   local_fields + virtual_fields. Basically, the only reason for
   virtual_fields that I could find was that they were cloned in each
   model subclass, more on this in the next item.

3) No more cloning of all virtual fields in each model subclass.
   Currently, each field in virtual_fields in parent models is cloned
   in ModelBase.__new__ and added to the subclass as a separately
   owned field. This is rather redundant for most virtual field types
   (in master that would only be GenericForeignKey and
   GenericRelation, in my composite-fields branch there's also
   ForeignKey and CompositeField). The only "field" which requires
   cloning is GenericRelation which needs to determine when it's
   accessed through a model subclass to retrieve the right content
   type.

   For other field types this is not necessary and in the case of
   ForeignKey it might even cause undesired effects, like multiple
   conflicting reverse ForeignKey pointers to a target model. Also,
   all related object descriptors and possibly other objects would be
   recreated separately for each subclass. While those should be
   possible to deal with, I'm still not a big fan of creating clones
   of objects and adding extra complexity to account for this without
   any real reason.

   Therefore, instead of cloning all virtual fields, each field class
   now has an attribute `clone_in_subclasses` which is True in
   GenericRelation and False everywhere else. Those fields with this
   attribute set to True will end up in private_fields instead of
   local_fields.

To see the whole diff, check out the pull request I created [2].

I'd like people's opinions on these changes. What's the status of
Model._meta? Last time I saw, it was in the state of a semi-private
API -- it is not really public as it is not documented anywhere, but a
LOT of people still use it in their projects because it's considered
quite stable.

As I said, I don't really know what people use _meta for in their
projects and it's rather difficult for me to anticipate in what ways
these changes can break things for them.

Anssi suggested in a comment [3] to keep fields as close to the
current state as possible, which means ForeignKey would appear there
and the auxiliary fields it creates would not and create something
like all_fields which would hold those as well. It is certainly
possible to do this, but personally, I'm not really convinced -- it
would mean I'd have to rewrite practically all occurrences od
_meta.fields in Django to _meta.all_fields and it would introduce
certain ambiguity as it would not really be clear what the difference
between fields and all_fields is.

So, I'd like your opinions. The more the better. Whatever the outcome,
all changes will be thoroughly documented in the release notes which
I'll start working on as soon as a conclusion is reached.

Michal


[1] https://github.com/koniiiik/django/tree/soc2013/foreignkey-refactor
[2] https://github.com/django/django/pull/1407
[3] https://github.com/django/django/pull/1407#issuecomment-22092167

Attachment: signature.asc
Description: Digital signature

Reply via email to