Refs #16508 -- Made Model.__init__() aware of virtual fields.

It's no longer necessary for GenericForeignKey (and any other virtual fields)
to intercept the field's values using the pre_init signal.
This commit is contained in:
Michal Petrucha 2016-04-19 22:34:08 +02:00 committed by Tim Graham
parent 8a55982e70
commit 8a47ba679d
3 changed files with 9 additions and 22 deletions

View File

@ -6,7 +6,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core import checks from django.core import checks
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
from django.db import DEFAULT_DB_ALIAS, models, router, transaction from django.db import DEFAULT_DB_ALIAS, models, router, transaction
from django.db.models import DO_NOTHING, signals from django.db.models import DO_NOTHING
from django.db.models.base import ModelBase, make_foreign_order_accessors from django.db.models.base import ModelBase, make_foreign_order_accessors
from django.db.models.fields.related import ( from django.db.models.fields.related import (
ForeignObject, ForeignObjectRel, ReverseManyToOneDescriptor, ForeignObject, ForeignObjectRel, ReverseManyToOneDescriptor,
@ -54,11 +54,6 @@ class GenericForeignKey(object):
self.model = cls self.model = cls
self.cache_attr = "_%s_cache" % name self.cache_attr = "_%s_cache" % name
cls._meta.add_field(self, private=True) cls._meta.add_field(self, private=True)
# Only run pre-initialization field assignment on non-abstract models
if not cls._meta.abstract:
signals.pre_init.connect(self.instance_pre_init, sender=cls)
setattr(cls, name, self) setattr(cls, name, self)
def get_filter_kwargs_for_object(self, obj): def get_filter_kwargs_for_object(self, obj):
@ -162,20 +157,6 @@ class GenericForeignKey(object):
else: else:
return [] return []
def instance_pre_init(self, signal, sender, args, kwargs, **_kwargs):
"""
Handle initializing an object with the generic FK instead of
content_type and object_id fields.
"""
if self.name in kwargs:
value = kwargs.pop(self.name)
if value is not None:
kwargs[self.ct_field] = self.get_content_type(obj=value)
kwargs[self.fk_field] = value._get_pk_val()
else:
kwargs[self.ct_field] = None
kwargs[self.fk_field] = None
def get_content_type(self, obj=None, id=None, using=None): def get_content_type(self, obj=None, id=None, using=None):
if obj is not None: if obj is not None:
return ContentType.objects.db_manager(obj._state.db).get_for_model( return ContentType.objects.db_manager(obj._state.db).get_for_model(

View File

@ -452,11 +452,14 @@ class Model(six.with_metaclass(ModelBase)):
if kwargs: if kwargs:
for prop in list(kwargs): for prop in list(kwargs):
try: try:
if isinstance(getattr(self.__class__, prop), property): # Any remaining kwargs must correspond to properties or
# virtual fields.
if (isinstance(getattr(self.__class__, prop), property) or
self._meta.get_field(prop)):
if kwargs[prop] is not DEFERRED: if kwargs[prop] is not DEFERRED:
setattr(self, prop, kwargs[prop]) setattr(self, prop, kwargs[prop])
del kwargs[prop] del kwargs[prop]
except AttributeError: except (AttributeError, FieldDoesNotExist):
pass pass
if kwargs: if kwargs:
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0]) raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])

View File

@ -400,6 +400,9 @@ Models
* A proxy model may now inherit multiple proxy models that share a common * A proxy model may now inherit multiple proxy models that share a common
non-abstract parent class. non-abstract parent class.
* ``Model.__init__()`` now sets values of virtual fields from its keyword
arguments.
Requests and Responses Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~