from functools import partial
from django.db.models.utils import make_model_tuple
from django.dispatch import Signal
class_prepared = Signal(providing_args=["class"])
classModelSignal(Signal):"""
Signal subclass that allows the sender to be lazily specified as a string
of the `app_label.ModelName` form.
"""def_lazy_method(self, method, apps, receiver, sender, **kwargs):from django.db.models.options import Options
# This partial takes a single optional argument named "sender".
partial_method = partial(method, receiver, **kwargs)
if isinstance(sender, str):
apps = apps or Options.default_apps
apps.lazy_model_operation(partial_method, make_model_tuple(sender))
else:
return partial_method(sender)
defconnect(self, receiver, sender=None, weak=True, dispatch_uid=None, apps=None):
self._lazy_method(
super().connect, apps, receiver, sender,
weak=weak, dispatch_uid=dispatch_uid,
)
defdisconnect(self, receiver=None, sender=None, dispatch_uid=None, apps=None):return self._lazy_method(
super().disconnect, apps, receiver, sender, dispatch_uid=dispatch_uid
)
pre_init = ModelSignal(providing_args=["instance", "args", "kwargs"], use_caching=True)
post_init = ModelSignal(providing_args=["instance"], use_caching=True)
pre_save = ModelSignal(providing_args=["instance", "raw", "using", "update_fields"],
use_caching=True)
post_save = ModelSignal(providing_args=["instance", "raw", "created", "using", "update_fields"], use_caching=True)
pre_delete = ModelSignal(providing_args=["instance", "using"], use_caching=True)
post_delete = ModelSignal(providing_args=["instance", "using"], use_caching=True)
m2m_changed = ModelSignal(
providing_args=["action", "instance", "reverse", "model", "pk_set", "using"],
use_caching=True,
)
pre_migrate = Signal(providing_args=["app_config", "verbosity", "interactive", "using", "apps", "plan"])
post_migrate = Signal(providing_args=["app_config", "verbosity", "interactive", "using", "apps", "plan"])
先记录下,之后慢慢学习~
classModel(metaclass=ModelBase):def__init__(self, *args, **kwargs):# Alias some things as locals to avoid repeat global lookups
cls = self.__class__
opts = self._meta
_setattr = setattr
_DEFERRED = DEFERRED
#初始化前发送信号
pre_init.send(sender=cls, args=args, kwargs=kwargs)
# Set up the storage for instance state
self._state = ModelState()
# There is a rather weird disparity here; if kwargs, it's set, then args# overrides it. It should be one or the other; don't duplicate the work# The reason for the kwargs check is that standard iterator passes in by# args, and instantiation for iteration is 33% faster.if len(args) > len(opts.concrete_fields):
# Daft, but matches old exception sans the err msg.raise IndexError("Number of args exceeds number of fields")
ifnot kwargs:
fields_iter = iter(opts.concrete_fields)
# The ordering of the zip calls matter - zip throws StopIteration# when an iter throws it. So if the first iter throws it, the second# is *not* consumed. We rely on this, so don't change the order# without changing the logic.for val, field in zip(args, fields_iter):
if val is _DEFERRED:
continue
_setattr(self, field.attname, val)
else:
# Slower, kwargs-ready version.
fields_iter = iter(opts.fields)
for val, field in zip(args, fields_iter):
if val is _DEFERRED:
continue
_setattr(self, field.attname, val)
kwargs.pop(field.name, None)
# Now we're left with the unprocessed fields that *must* come from# keywords, or default.for field in fields_iter:
is_related_object = False# Virtual fieldif field.attname notin kwargs and field.column isNone:
continueif kwargs:
if isinstance(field.remote_field, ForeignObjectRel):
try:
# Assume object instance was passed in.
rel_obj = kwargs.pop(field.name)
is_related_object = Trueexcept KeyError:
try:
# Object instance wasn't passed in -- must be an ID.
val = kwargs.pop(field.attname)
except KeyError:
val = field.get_default()
else:
# Object instance was passed in. Special case: You can# pass in "None" for related objects if it's allowed.if rel_obj isNoneand field.null:
val = Noneelse:
try:
val = kwargs.pop(field.attname)
except KeyError:
# This is done with an exception rather than the# default argument on pop because we don't want# get_default() to be evaluated, and then not used.# Refs #12057.
val = field.get_default()
else:
val = field.get_default()
if is_related_object:
# If we are passed a related instance, set it using the# field.name instead of field.attname (e.g. "user" instead of# "user_id") so that the object gets properly cached (and type# checked) by the RelatedObjectDescriptor.if rel_obj isnot _DEFERRED:
_setattr(self, field.name, rel_obj)
else:
if val isnot _DEFERRED:
_setattr(self, field.attname, val)
if kwargs:
property_names = opts._property_names
for prop in tuple(kwargs):
try:
# Any remaining kwargs must correspond to properties or# virtual fields.if prop in property_names or opts.get_field(prop):
if kwargs[prop] isnot _DEFERRED:
_setattr(self, prop, kwargs[prop])
del kwargs[prop]
except (AttributeError, FieldDoesNotExist):
passfor kwarg in kwargs:
raise TypeError("'%s' is an invalid keyword argument for this function" % kwarg)
super().__init__()
#初始化完毕发送信号
post_init.send(sender=cls, instance=self)
defsave_base(self, raw=False, force_insert=False,
force_update=False, using=None, update_fields=None):"""
Handle the parts of saving which should be done only once per save,
yet need to be done in raw saves, too. This includes some sanity
checks and signal sending.
The 'raw' argument is telling save_base not to save any parent
models and not to do any changes to the values before save. This
is used by fixture loading.
"""
using = using or router.db_for_write(self.__class__, instance=self)
assertnot (force_insert and (force_update or update_fields))
assert update_fields isNoneor len(update_fields) > 0
cls = origin = self.__class__
# Skip proxies, but keep the origin as the proxy model.if cls._meta.proxy:
cls = cls._meta.concrete_model
meta = cls._meta
ifnot meta.auto_created:
#数据保存前发送信号
pre_save.send(
sender=origin, instance=self, raw=raw, using=using,
update_fields=update_fields,
)
with transaction.atomic(using=using, savepoint=False):
ifnot raw:
self._save_parents(cls, using, update_fields)
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
# Store the database on which the object was saved
self._state.db = using
# Once saved, this is no longer a to-be-added instance.
self._state.adding = False# Signal that the save is completeifnot meta.auto_created:
#数据保存后发送信号
post_save.send(
sender=origin, instance=self, created=(not updated),
update_fields=update_fields, raw=raw, using=using,
)
ModelBase类:
classModelBase(type):def_prepare(cls):"""Create some methods once self._meta has been populated."""
opts = cls._meta
opts._prepare(cls)
if opts.order_with_respect_to:
cls.get_next_in_order = partialmethod(cls._get_next_or_previous_in_order, is_next=True)
cls.get_previous_in_order = partialmethod(cls._get_next_or_previous_in_order, is_next=False)
# Defer creating accessors on the foreign class until it has been# created and registered. If remote_field is None, we're ordering# with respect to a GenericForeignKey and don't know what the# foreign class is - we'll add those accessors later in# contribute_to_class().if opts.order_with_respect_to.remote_field:
wrt = opts.order_with_respect_to
remote = wrt.remote_field.model
lazy_related_operation(make_foreign_order_accessors, cls, remote)
# Give the class a docstring -- its definition.if cls.__doc__ isNone:
cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join(f.name for f in opts.fields))
get_absolute_url_override = settings.ABSOLUTE_URL_OVERRIDES.get(opts.label_lower)
if get_absolute_url_override:
setattr(cls, 'get_absolute_url', get_absolute_url_override)
ifnot opts.managers:
if any(f.name == 'objects'for f in opts.fields):
raise ValueError(
"Model %s must specify a custom Manager, because it has a ""field named 'objects'." % cls.__name__
)
manager = Manager()
manager.auto_created = True
cls.add_to_class('objects', manager)
# Set the name of _meta.indexes. This can't be done in# Options.contribute_to_class() because fields haven't been added to# the model at that point.for index in cls._meta.indexes:
ifnot index.name:
index.set_name_with_model(cls)
#类准备完毕发送信号
class_prepared.send(sender=cls)