Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
django-taggit
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Wiki
Members
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
4b606c75
authored
Mar 24, 2014
by
Nicholas Serra
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
manager default to _TaggableManager in kwarg, swap class placement for import.
parent
e9b9de1b
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
146 additions
and
146 deletions
+146
-146
taggit/managers.py
+146
-146
No files found.
taggit/managers.py
View file @
4b606c75
...
@@ -69,16 +69,160 @@ class ExtraJoinRestriction(object):
...
@@ -69,16 +69,160 @@ class ExtraJoinRestriction(object):
return
self
.
__class__
(
self
.
alias
,
self
.
col
,
self
.
content_types
[:])
return
self
.
__class__
(
self
.
alias
,
self
.
col
,
self
.
content_types
[:])
class
_TaggableManager
(
models
.
Manager
):
def
__init__
(
self
,
through
,
model
,
instance
,
prefetch_cache_name
):
self
.
through
=
through
self
.
model
=
model
self
.
instance
=
instance
self
.
prefetch_cache_name
=
prefetch_cache_name
self
.
_db
=
None
def
is_cached
(
self
,
instance
):
return
self
.
prefetch_cache_name
in
instance
.
_prefetched_objects_cache
def
get_queryset
(
self
):
try
:
return
self
.
instance
.
_prefetched_objects_cache
[
self
.
prefetch_cache_name
]
except
(
AttributeError
,
KeyError
):
return
self
.
through
.
tags_for
(
self
.
model
,
self
.
instance
)
def
get_prefetch_queryset
(
self
,
instances
,
queryset
=
None
):
if
queryset
is
not
None
:
raise
ValueError
(
"Custom queryset can't be used for this lookup."
)
instance
=
instances
[
0
]
from
django.db
import
connections
db
=
self
.
_db
or
router
.
db_for_read
(
instance
.
__class__
,
instance
=
instance
)
fieldname
=
(
'object_id'
if
issubclass
(
self
.
through
,
GenericTaggedItemBase
)
else
'content_object'
)
fk
=
self
.
through
.
_meta
.
get_field
(
fieldname
)
query
=
{
'
%
s__
%
s__in'
%
(
self
.
through
.
tag_relname
(),
fk
.
name
)
:
set
(
obj
.
_get_pk_val
()
for
obj
in
instances
)
}
join_table
=
self
.
through
.
_meta
.
db_table
source_col
=
fk
.
column
connection
=
connections
[
db
]
qn
=
connection
.
ops
.
quote_name
qs
=
self
.
get_queryset
()
.
using
(
db
)
.
_next_is_sticky
()
.
filter
(
**
query
)
.
extra
(
select
=
{
'_prefetch_related_val'
:
'
%
s.
%
s'
%
(
qn
(
join_table
),
qn
(
source_col
))
}
)
return
(
qs
,
attrgetter
(
'_prefetch_related_val'
),
attrgetter
(
instance
.
_meta
.
pk
.
name
),
False
,
self
.
prefetch_cache_name
)
# Django < 1.6 uses the previous name of query_set
get_query_set
=
get_queryset
get_prefetch_query_set
=
get_prefetch_queryset
def
_lookup_kwargs
(
self
):
return
self
.
through
.
lookup_kwargs
(
self
.
instance
)
@require_instance_manager
def
add
(
self
,
*
tags
):
str_tags
=
set
([
t
for
t
in
tags
if
not
isinstance
(
t
,
self
.
through
.
tag_model
())
])
tag_objs
=
set
(
tags
)
-
str_tags
# If str_tags has 0 elements Django actually optimizes that to not do a
# query. Malcolm is very smart.
existing
=
self
.
through
.
tag_model
()
.
objects
.
filter
(
name__in
=
str_tags
)
tag_objs
.
update
(
existing
)
for
new_tag
in
str_tags
-
set
(
t
.
name
for
t
in
existing
):
tag_objs
.
add
(
self
.
through
.
tag_model
()
.
objects
.
create
(
name
=
new_tag
))
for
tag
in
tag_objs
:
self
.
through
.
objects
.
get_or_create
(
tag
=
tag
,
**
self
.
_lookup_kwargs
())
@require_instance_manager
def
names
(
self
):
return
self
.
get_queryset
()
.
values_list
(
'name'
,
flat
=
True
)
@require_instance_manager
def
slugs
(
self
):
return
self
.
get_queryset
()
.
values_list
(
'slug'
,
flat
=
True
)
@require_instance_manager
def
set
(
self
,
*
tags
):
self
.
clear
()
self
.
add
(
*
tags
)
@require_instance_manager
def
remove
(
self
,
*
tags
):
self
.
through
.
objects
.
filter
(
**
self
.
_lookup_kwargs
())
.
filter
(
tag__name__in
=
tags
)
.
delete
()
@require_instance_manager
def
clear
(
self
):
self
.
through
.
objects
.
filter
(
**
self
.
_lookup_kwargs
())
.
delete
()
def
most_common
(
self
):
return
self
.
get_queryset
()
.
annotate
(
num_times
=
models
.
Count
(
self
.
through
.
tag_relname
())
)
.
order_by
(
'-num_times'
)
@require_instance_manager
def
similar_objects
(
self
):
lookup_kwargs
=
self
.
_lookup_kwargs
()
lookup_keys
=
sorted
(
lookup_kwargs
)
qs
=
self
.
through
.
objects
.
values
(
*
six
.
iterkeys
(
lookup_kwargs
))
qs
=
qs
.
annotate
(
n
=
models
.
Count
(
'pk'
))
qs
=
qs
.
exclude
(
**
lookup_kwargs
)
qs
=
qs
.
filter
(
tag__in
=
self
.
all
())
qs
=
qs
.
order_by
(
'-n'
)
# TODO: This all feels like a bit of a hack.
items
=
{}
if
len
(
lookup_keys
)
==
1
:
# Can we do this without a second query by using a select_related()
# somehow?
f
=
self
.
through
.
_meta
.
get_field_by_name
(
lookup_keys
[
0
])[
0
]
objs
=
f
.
rel
.
to
.
_default_manager
.
filter
(
**
{
"
%
s__in"
%
f
.
rel
.
field_name
:
[
r
[
"content_object"
]
for
r
in
qs
]
})
for
obj
in
objs
:
items
[(
getattr
(
obj
,
f
.
rel
.
field_name
),)]
=
obj
else
:
preload
=
{}
for
result
in
qs
:
preload
.
setdefault
(
result
[
'content_type'
],
set
())
preload
[
result
[
"content_type"
]]
.
add
(
result
[
"object_id"
])
for
ct
,
obj_ids
in
preload
.
items
():
ct
=
ContentType
.
objects
.
get_for_id
(
ct
)
for
obj
in
ct
.
model_class
()
.
_default_manager
.
filter
(
pk__in
=
obj_ids
):
items
[(
ct
.
pk
,
obj
.
pk
)]
=
obj
results
=
[]
for
result
in
qs
:
obj
=
items
[
tuple
(
result
[
k
]
for
k
in
lookup_keys
)
]
obj
.
similar_tags
=
result
[
"n"
]
results
.
append
(
obj
)
return
results
class
TaggableManager
(
RelatedField
,
Field
):
class
TaggableManager
(
RelatedField
,
Field
):
_related_name_counter
=
0
_related_name_counter
=
0
def
__init__
(
self
,
verbose_name
=
_
(
"Tags"
),
help_text
=
_
(
"A comma-separated list of tags."
),
def
__init__
(
self
,
verbose_name
=
_
(
"Tags"
),
help_text
=
_
(
"A comma-separated list of tags."
),
through
=
None
,
blank
=
False
,
related_name
=
None
,
manager
=
None
):
through
=
None
,
blank
=
False
,
related_name
=
None
,
manager
=
_TaggableManager
):
Field
.
__init__
(
self
,
verbose_name
=
verbose_name
,
help_text
=
help_text
,
blank
=
blank
,
null
=
True
,
serialize
=
False
)
Field
.
__init__
(
self
,
verbose_name
=
verbose_name
,
help_text
=
help_text
,
blank
=
blank
,
null
=
True
,
serialize
=
False
)
self
.
through
=
through
or
TaggedItem
self
.
through
=
through
or
TaggedItem
self
.
rel
=
TaggableRel
(
self
,
related_name
,
self
.
through
)
self
.
rel
=
TaggableRel
(
self
,
related_name
,
self
.
through
)
self
.
swappable
=
False
self
.
swappable
=
False
self
.
manager
=
manager
or
_TaggableManager
self
.
manager
=
manager
def
__get__
(
self
,
instance
,
model
):
def
__get__
(
self
,
instance
,
model
):
if
instance
is
not
None
and
instance
.
pk
is
None
:
if
instance
is
not
None
and
instance
.
pk
is
None
:
...
@@ -286,150 +430,6 @@ class TaggableManager(RelatedField, Field):
...
@@ -286,150 +430,6 @@ class TaggableManager(RelatedField, Field):
return
[
self
.
related_fields
[
0
][
1
]]
return
[
self
.
related_fields
[
0
][
1
]]
class
_TaggableManager
(
models
.
Manager
):
def
__init__
(
self
,
through
,
model
,
instance
,
prefetch_cache_name
):
self
.
through
=
through
self
.
model
=
model
self
.
instance
=
instance
self
.
prefetch_cache_name
=
prefetch_cache_name
self
.
_db
=
None
def
is_cached
(
self
,
instance
):
return
self
.
prefetch_cache_name
in
instance
.
_prefetched_objects_cache
def
get_queryset
(
self
):
try
:
return
self
.
instance
.
_prefetched_objects_cache
[
self
.
prefetch_cache_name
]
except
(
AttributeError
,
KeyError
):
return
self
.
through
.
tags_for
(
self
.
model
,
self
.
instance
)
def
get_prefetch_queryset
(
self
,
instances
,
queryset
=
None
):
if
queryset
is
not
None
:
raise
ValueError
(
"Custom queryset can't be used for this lookup."
)
instance
=
instances
[
0
]
from
django.db
import
connections
db
=
self
.
_db
or
router
.
db_for_read
(
instance
.
__class__
,
instance
=
instance
)
fieldname
=
(
'object_id'
if
issubclass
(
self
.
through
,
GenericTaggedItemBase
)
else
'content_object'
)
fk
=
self
.
through
.
_meta
.
get_field
(
fieldname
)
query
=
{
'
%
s__
%
s__in'
%
(
self
.
through
.
tag_relname
(),
fk
.
name
)
:
set
(
obj
.
_get_pk_val
()
for
obj
in
instances
)
}
join_table
=
self
.
through
.
_meta
.
db_table
source_col
=
fk
.
column
connection
=
connections
[
db
]
qn
=
connection
.
ops
.
quote_name
qs
=
self
.
get_queryset
()
.
using
(
db
)
.
_next_is_sticky
()
.
filter
(
**
query
)
.
extra
(
select
=
{
'_prefetch_related_val'
:
'
%
s.
%
s'
%
(
qn
(
join_table
),
qn
(
source_col
))
}
)
return
(
qs
,
attrgetter
(
'_prefetch_related_val'
),
attrgetter
(
instance
.
_meta
.
pk
.
name
),
False
,
self
.
prefetch_cache_name
)
# Django < 1.6 uses the previous name of query_set
get_query_set
=
get_queryset
get_prefetch_query_set
=
get_prefetch_queryset
def
_lookup_kwargs
(
self
):
return
self
.
through
.
lookup_kwargs
(
self
.
instance
)
@require_instance_manager
def
add
(
self
,
*
tags
):
str_tags
=
set
([
t
for
t
in
tags
if
not
isinstance
(
t
,
self
.
through
.
tag_model
())
])
tag_objs
=
set
(
tags
)
-
str_tags
# If str_tags has 0 elements Django actually optimizes that to not do a
# query. Malcolm is very smart.
existing
=
self
.
through
.
tag_model
()
.
objects
.
filter
(
name__in
=
str_tags
)
tag_objs
.
update
(
existing
)
for
new_tag
in
str_tags
-
set
(
t
.
name
for
t
in
existing
):
tag_objs
.
add
(
self
.
through
.
tag_model
()
.
objects
.
create
(
name
=
new_tag
))
for
tag
in
tag_objs
:
self
.
through
.
objects
.
get_or_create
(
tag
=
tag
,
**
self
.
_lookup_kwargs
())
@require_instance_manager
def
names
(
self
):
return
self
.
get_queryset
()
.
values_list
(
'name'
,
flat
=
True
)
@require_instance_manager
def
slugs
(
self
):
return
self
.
get_queryset
()
.
values_list
(
'slug'
,
flat
=
True
)
@require_instance_manager
def
set
(
self
,
*
tags
):
self
.
clear
()
self
.
add
(
*
tags
)
@require_instance_manager
def
remove
(
self
,
*
tags
):
self
.
through
.
objects
.
filter
(
**
self
.
_lookup_kwargs
())
.
filter
(
tag__name__in
=
tags
)
.
delete
()
@require_instance_manager
def
clear
(
self
):
self
.
through
.
objects
.
filter
(
**
self
.
_lookup_kwargs
())
.
delete
()
def
most_common
(
self
):
return
self
.
get_queryset
()
.
annotate
(
num_times
=
models
.
Count
(
self
.
through
.
tag_relname
())
)
.
order_by
(
'-num_times'
)
@require_instance_manager
def
similar_objects
(
self
):
lookup_kwargs
=
self
.
_lookup_kwargs
()
lookup_keys
=
sorted
(
lookup_kwargs
)
qs
=
self
.
through
.
objects
.
values
(
*
six
.
iterkeys
(
lookup_kwargs
))
qs
=
qs
.
annotate
(
n
=
models
.
Count
(
'pk'
))
qs
=
qs
.
exclude
(
**
lookup_kwargs
)
qs
=
qs
.
filter
(
tag__in
=
self
.
all
())
qs
=
qs
.
order_by
(
'-n'
)
# TODO: This all feels like a bit of a hack.
items
=
{}
if
len
(
lookup_keys
)
==
1
:
# Can we do this without a second query by using a select_related()
# somehow?
f
=
self
.
through
.
_meta
.
get_field_by_name
(
lookup_keys
[
0
])[
0
]
objs
=
f
.
rel
.
to
.
_default_manager
.
filter
(
**
{
"
%
s__in"
%
f
.
rel
.
field_name
:
[
r
[
"content_object"
]
for
r
in
qs
]
})
for
obj
in
objs
:
items
[(
getattr
(
obj
,
f
.
rel
.
field_name
),)]
=
obj
else
:
preload
=
{}
for
result
in
qs
:
preload
.
setdefault
(
result
[
'content_type'
],
set
())
preload
[
result
[
"content_type"
]]
.
add
(
result
[
"object_id"
])
for
ct
,
obj_ids
in
preload
.
items
():
ct
=
ContentType
.
objects
.
get_for_id
(
ct
)
for
obj
in
ct
.
model_class
()
.
_default_manager
.
filter
(
pk__in
=
obj_ids
):
items
[(
ct
.
pk
,
obj
.
pk
)]
=
obj
results
=
[]
for
result
in
qs
:
obj
=
items
[
tuple
(
result
[
k
]
for
k
in
lookup_keys
)
]
obj
.
similar_tags
=
result
[
"n"
]
results
.
append
(
obj
)
return
results
def
_get_subclasses
(
model
):
def
_get_subclasses
(
model
):
subclasses
=
[
model
]
subclasses
=
[
model
]
for
f
in
model
.
_meta
.
get_all_field_names
():
for
f
in
model
.
_meta
.
get_all_field_names
():
...
...
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