Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
3a47d42f
Kaydet (Commit)
3a47d42f
authored
Şub 18, 2016
tarafından
Loïc Bistuer
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #20932, #25897 -- Streamlined manager inheritance.
üst
9935f97c
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
116 additions
and
222 deletions
+116
-222
state.py
django/db/migrations/state.py
+1
-2
base.py
django/db/models/base.py
+2
-31
manager.py
django/db/models/manager.py
+47
-91
options.py
django/db/models/options.py
+27
-21
managers.txt
docs/topics/db/managers.txt
+17
-24
models.txt
docs/topics/db/models.txt
+11
-25
test_basic.py
tests/auth_tests/test_basic.py
+0
-13
models.py
tests/managers_regress/models.py
+1
-3
tests.py
tests/managers_regress/tests.py
+1
-1
tests.py
tests/many_to_one/tests.py
+2
-2
test_state.py
tests/migrations/test_state.py
+3
-5
tests.py
tests/one_to_one/tests.py
+4
-4
No files found.
django/db/migrations/state.py
Dosyayı görüntüle @
3a47d42f
...
@@ -500,8 +500,7 @@ class ModelState(object):
...
@@ -500,8 +500,7 @@ class ModelState(object):
else
:
else
:
# Force this manager to be the first and thus default
# Force this manager to be the first and thus default
managers_mapping
[
default_manager_name
]
=
(
0
,
models
.
Manager
())
managers_mapping
[
default_manager_name
]
=
(
0
,
models
.
Manager
())
# Sort all managers by their creation counter
for
manager
in
model
.
_meta
.
managers
:
for
_
,
manager
,
_
in
sorted
(
model
.
_meta
.
managers
):
if
manager
.
name
==
"_base_manager"
or
not
manager
.
use_in_migrations
:
if
manager
.
name
==
"_base_manager"
or
not
manager
.
use_in_migrations
:
continue
continue
reconstruct_manager
(
manager
)
reconstruct_manager
(
manager
)
...
...
django/db/models/base.py
Dosyayı görüntüle @
3a47d42f
...
@@ -151,18 +151,6 @@ class ModelBase(type):
...
@@ -151,18 +151,6 @@ class ModelBase(type):
if
is_proxy
and
base_meta
and
base_meta
.
swapped
:
if
is_proxy
and
base_meta
and
base_meta
.
swapped
:
raise
TypeError
(
"
%
s cannot proxy the swapped model '
%
s'."
%
(
name
,
base_meta
.
swapped
))
raise
TypeError
(
"
%
s cannot proxy the swapped model '
%
s'."
%
(
name
,
base_meta
.
swapped
))
if
getattr
(
new_class
,
'_default_manager'
,
None
):
if
not
is_proxy
:
# Multi-table inheritance doesn't inherit default manager from
# parents.
new_class
.
_default_manager
=
None
new_class
.
_base_manager
=
None
else
:
# Proxy classes do inherit parent's default manager, if none is
# set explicitly.
new_class
.
_default_manager
=
new_class
.
_default_manager
.
_copy_to_model
(
new_class
)
new_class
.
_base_manager
=
new_class
.
_base_manager
.
_copy_to_model
(
new_class
)
# Add all attributes to the class.
# Add all attributes to the class.
for
obj_name
,
obj
in
attrs
.
items
():
for
obj_name
,
obj
in
attrs
.
items
():
new_class
.
add_to_class
(
obj_name
,
obj
)
new_class
.
add_to_class
(
obj_name
,
obj
)
...
@@ -217,7 +205,6 @@ class ModelBase(type):
...
@@ -217,7 +205,6 @@ class ModelBase(type):
inherited_attributes
=
set
()
inherited_attributes
=
set
()
# Do the appropriate setup for any model parents.
# Do the appropriate setup for any model parents.
for
base
in
new_class
.
mro
():
for
base
in
new_class
.
mro
():
original_base
=
base
if
base
not
in
parents
or
not
hasattr
(
base
,
'_meta'
):
if
base
not
in
parents
or
not
hasattr
(
base
,
'_meta'
):
# Things without _meta aren't functional models, so they're
# Things without _meta aren't functional models, so they're
# uninteresting parents.
# uninteresting parents.
...
@@ -294,14 +281,6 @@ class ModelBase(type):
...
@@ -294,14 +281,6 @@ class ModelBase(type):
# Pass any non-abstract parent classes onto child.
# Pass any non-abstract parent classes onto child.
new_class
.
_meta
.
parents
.
update
(
base_parents
)
new_class
.
_meta
.
parents
.
update
(
base_parents
)
# Inherit managers from the abstract base classes.
new_class
.
copy_managers
(
base
.
_meta
.
abstract_managers
)
# Proxy models inherit the non-abstract managers from their base,
# unless they have redefined any of them.
if
is_proxy
:
new_class
.
copy_managers
(
original_base
.
_meta
.
concrete_managers
)
# Inherit private fields (like GenericForeignKey) from the parent
# Inherit private fields (like GenericForeignKey) from the parent
# class
# class
for
field
in
base
.
_meta
.
private_fields
:
for
field
in
base
.
_meta
.
private_fields
:
...
@@ -330,15 +309,6 @@ class ModelBase(type):
...
@@ -330,15 +309,6 @@ class ModelBase(type):
new_class
.
_meta
.
apps
.
register_model
(
new_class
.
_meta
.
app_label
,
new_class
)
new_class
.
_meta
.
apps
.
register_model
(
new_class
.
_meta
.
app_label
,
new_class
)
return
new_class
return
new_class
def
copy_managers
(
cls
,
base_managers
):
# This is in-place sorting of an Options attribute, but that's fine.
base_managers
.
sort
()
for
_
,
mgr_name
,
manager
in
base_managers
:
# NOQA (redefinition of _)
val
=
getattr
(
cls
,
mgr_name
,
None
)
if
not
val
or
val
is
manager
:
new_manager
=
manager
.
_copy_to_model
(
cls
)
cls
.
add_to_class
(
mgr_name
,
new_manager
)
def
add_to_class
(
cls
,
name
,
value
):
def
add_to_class
(
cls
,
name
,
value
):
# We should call the contribute_to_class method only if it's bound
# We should call the contribute_to_class method only if it's bound
if
not
inspect
.
isclass
(
value
)
and
hasattr
(
value
,
'contribute_to_class'
):
if
not
inspect
.
isclass
(
value
)
and
hasattr
(
value
,
'contribute_to_class'
):
...
@@ -376,6 +346,7 @@ class ModelBase(type):
...
@@ -376,6 +346,7 @@ class ModelBase(type):
setattr
(
cls
,
'get_absolute_url'
,
get_absolute_url_override
)
setattr
(
cls
,
'get_absolute_url'
,
get_absolute_url_override
)
ensure_default_manager
(
cls
)
ensure_default_manager
(
cls
)
signals
.
class_prepared
.
send
(
sender
=
cls
)
signals
.
class_prepared
.
send
(
sender
=
cls
)
...
@@ -1263,7 +1234,7 @@ class Model(six.with_metaclass(ModelBase)):
...
@@ -1263,7 +1234,7 @@ class Model(six.with_metaclass(ModelBase)):
""" Perform all manager checks. """
""" Perform all manager checks. """
errors
=
[]
errors
=
[]
for
__
,
manager
,
__
in
cls
.
_meta
.
managers
:
for
manager
in
cls
.
_meta
.
managers
:
errors
.
extend
(
manager
.
check
(
**
kwargs
))
errors
.
extend
(
manager
.
check
(
**
kwargs
))
return
errors
return
errors
...
...
django/db/models/manager.py
Dosyayı görüntüle @
3a47d42f
...
@@ -8,43 +8,40 @@ from django.utils import six
...
@@ -8,43 +8,40 @@ from django.utils import six
from
django.utils.encoding
import
python_2_unicode_compatible
from
django.utils.encoding
import
python_2_unicode_compatible
def
ensure_default_manager
(
cls
):
def
can_use_for_related_field
(
manager_class
):
return
manager_class
is
Manager
or
getattr
(
manager_class
,
'use_for_related_fields'
,
False
)
def
ensure_default_manager
(
model
):
"""
"""
Ensures that a Model subclass contains a default manager and sets the
Ensures that a Model subclass contains a default manager and sets the
_default_manager attribute on the class. Also sets up the _base_manager
_default_manager and _base_manager attributes on the class.
points to a plain Manager instance (which could be the same as
_default_manager if it's not a subclass of Manager).
"""
"""
if
cls
.
_meta
.
swapped
:
setattr
(
cls
,
'objects'
,
SwappedManagerDescriptor
(
cls
))
if
not
model
.
_meta
.
managers
:
return
if
any
(
f
.
name
==
'objects'
for
f
in
model
.
_meta
.
fields
):
if
not
getattr
(
cls
,
'_default_manager'
,
None
):
if
any
(
f
.
name
==
'objects'
for
f
in
cls
.
_meta
.
fields
):
raise
ValueError
(
raise
ValueError
(
"Model
%
s must specify a custom Manager, because it has a "
"Model
%
s must specify a custom Manager, because it has a "
"field named 'objects'"
%
cls
.
__name__
"field named 'objects'"
%
model
.
__name__
)
)
# Create the default manager, if needed.
model
.
add_to_class
(
'objects'
,
Manager
())
cls
.
add_to_class
(
'objects'
,
Manager
())
cls
.
_base_manager
=
cls
.
objects
model
.
_default_manager
=
model
.
_meta
.
managers
[
0
]
elif
not
getattr
(
cls
,
'_base_manager'
,
None
):
default_mgr
=
cls
.
_default_manager
.
__class__
# Just alias _base_manager if default manager is suitable.
if
(
default_mgr
is
Manager
or
if
can_use_for_related_field
(
model
.
_default_manager
.
__class__
):
getattr
(
default_mgr
,
"use_for_related_fields"
,
False
)):
model
.
_base_manager
=
model
.
_default_manager
cls
.
_base_manager
=
cls
.
_default_manager
# Otherwise search for a suitable manager type in the default manager MRO.
else
:
for
base_manager_class
in
model
.
_default_manager
.
__class__
.
mro
()[
1
:]:
if
can_use_for_related_field
(
base_manager_class
):
model
.
_base_manager
=
base_manager_class
()
model
.
_base_manager
.
name
=
'_base_manager'
model
.
_base_manager
.
model
=
model
break
else
:
else
:
# Default manager isn't a plain Manager class, or a suitable
raise
ValueError
(
"Could not find a suitable base manager."
)
# replacement, so we walk up the base class hierarchy until we hit
# something appropriate.
for
base_class
in
default_mgr
.
mro
()[
1
:]:
if
(
base_class
is
Manager
or
getattr
(
base_class
,
"use_for_related_fields"
,
False
)):
cls
.
add_to_class
(
'_base_manager'
,
base_class
())
return
raise
AssertionError
(
"Should never get here. Please report a bug, including your "
"model and model manager setup."
)
@python_2_unicode_compatible
@python_2_unicode_compatible
...
@@ -67,7 +64,6 @@ class BaseManager(object):
...
@@ -67,7 +64,6 @@ class BaseManager(object):
self
.
_set_creation_counter
()
self
.
_set_creation_counter
()
self
.
model
=
None
self
.
model
=
None
self
.
name
=
None
self
.
name
=
None
self
.
_inherited
=
False
self
.
_db
=
None
self
.
_db
=
None
self
.
_hints
=
{}
self
.
_hints
=
{}
...
@@ -150,26 +146,13 @@ class BaseManager(object):
...
@@ -150,26 +146,13 @@ class BaseManager(object):
return
type
(
class_name
,
(
cls
,),
class_dict
)
return
type
(
class_name
,
(
cls
,),
class_dict
)
def
contribute_to_class
(
self
,
model
,
name
):
def
contribute_to_class
(
self
,
model
,
name
):
# TODO: Use weakref because of possible memory leak / circular reference.
self
.
model
=
model
if
not
self
.
name
:
if
not
self
.
name
:
self
.
name
=
name
self
.
name
=
name
# Only contribute the manager if the model is concrete
self
.
model
=
model
if
model
.
_meta
.
abstract
:
setattr
(
model
,
name
,
AbstractManagerDescriptor
(
model
))
elif
model
.
_meta
.
swapped
:
setattr
(
model
,
name
,
SwappedManagerDescriptor
(
model
))
else
:
# if not model._meta.abstract and not model._meta.swapped:
setattr
(
model
,
name
,
ManagerDescriptor
(
self
))
if
(
not
getattr
(
model
,
'_default_manager'
,
None
)
or
self
.
creation_counter
<
model
.
_default_manager
.
creation_counter
):
model
.
_default_manager
=
self
abstract
=
False
setattr
(
model
,
name
,
ManagerDescriptor
(
self
))
if
model
.
_meta
.
abstract
or
(
self
.
_inherited
and
not
self
.
model
.
_meta
.
proxy
):
abstract
=
True
model
.
_meta
.
add_manager
(
self
)
model
.
_meta
.
managers
.
append
((
self
.
creation_counter
,
self
,
abstract
))
def
_set_creation_counter
(
self
):
def
_set_creation_counter
(
self
):
"""
"""
...
@@ -179,19 +162,6 @@ class BaseManager(object):
...
@@ -179,19 +162,6 @@ class BaseManager(object):
self
.
creation_counter
=
BaseManager
.
creation_counter
self
.
creation_counter
=
BaseManager
.
creation_counter
BaseManager
.
creation_counter
+=
1
BaseManager
.
creation_counter
+=
1
def
_copy_to_model
(
self
,
model
):
"""
Makes a copy of the manager and assigns it to 'model', which should be
a child of the existing model (used when inheriting a manager from an
abstract base class).
"""
assert
issubclass
(
model
,
self
.
model
)
mgr
=
copy
.
copy
(
self
)
mgr
.
_set_creation_counter
()
mgr
.
model
=
model
mgr
.
_inherited
=
True
return
mgr
def
db_manager
(
self
,
using
=
None
,
hints
=
None
):
def
db_manager
(
self
,
using
=
None
,
hints
=
None
):
obj
=
copy
.
copy
(
self
)
obj
=
copy
.
copy
(
self
)
obj
.
_db
=
using
or
self
.
_db
obj
.
_db
=
using
or
self
.
_db
...
@@ -240,43 +210,29 @@ class Manager(BaseManager.from_queryset(QuerySet)):
...
@@ -240,43 +210,29 @@ class Manager(BaseManager.from_queryset(QuerySet)):
class
ManagerDescriptor
(
object
):
class
ManagerDescriptor
(
object
):
# This class ensures managers aren't accessible via model instances.
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.
def
__init__
(
self
,
manager
):
def
__init__
(
self
,
manager
):
self
.
manager
=
manager
self
.
manager
=
manager
def
__get__
(
self
,
instance
,
cls
=
None
):
def
__get__
(
self
,
instance
,
cls
=
None
):
if
instance
is
not
None
:
if
instance
is
not
None
:
raise
AttributeError
(
"Manager isn't accessible via
%
s instances"
%
cls
.
__name__
)
raise
AttributeError
(
"Manager isn't accessible via
%
s instances"
%
cls
.
__name__
)
return
self
.
manager
class
AbstractManagerDescriptor
(
object
):
if
cls
.
_meta
.
abstract
:
# This class provides a better error message when you try to access a
raise
AttributeError
(
"Manager isn't available;
%
s is abstract"
%
(
# manager on an abstract model.
cls
.
_meta
.
object_name
,
def
__init__
(
self
,
model
):
))
self
.
model
=
model
if
cls
.
_meta
.
swapped
:
def
__get__
(
self
,
instance
,
cls
=
None
):
raise
AttributeError
(
raise
AttributeError
(
"Manager isn't available;
%
s is abstract"
%
(
"Manager isn't available; '
%
s.
%
s' has been swapped for '
%
s'"
%
(
self
.
model
.
_meta
.
object_name
,
cls
.
_meta
.
app_label
,
))
cls
.
_meta
.
object_name
,
cls
.
_meta
.
swapped
,
)
class
SwappedManagerDescriptor
(
object
):
# This class provides a better error message when you try to access a
# manager on a swapped model.
def
__init__
(
self
,
model
):
self
.
model
=
model
def
__get__
(
self
,
instance
,
cls
=
None
):
raise
AttributeError
(
"Manager isn't available; '
%
s.
%
s' has been swapped for '
%
s'"
%
(
self
.
model
.
_meta
.
app_label
,
self
.
model
.
_meta
.
object_name
,
self
.
model
.
_meta
.
swapped
,
)
)
)
return
cls
.
_meta
.
managers_map
[
self
.
manager
.
name
]
class
EmptyManager
(
Manager
):
class
EmptyManager
(
Manager
):
...
...
django/db/models/options.py
Dosyayı görüntüle @
3a47d42f
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
import
copy
import
warnings
import
warnings
from
bisect
import
bisect
from
bisect
import
bisect
from
collections
import
OrderedDict
,
defaultdict
from
collections
import
OrderedDict
,
defaultdict
...
@@ -73,7 +74,8 @@ def make_immutable_fields_list(name, data):
...
@@ -73,7 +74,8 @@ def make_immutable_fields_list(name, data):
@python_2_unicode_compatible
@python_2_unicode_compatible
class
Options
(
object
):
class
Options
(
object
):
FORWARD_PROPERTIES
=
{
'fields'
,
'many_to_many'
,
'concrete_fields'
,
FORWARD_PROPERTIES
=
{
'fields'
,
'many_to_many'
,
'concrete_fields'
,
'local_concrete_fields'
,
'_forward_fields_map'
}
'local_concrete_fields'
,
'_forward_fields_map'
,
'managers'
,
'managers_map'
}
REVERSE_PROPERTIES
=
{
'related_objects'
,
'fields_map'
,
'_relation_tree'
}
REVERSE_PROPERTIES
=
{
'related_objects'
,
'fields_map'
,
'_relation_tree'
}
default_apps
=
apps
default_apps
=
apps
...
@@ -83,6 +85,7 @@ class Options(object):
...
@@ -83,6 +85,7 @@ class Options(object):
self
.
local_fields
=
[]
self
.
local_fields
=
[]
self
.
local_many_to_many
=
[]
self
.
local_many_to_many
=
[]
self
.
private_fields
=
[]
self
.
private_fields
=
[]
self
.
local_managers
=
[]
self
.
model_name
=
None
self
.
model_name
=
None
self
.
verbose_name
=
None
self
.
verbose_name
=
None
self
.
verbose_name_plural
=
None
self
.
verbose_name_plural
=
None
...
@@ -122,12 +125,6 @@ class Options(object):
...
@@ -122,12 +125,6 @@ class Options(object):
self
.
parents
=
OrderedDict
()
self
.
parents
=
OrderedDict
()
self
.
auto_created
=
False
self
.
auto_created
=
False
# To handle various inheritance situations, we need to track where
# managers came from (concrete or abstract base classes). `managers`
# keeps a list of 3-tuples of the form:
# (creation_counter, instance, abstract(=True))
self
.
managers
=
[]
# List of all lookups defined in ForeignKey 'limit_choices_to' options
# List of all lookups defined in ForeignKey 'limit_choices_to' options
# from *other* models. Needed for some admin checks. Internal use only.
# from *other* models. Needed for some admin checks. Internal use only.
self
.
related_fkey_lookups
=
[]
self
.
related_fkey_lookups
=
[]
...
@@ -154,20 +151,6 @@ class Options(object):
...
@@ -154,20 +151,6 @@ class Options(object):
def
installed
(
self
):
def
installed
(
self
):
return
self
.
app_config
is
not
None
return
self
.
app_config
is
not
None
@property
def
abstract_managers
(
self
):
return
[
(
counter
,
instance
.
name
,
instance
)
for
counter
,
instance
,
abstract
in
self
.
managers
if
abstract
]
@property
def
concrete_managers
(
self
):
return
[
(
counter
,
instance
.
name
,
instance
)
for
counter
,
instance
,
abstract
in
self
.
managers
if
not
abstract
]
def
contribute_to_class
(
self
,
cls
,
name
):
def
contribute_to_class
(
self
,
cls
,
name
):
from
django.db
import
connection
from
django.db
import
connection
from
django.db.backends.utils
import
truncate_name
from
django.db.backends.utils
import
truncate_name
...
@@ -264,6 +247,10 @@ class Options(object):
...
@@ -264,6 +247,10 @@ class Options(object):
auto
=
AutoField
(
verbose_name
=
'ID'
,
primary_key
=
True
,
auto_created
=
True
)
auto
=
AutoField
(
verbose_name
=
'ID'
,
primary_key
=
True
,
auto_created
=
True
)
model
.
add_to_class
(
'id'
,
auto
)
model
.
add_to_class
(
'id'
,
auto
)
def
add_manager
(
self
,
manager
):
self
.
local_managers
.
append
(
manager
)
self
.
_expire_cache
()
def
add_field
(
self
,
field
,
private
=
False
,
virtual
=
NOT_PROVIDED
):
def
add_field
(
self
,
field
,
private
=
False
,
virtual
=
NOT_PROVIDED
):
if
virtual
is
not
NOT_PROVIDED
:
if
virtual
is
not
NOT_PROVIDED
:
warnings
.
warn
(
warnings
.
warn
(
...
@@ -371,6 +358,25 @@ class Options(object):
...
@@ -371,6 +358,25 @@ class Options(object):
return
swapped_for
return
swapped_for
return
None
return
None
@cached_property
def
managers
(
self
):
managers
=
[]
bases
=
(
b
for
b
in
self
.
model
.
mro
()
if
hasattr
(
b
,
'_meta'
))
for
depth
,
base
in
enumerate
(
bases
):
for
manager
in
base
.
_meta
.
local_managers
:
manager
=
copy
.
copy
(
manager
)
manager
.
model
=
self
.
model
managers
.
append
((
depth
,
manager
.
creation_counter
,
manager
))
return
make_immutable_fields_list
(
"managers"
,
(
m
[
2
]
for
m
in
sorted
(
managers
)),
)
@cached_property
def
managers_map
(
self
):
return
{
manager
.
name
:
manager
for
manager
in
reversed
(
self
.
managers
)}
@cached_property
@cached_property
def
fields
(
self
):
def
fields
(
self
):
"""
"""
...
...
docs/topics/db/managers.txt
Dosyayı görüntüle @
3a47d42f
...
@@ -321,33 +321,26 @@ You may also store the generated class into a variable::
...
@@ -321,33 +321,26 @@ You may also store the generated class into a variable::
Custom managers and model inheritance
Custom managers and model inheritance
-------------------------------------
-------------------------------------
Class inheritance and model managers aren't quite a perfect match for each
Here's how Django handles custom managers and
other. Managers are often specific to the classes they are defined on and
inheriting them in subclasses isn't necessarily a good idea. Also, because the
first manager declared is the *default manager*, it is important to allow that
to be controlled. So here's how Django handles custom managers and
:ref:`model inheritance <model-inheritance>`:
:ref:`model inheritance <model-inheritance>`:
1. Managers defined on non-abstract base classes are *not* inherited by
1. Managers from base classes are always inherited by the child class,
child classes. If you want to reuse a manager from a non-abstract base,
using Python's normal name resolution order (names on the child
redeclare it explicitly on the child class. These sorts of managers are
likely to be fairly specific to the class they are defined on, so
inheriting them can often lead to unexpected results (particularly as
far as the default manager goes). Therefore, they aren't passed onto
child classes.
2. Managers from abstract base classes are always inherited by the child
class, using Python's normal name resolution order (names on the child
class override all others; then come names on the first parent class,
class override all others; then come names on the first parent class,
and so on). Abstract base classes are designed to capture information
and so on).
and behavior that is common to their child classes. Defining common
managers is an appropriate part of this common information.
2. The default manager on a class is either the first manager declared on the
class, if that exists, or the default manager of the first parent class in
3. The default manager on a class is either the first manager declared on
the parent hierarchy, if that exists. If no manager is explicitly declared,
the class, if that exists, or the default manager of the first abstract
Django automatically creates the `objects` manager and it becomes the default
base class in the parent hierarchy, if that exists. If no default
manager.
manager is explicitly declared, Django's normal default manager is
used.
.. versionchanged:: 1.10
In older versions, manager inheritance varied depending on the type of
model inheritance (i.e. :ref:`abstract-base-classes`,
:ref:`multi-table-inheritance`, or :ref:`proxy-models`), especially
with regards to electing the default manager.
These rules provide the necessary flexibility if you want to install a
These rules provide the necessary flexibility if you want to install a
collection of custom managers on a group of models, via an abstract base
collection of custom managers on a group of models, via an abstract base
...
...
docs/topics/db/models.txt
Dosyayı görüntüle @
3a47d42f
...
@@ -1287,33 +1287,19 @@ Differences between proxy inheritance and unmanaged models
...
@@ -1287,33 +1287,19 @@ Differences between proxy inheritance and unmanaged models
Proxy model inheritance might look fairly similar to creating an unmanaged
Proxy model inheritance might look fairly similar to creating an unmanaged
model, using the :attr:`~django.db.models.Options.managed` attribute on a
model, using the :attr:`~django.db.models.Options.managed` attribute on a
model's ``Meta`` class. The two alternatives are not quite the same and it's
model's ``Meta`` class.
worth considering which one you should use.
With careful setting of :attr:`Meta.db_table
One difference is that you can (and, in fact, must unless you want an empty
<django.db.models.Options.db_table>` you could create an unmanaged model that
model) specify model fields on models with ``Meta.managed=False``. You could,
shadows an existing model and adds Python methods to it. However, that would be
with careful setting of :attr:`Meta.db_table
very repetitive and fragile as you need to keep both copies synchronized if you
<django.db.models.Options.db_table>` create an unmanaged model that shadowed
an existing model and add Python methods to it. However, that would be very
repetitive and fragile as you need to keep both copies synchronized if you
make any changes.
make any changes.
The other difference that is more important for proxy models, is how model
On the other hand, proxy models are intended to behave exactly like the model
managers are handled. Proxy models are intended to behave exactly like the
they are proxying for. They are always in sync with the parent model since they
model they are proxying for. So they inherit the parent model's managers,
directly inherit its fields and managers.
including the default manager. In the normal multi-table model inheritance
case, children do not inherit managers from their parents as the custom
The general rules are:
managers aren't always appropriate when extra fields are involved. The
:ref:`manager documentation <custom-managers-and-inheritance>` has more
details about this latter case.
When these two features were implemented, attempts were made to squash them
into a single option. It turned out that interactions with inheritance, in
general, and managers, in particular, made the API very complicated and
potentially difficult to understand and use. It turned out that two options
were needed in any case, so the current separation arose.
So, the general rules are:
1. If you are mirroring an existing model or database table and don't want
1. If you are mirroring an existing model or database table and don't want
all the original database table columns, use ``Meta.managed=False``.
all the original database table columns, use ``Meta.managed=False``.
...
...
tests/auth_tests/test_basic.py
Dosyayı görüntüle @
3a47d42f
...
@@ -3,29 +3,16 @@ from __future__ import unicode_literals
...
@@ -3,29 +3,16 @@ from __future__ import unicode_literals
import
warnings
import
warnings
from
django.apps
import
apps
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.models
import
AnonymousUser
,
User
from
django.contrib.auth.models
import
AnonymousUser
,
User
from
django.core.exceptions
import
ImproperlyConfigured
from
django.core.exceptions
import
ImproperlyConfigured
from
django.db
import
IntegrityError
from
django.db
import
IntegrityError
from
django.dispatch
import
receiver
from
django.test
import
TestCase
,
override_settings
from
django.test
import
TestCase
,
override_settings
from
django.test.signals
import
setting_changed
from
django.utils
import
translation
from
django.utils
import
translation
from
.models
import
CustomUser
from
.models
import
CustomUser
@receiver
(
setting_changed
)
def
user_model_swapped
(
**
kwargs
):
if
kwargs
[
'setting'
]
==
'AUTH_USER_MODEL'
:
from
django.db.models.manager
import
ensure_default_manager
# Reset User manager
setattr
(
User
,
'objects'
,
User
.
_default_manager
)
ensure_default_manager
(
User
)
apps
.
clear_cache
()
class
BasicTestCase
(
TestCase
):
class
BasicTestCase
(
TestCase
):
def
test_user
(
self
):
def
test_user
(
self
):
"Check that users can be created and can set their password"
"Check that users can be created and can set their password"
...
...
tests/managers_regress/models.py
Dosyayı görüntüle @
3a47d42f
...
@@ -115,14 +115,12 @@ class Child5(AbstractBase3):
...
@@ -115,14 +115,12 @@ class Child5(AbstractBase3):
return
self
.
name
return
self
.
name
# Will inherit managers from AbstractBase1, but not Child4.
class
Child6
(
Child4
):
class
Child6
(
Child4
):
value
=
models
.
IntegerField
()
value
=
models
.
IntegerField
()
# Will not inherit default manager from parent.
class
Child7
(
Parent
):
class
Child7
(
Parent
):
pass
objects
=
models
.
Manager
()
# RelatedManagers
# RelatedManagers
...
...
tests/managers_regress/tests.py
Dosyayı görüntüle @
3a47d42f
...
@@ -50,7 +50,7 @@ class ManagersRegressionTests(TestCase):
...
@@ -50,7 +50,7 @@ class ManagersRegressionTests(TestCase):
])
])
self
.
assertQuerysetEqual
(
Child4
.
manager1
.
all
(),
[
"<Child4: d1>"
,
"<Child4: f1>"
],
ordered
=
False
)
self
.
assertQuerysetEqual
(
Child4
.
manager1
.
all
(),
[
"<Child4: d1>"
,
"<Child4: f1>"
],
ordered
=
False
)
self
.
assertQuerysetEqual
(
Child5
.
_default_manager
.
all
(),
[
"<Child5: fred>"
])
self
.
assertQuerysetEqual
(
Child5
.
_default_manager
.
all
(),
[
"<Child5: fred>"
])
self
.
assertQuerysetEqual
(
Child6
.
_default_manager
.
all
(),
[
"<Child6: f1>"
]
)
self
.
assertQuerysetEqual
(
Child6
.
_default_manager
.
all
(),
[
"<Child6: f1>"
,
"<Child6: f2>"
],
ordered
=
False
)
self
.
assertQuerysetEqual
(
self
.
assertQuerysetEqual
(
Child7
.
_default_manager
.
order_by
(
'name'
),
Child7
.
_default_manager
.
order_by
(
'name'
),
[
"<Child7: barney>"
,
"<Child7: fred>"
]
[
"<Child7: barney>"
,
"<Child7: fred>"
]
...
...
tests/many_to_one/tests.py
Dosyayı görüntüle @
3a47d42f
...
@@ -600,13 +600,13 @@ class ManyToOneTests(TestCase):
...
@@ -600,13 +600,13 @@ class ManyToOneTests(TestCase):
# If the manager is marked "use_for_related_fields", it'll get used instead
# If the manager is marked "use_for_related_fields", it'll get used instead
# of the "bare" queryset. Usually you'd define this as a property on the class,
# of the "bare" queryset. Usually you'd define this as a property on the class,
# but this approximates that in a way that's easier in tests.
# but this approximates that in a way that's easier in tests.
School
.
objects
.
use_for_related_fields
=
True
School
.
_default_manager
.
use_for_related_fields
=
True
try
:
try
:
private_student
=
Student
.
objects
.
get
(
pk
=
private_student
.
pk
)
private_student
=
Student
.
objects
.
get
(
pk
=
private_student
.
pk
)
with
self
.
assertRaises
(
School
.
DoesNotExist
):
with
self
.
assertRaises
(
School
.
DoesNotExist
):
private_student
.
school
private_student
.
school
finally
:
finally
:
School
.
objects
.
use_for_related_fields
=
False
School
.
_default_manager
.
use_for_related_fields
=
False
def
test_hasattr_related_object
(
self
):
def
test_hasattr_related_object
(
self
):
# The exception raised on attribute access when a related object
# The exception raised on attribute access when a related object
...
...
tests/migrations/test_state.py
Dosyayı görüntüle @
3a47d42f
...
@@ -262,13 +262,11 @@ class StateTests(SimpleTestCase):
...
@@ -262,13 +262,11 @@ class StateTests(SimpleTestCase):
self
.
assertEqual
(
len
(
new_apps
.
get_model
(
"migrations"
,
"SubTag"
)
.
_meta
.
local_fields
),
2
)
self
.
assertEqual
(
len
(
new_apps
.
get_model
(
"migrations"
,
"SubTag"
)
.
_meta
.
local_fields
),
2
)
Food
=
new_apps
.
get_model
(
"migrations"
,
"Food"
)
Food
=
new_apps
.
get_model
(
"migrations"
,
"Food"
)
managers
=
sorted
(
Food
.
_meta
.
managers
)
self
.
assertEqual
([
mgr
.
name
for
mgr
in
Food
.
_meta
.
managers
],
self
.
assertEqual
([
mgr
.
name
for
_
,
mgr
,
_
in
managers
],
[
'default'
,
'food_mgr1'
,
'food_mgr2'
])
[
'default'
,
'food_mgr1'
,
'food_mgr2'
])
self
.
assertTrue
(
all
(
isinstance
(
mgr
.
name
,
six
.
text_type
)
for
_
,
mgr
,
_
in
managers
))
self
.
assertTrue
(
all
(
isinstance
(
mgr
.
name
,
six
.
text_type
)
for
mgr
in
Food
.
_meta
.
managers
))
self
.
assertEqual
([
mgr
.
__class__
for
_
,
mgr
,
_
in
managers
],
self
.
assertEqual
([
mgr
.
__class__
for
mgr
in
Food
.
_meta
.
managers
],
[
models
.
Manager
,
FoodManager
,
FoodManager
])
[
models
.
Manager
,
FoodManager
,
FoodManager
])
self
.
assertIs
(
managers
[
0
][
1
],
Food
.
_default_manager
)
def
test_render_model_inheritance
(
self
):
def
test_render_model_inheritance
(
self
):
class
Book
(
models
.
Model
):
class
Book
(
models
.
Model
):
...
...
tests/one_to_one/tests.py
Dosyayı görüntüle @
3a47d42f
...
@@ -457,21 +457,21 @@ class OneToOneTests(TestCase):
...
@@ -457,21 +457,21 @@ class OneToOneTests(TestCase):
# If the manager is marked "use_for_related_fields", it'll get used instead
# If the manager is marked "use_for_related_fields", it'll get used instead
# of the "bare" queryset. Usually you'd define this as a property on the class,
# of the "bare" queryset. Usually you'd define this as a property on the class,
# but this approximates that in a way that's easier in tests.
# but this approximates that in a way that's easier in tests.
School
.
objects
.
use_for_related_fields
=
True
School
.
_default_manager
.
use_for_related_fields
=
True
try
:
try
:
private_director
=
Director
.
_base_manager
.
get
(
pk
=
private_director
.
pk
)
private_director
=
Director
.
_base_manager
.
get
(
pk
=
private_director
.
pk
)
with
self
.
assertRaises
(
School
.
DoesNotExist
):
with
self
.
assertRaises
(
School
.
DoesNotExist
):
private_director
.
school
private_director
.
school
finally
:
finally
:
School
.
objects
.
use_for_related_fields
=
False
School
.
_default_manager
.
use_for_related_fields
=
False
Director
.
objects
.
use_for_related_fields
=
True
Director
.
_default_manager
.
use_for_related_fields
=
True
try
:
try
:
private_school
=
School
.
_base_manager
.
get
(
pk
=
private_school
.
pk
)
private_school
=
School
.
_base_manager
.
get
(
pk
=
private_school
.
pk
)
with
self
.
assertRaises
(
Director
.
DoesNotExist
):
with
self
.
assertRaises
(
Director
.
DoesNotExist
):
private_school
.
director
private_school
.
director
finally
:
finally
:
Director
.
objects
.
use_for_related_fields
=
False
Director
.
_default_manager
.
use_for_related_fields
=
False
def
test_hasattr_related_object
(
self
):
def
test_hasattr_related_object
(
self
):
# The exception raised on attribute access when a related object
# The exception raised on attribute access when a related object
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment