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
04a2a6b0
Kaydet (Commit)
04a2a6b0
authored
Eyl 18, 2013
tarafından
Loic Bistuer
Kaydeden (comit)
Anssi Kääriäinen
Eyl 25, 2013
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #3871 -- Custom managers when traversing reverse relations.
üst
83554b01
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
213 additions
and
42 deletions
+213
-42
generic.py
django/contrib/contenttypes/generic.py
+17
-0
related.py
django/db/models/fields/related.py
+59
-31
1.7.txt
docs/releases/1.7.txt
+6
-0
queries.txt
docs/topics/db/queries.txt
+25
-0
models.py
tests/custom_managers/models.py
+20
-0
tests.py
tests/custom_managers/tests.py
+86
-11
No files found.
django/contrib/contenttypes/generic.py
Dosyayı görüntüle @
04a2a6b0
...
...
@@ -319,6 +319,23 @@ def create_generic_related_manager(superclass):
'
%
s__exact'
%
object_id_field_name
:
instance
.
_get_pk_val
(),
}
def
__call__
(
self
,
**
kwargs
):
# We use **kwargs rather than a kwarg argument to enforce the
# `manager='manager_name'` syntax.
manager
=
getattr
(
self
.
model
,
kwargs
.
pop
(
'manager'
))
manager_class
=
create_generic_related_manager
(
manager
.
__class__
)
return
manager_class
(
model
=
self
.
model
,
instance
=
self
.
instance
,
symmetrical
=
self
.
symmetrical
,
source_col_name
=
self
.
source_col_name
,
target_col_name
=
self
.
target_col_name
,
content_type
=
self
.
content_type
,
content_type_field_name
=
self
.
content_type_field_name
,
object_id_field_name
=
self
.
object_id_field_name
,
prefetch_cache_name
=
self
.
prefetch_cache_name
,
)
def
get_queryset
(
self
):
try
:
return
self
.
instance
.
_prefetched_objects_cache
[
self
.
prefetch_cache_name
]
...
...
django/db/models/fields/related.py
Dosyayı görüntüle @
04a2a6b0
...
...
@@ -365,37 +365,7 @@ class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjec
setattr
(
value
,
self
.
field
.
related
.
get_cache_name
(),
instance
)
class
ForeignRelatedObjectsDescriptor
(
object
):
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# multiple "remote" values and have a ForeignKey pointed at them by
# some other model. In the example "poll.choice_set", the choice_set
# attribute is a ForeignRelatedObjectsDescriptor instance.
def
__init__
(
self
,
related
):
self
.
related
=
related
# RelatedObject instance
def
__get__
(
self
,
instance
,
instance_type
=
None
):
if
instance
is
None
:
return
self
return
self
.
related_manager_cls
(
instance
)
def
__set__
(
self
,
instance
,
value
):
manager
=
self
.
__get__
(
instance
)
# If the foreign key can support nulls, then completely clear the related set.
# Otherwise, just move the named objects into the set.
if
self
.
related
.
field
.
null
:
manager
.
clear
()
manager
.
add
(
*
value
)
@cached_property
def
related_manager_cls
(
self
):
# Dynamically create a class that subclasses the related model's default
# manager.
superclass
=
self
.
related
.
model
.
_default_manager
.
__class__
rel_field
=
self
.
related
.
field
rel_model
=
self
.
related
.
model
def
create_foreign_related_manager
(
superclass
,
rel_field
,
rel_model
):
class
RelatedManager
(
superclass
):
def
__init__
(
self
,
instance
):
super
(
RelatedManager
,
self
)
.
__init__
()
...
...
@@ -403,6 +373,13 @@ class ForeignRelatedObjectsDescriptor(object):
self
.
core_filters
=
{
'
%
s__exact'
%
rel_field
.
name
:
instance
}
self
.
model
=
rel_model
def
__call__
(
self
,
**
kwargs
):
# We use **kwargs rather than a kwarg argument to enforce the
# `manager='manager_name'` syntax.
manager
=
getattr
(
self
.
model
,
kwargs
.
pop
(
'manager'
))
manager_class
=
create_foreign_related_manager
(
manager
.
__class__
,
rel_field
,
rel_model
)
return
manager_class
(
self
.
instance
)
def
get_queryset
(
self
):
try
:
return
self
.
instance
.
_prefetched_objects_cache
[
rel_field
.
related_query_name
()]
...
...
@@ -474,6 +451,40 @@ class ForeignRelatedObjectsDescriptor(object):
return
RelatedManager
class
ForeignRelatedObjectsDescriptor
(
object
):
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# multiple "remote" values and have a ForeignKey pointed at them by
# some other model. In the example "poll.choice_set", the choice_set
# attribute is a ForeignRelatedObjectsDescriptor instance.
def
__init__
(
self
,
related
):
self
.
related
=
related
# RelatedObject instance
def
__get__
(
self
,
instance
,
instance_type
=
None
):
if
instance
is
None
:
return
self
return
self
.
related_manager_cls
(
instance
)
def
__set__
(
self
,
instance
,
value
):
manager
=
self
.
__get__
(
instance
)
# If the foreign key can support nulls, then completely clear the related set.
# Otherwise, just move the named objects into the set.
if
self
.
related
.
field
.
null
:
manager
.
clear
()
manager
.
add
(
*
value
)
@cached_property
def
related_manager_cls
(
self
):
# Dynamically create a class that subclasses the related model's default
# manager.
return
create_foreign_related_manager
(
self
.
related
.
model
.
_default_manager
.
__class__
,
self
.
related
.
field
,
self
.
related
.
model
,
)
def
create_many_related_manager
(
superclass
,
rel
):
"""Creates a manager that subclasses 'superclass' (which is a Manager)
and adds behavior for many-to-many related objects."""
...
...
@@ -513,6 +524,23 @@ def create_many_related_manager(superclass, rel):
"a many-to-many relationship can be used."
%
instance
.
__class__
.
__name__
)
def
__call__
(
self
,
**
kwargs
):
# We use **kwargs rather than a kwarg argument to enforce the
# `manager='manager_name'` syntax.
manager
=
getattr
(
self
.
model
,
kwargs
.
pop
(
'manager'
))
manager_class
=
create_many_related_manager
(
manager
.
__class__
,
rel
)
return
manager_class
(
model
=
self
.
model
,
query_field_name
=
self
.
query_field_name
,
instance
=
self
.
instance
,
symmetrical
=
self
.
symmetrical
,
source_field_name
=
self
.
source_field_name
,
target_field_name
=
self
.
target_field_name
,
reverse
=
self
.
reverse
,
through
=
self
.
through
,
prefetch_cache_name
=
self
.
prefetch_cache_name
,
)
def
get_queryset
(
self
):
try
:
return
self
.
instance
.
_prefetched_objects_cache
[
self
.
prefetch_cache_name
]
...
...
docs/releases/1.7.txt
Dosyayı görüntüle @
04a2a6b0
...
...
@@ -92,6 +92,12 @@ The :meth:`QuerySet.as_manager() <django.db.models.query.QuerySet.as_manager>`
class method has been added to :ref:`create Manager with QuerySet methods
<create-manager-with-queryset-methods>`.
Using a custom manager when traversing reverse relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is now possible to :ref:`specify a custom manager
<using-custom-reverse-manager>` when traversing a reverse relationship.
Admin shortcuts support time zones
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
...
docs/topics/db/queries.txt
Dosyayı görüntüle @
04a2a6b0
...
...
@@ -1136,6 +1136,31 @@ above example code would look like this::
>>> b.entries.filter(headline__contains='Lennon')
>>> b.entries.count()
.. _using-custom-reverse-manager:
Using a custom reverse manager
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.7
By default the :class:`~django.db.models.fields.related.RelatedManager` used
for reverse relations is a subclass of the :ref:`default manager <manager-names>`
for that model. If you would like to specify a different manager for a given
query you can use the following syntax::
from django.db import models
class Entry(models.Model):
#...
objects = models.Manager() # Default Manager
entries = EntryManager() # Custom Manager
>>> b = Blog.objects.get(id=1)
>>> b.entry_set(manager='entries').all()
Additional methods to handle related objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In addition to the :class:`~django.db.models.query.QuerySet` methods defined in
"Retrieving objects" above, the :class:`~django.db.models.ForeignKey`
:class:`~django.db.models.Manager` has additional methods used to handle the
...
...
tests/custom_managers/models.py
Dosyayı görüntüle @
04a2a6b0
...
...
@@ -11,6 +11,7 @@ returns.
from
__future__
import
unicode_literals
from
django.contrib.contenttypes
import
generic
from
django.db
import
models
from
django.utils.encoding
import
python_2_unicode_compatible
...
...
@@ -63,12 +64,28 @@ class BaseCustomManager(models.Manager):
CustomManager
=
BaseCustomManager
.
from_queryset
(
CustomQuerySet
)
class
FunPeopleManager
(
models
.
Manager
):
def
get_queryset
(
self
):
return
super
(
FunPeopleManager
,
self
)
.
get_queryset
()
.
filter
(
fun
=
True
)
class
BoringPeopleManager
(
models
.
Manager
):
def
get_queryset
(
self
):
return
super
(
BoringPeopleManager
,
self
)
.
get_queryset
()
.
filter
(
fun
=
False
)
@python_2_unicode_compatible
class
Person
(
models
.
Model
):
first_name
=
models
.
CharField
(
max_length
=
30
)
last_name
=
models
.
CharField
(
max_length
=
30
)
fun
=
models
.
BooleanField
(
default
=
False
)
favorite_book
=
models
.
ForeignKey
(
'Book'
,
null
=
True
,
related_name
=
'favorite_books'
)
favorite_thing_type
=
models
.
ForeignKey
(
'contenttypes.ContentType'
,
null
=
True
)
favorite_thing_id
=
models
.
IntegerField
(
null
=
True
)
favorite_thing
=
generic
.
GenericForeignKey
(
'favorite_thing_type'
,
'favorite_thing_id'
)
objects
=
PersonManager
()
fun_people
=
FunPeopleManager
()
boring_people
=
BoringPeopleManager
()
custom_queryset_default_manager
=
CustomQuerySet
.
as_manager
()
custom_queryset_custom_manager
=
CustomManager
(
'hello'
)
...
...
@@ -84,6 +101,9 @@ class Book(models.Model):
published_objects
=
PublishedBookManager
()
authors
=
models
.
ManyToManyField
(
Person
,
related_name
=
'books'
)
favorite_things
=
generic
.
GenericRelation
(
Person
,
content_type_field
=
'favorite_thing_type'
,
object_id_field
=
'favorite_thing_id'
)
def
__str__
(
self
):
return
self
.
title
...
...
tests/custom_managers/tests.py
Dosyayı görüntüle @
04a2a6b0
...
...
@@ -7,10 +7,15 @@ from .models import Person, Book, Car, PersonManager, PublishedBookManager
class
CustomManagerTests
(
TestCase
):
def
test_manager
(
self
):
Person
.
objects
.
create
(
first_name
=
"Bugs"
,
last_name
=
"Bunny"
,
fun
=
True
)
p2
=
Person
.
objects
.
create
(
first_name
=
"Droopy"
,
last_name
=
"Dog"
,
fun
=
False
)
def
setUp
(
self
):
self
.
b1
=
Book
.
published_objects
.
create
(
title
=
"How to program"
,
author
=
"Rodney Dangerfield"
,
is_published
=
True
)
self
.
b2
=
Book
.
published_objects
.
create
(
title
=
"How to be smart"
,
author
=
"Albert Einstein"
,
is_published
=
False
)
self
.
p1
=
Person
.
objects
.
create
(
first_name
=
"Bugs"
,
last_name
=
"Bunny"
,
fun
=
True
)
self
.
p2
=
Person
.
objects
.
create
(
first_name
=
"Droopy"
,
last_name
=
"Dog"
,
fun
=
False
)
def
test_manager
(
self
):
# Test a custom `Manager` method.
self
.
assertQuerysetEqual
(
Person
.
objects
.
get_fun_people
(),
[
...
...
@@ -61,14 +66,8 @@ class CustomManagerTests(TestCase):
# The RelatedManager used on the 'books' descriptor extends the default
# manager
self
.
assertIsInstance
(
p2
.
books
,
PublishedBookManager
)
self
.
assertIsInstance
(
self
.
p2
.
books
,
PublishedBookManager
)
Book
.
published_objects
.
create
(
title
=
"How to program"
,
author
=
"Rodney Dangerfield"
,
is_published
=
True
)
b2
=
Book
.
published_objects
.
create
(
title
=
"How to be smart"
,
author
=
"Albert Einstein"
,
is_published
=
False
)
# The default manager, "objects", doesn't exist, because a custom one
# was provided.
...
...
@@ -76,7 +75,7 @@ class CustomManagerTests(TestCase):
# The RelatedManager used on the 'authors' descriptor extends the
# default manager
self
.
assertIsInstance
(
b2
.
authors
,
PersonManager
)
self
.
assertIsInstance
(
self
.
b2
.
authors
,
PersonManager
)
self
.
assertQuerysetEqual
(
Book
.
published_objects
.
all
(),
[
...
...
@@ -114,3 +113,79 @@ class CustomManagerTests(TestCase):
],
lambda
c
:
c
.
name
)
def
test_related_manager_fk
(
self
):
self
.
p1
.
favorite_book
=
self
.
b1
self
.
p1
.
save
()
self
.
p2
.
favorite_book
=
self
.
b1
self
.
p2
.
save
()
self
.
assertQuerysetEqual
(
self
.
b1
.
favorite_books
.
order_by
(
'first_name'
)
.
all
(),
[
"Bugs"
,
"Droopy"
,
],
lambda
c
:
c
.
first_name
)
self
.
assertQuerysetEqual
(
self
.
b1
.
favorite_books
(
manager
=
'boring_people'
)
.
all
(),
[
"Droopy"
,
],
lambda
c
:
c
.
first_name
)
self
.
assertQuerysetEqual
(
self
.
b1
.
favorite_books
(
manager
=
'fun_people'
)
.
all
(),
[
"Bugs"
,
],
lambda
c
:
c
.
first_name
)
def
test_related_manager_gfk
(
self
):
self
.
p1
.
favorite_thing
=
self
.
b1
self
.
p1
.
save
()
self
.
p2
.
favorite_thing
=
self
.
b1
self
.
p2
.
save
()
self
.
assertQuerysetEqual
(
self
.
b1
.
favorite_things
.
order_by
(
'first_name'
)
.
all
(),
[
"Bugs"
,
"Droopy"
,
],
lambda
c
:
c
.
first_name
)
self
.
assertQuerysetEqual
(
self
.
b1
.
favorite_things
(
manager
=
'boring_people'
)
.
all
(),
[
"Droopy"
,
],
lambda
c
:
c
.
first_name
)
self
.
assertQuerysetEqual
(
self
.
b1
.
favorite_things
(
manager
=
'fun_people'
)
.
all
(),
[
"Bugs"
,
],
lambda
c
:
c
.
first_name
)
def
test_related_manager_m2m
(
self
):
self
.
b1
.
authors
.
add
(
self
.
p1
)
self
.
b1
.
authors
.
add
(
self
.
p2
)
self
.
assertQuerysetEqual
(
self
.
b1
.
authors
.
order_by
(
'first_name'
)
.
all
(),
[
"Bugs"
,
"Droopy"
,
],
lambda
c
:
c
.
first_name
)
self
.
assertQuerysetEqual
(
self
.
b1
.
authors
(
manager
=
'boring_people'
)
.
all
(),
[
"Droopy"
,
],
lambda
c
:
c
.
first_name
)
self
.
assertQuerysetEqual
(
self
.
b1
.
authors
(
manager
=
'fun_people'
)
.
all
(),
[
"Bugs"
,
],
lambda
c
:
c
.
first_name
)
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