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
599f3df1
authored
Jul 26, 2013
by
Florian Apolloner
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'akaariai/path_info_fix' into develop
parents
956dbc76
879c9c92
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
105 additions
and
4 deletions
+105
-4
docs/getting_started.txt
+2
-0
taggit/managers.py
+99
-3
tests/forms.py
+4
-0
tests/tests.py
+0
-1
No files found.
docs/getting_started.txt
View file @
599f3df1
...
...
@@ -9,6 +9,8 @@ To get started using ``django-taggit`` simply install it with
Add ``"taggit"`` to your project's ``INSTALLED_APPS`` setting.
Run `./manage.py syncdb` or `./manage.py migrate taggit` if using South.
And then to any model you want tagging on do the following::
from django.db import models
...
...
taggit/managers.py
View file @
599f3df1
...
...
@@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from
django.db
import
models
from
django.db.models.fields
import
Field
from
django.db.models.fields.related
import
ManyToManyRel
,
RelatedField
,
add_lazy_relation
from
django.db.models.related
import
RelatedObject
from
django.db.models.related
import
RelatedObject
,
PathInfo
from
django.utils.text
import
capfirst
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils
import
six
...
...
@@ -21,20 +21,46 @@ from taggit.utils import require_instance_manager
class
TaggableRel
(
ManyToManyRel
):
def
__init__
(
self
):
def
__init__
(
self
,
field
):
self
.
related_name
=
None
self
.
limit_choices_to
=
{}
self
.
symmetrical
=
True
self
.
multiple
=
True
self
.
through
=
None
self
.
field
=
field
def
get_joining_columns
(
self
):
return
self
.
field
.
get_reverse_joining_columns
()
def
get_extra_restriction
(
self
,
where_class
,
alias
,
related_alias
):
return
self
.
field
.
get_extra_restriction
(
where_class
,
related_alias
,
alias
)
class
ExtraJoinRestriction
(
object
):
"""
An extra restriction used for contenttype restriction in joins.
"""
def
__init__
(
self
,
alias
,
col
,
content_types
):
self
.
alias
=
alias
self
.
col
=
col
self
.
content_types
=
content_types
def
as_sql
(
self
,
qn
,
connection
):
if
len
(
self
.
content_types
)
==
1
:
extra_where
=
"
%
s.
%
s =
%%
s"
%
(
qn
(
self
.
alias
),
qn
(
self
.
col
))
params
=
[
self
.
content_types
[
0
]]
else
:
extra_where
=
"
%
s.
%
s IN (
%
s)"
%
(
qn
(
self
.
alias
),
qn
(
self
.
col
),
','
.
join
([
'
%
s'
]
*
len
(
self
.
content_types
)))
params
=
self
.
content_types
return
extra_where
,
params
class
TaggableManager
(
RelatedField
,
Field
):
def
__init__
(
self
,
verbose_name
=
_
(
"Tags"
),
help_text
=
_
(
"A comma-separated list of tags."
),
through
=
None
,
blank
=
False
):
Field
.
__init__
(
self
,
verbose_name
=
verbose_name
,
help_text
=
help_text
,
blank
=
blank
)
self
.
through
=
through
or
TaggedItem
self
.
rel
=
TaggableRel
()
self
.
rel
=
TaggableRel
(
self
)
def
__get__
(
self
,
instance
,
model
):
if
instance
is
not
None
and
instance
.
pk
is
None
:
...
...
@@ -70,6 +96,7 @@ class TaggableManager(RelatedField, Field):
return
False
def
post_through_setup
(
self
,
cls
):
self
.
related
=
RelatedObject
(
cls
,
self
.
model
,
self
)
self
.
use_gfk
=
(
self
.
through
is
None
or
issubclass
(
self
.
through
,
GenericTaggedItemBase
)
)
...
...
@@ -197,6 +224,72 @@ class TaggableManager(RelatedField, Field):
else
:
return
self
.
_get_mm_case_path_info
(
direct
=
False
)
# This and all the methods till the end of class are only used in django >= 1.6
def
_get_mm_case_path_info
(
self
,
direct
=
False
):
pathinfos
=
[]
linkfield1
=
self
.
through
.
_meta
.
get_field_by_name
(
'content_object'
)[
0
]
linkfield2
=
self
.
through
.
_meta
.
get_field_by_name
(
self
.
m2m_reverse_field_name
())[
0
]
if
direct
:
join1infos
=
linkfield1
.
get_reverse_path_info
()
join2infos
=
linkfield2
.
get_path_info
()
else
:
join1infos
=
linkfield2
.
get_reverse_path_info
()
join2infos
=
linkfield1
.
get_path_info
()
pathinfos
.
extend
(
join1infos
)
pathinfos
.
extend
(
join2infos
)
return
pathinfos
def
_get_gfk_case_path_info
(
self
,
direct
=
False
):
pathinfos
=
[]
from_field
=
self
.
model
.
_meta
.
pk
opts
=
self
.
through
.
_meta
object_id_field
=
opts
.
get_field_by_name
(
'object_id'
)[
0
]
linkfield
=
self
.
through
.
_meta
.
get_field_by_name
(
self
.
m2m_reverse_field_name
())[
0
]
if
direct
:
join1infos
=
[
PathInfo
(
self
.
model
.
_meta
,
opts
,
[
from_field
],
self
.
rel
,
True
,
False
)]
join2infos
=
linkfield
.
get_path_info
()
else
:
join1infos
=
linkfield
.
get_reverse_path_info
()
join2infos
=
[
PathInfo
(
opts
,
self
.
model
.
_meta
,
[
object_id_field
],
self
,
True
,
False
)]
pathinfos
.
extend
(
join1infos
)
pathinfos
.
extend
(
join2infos
)
return
pathinfos
def
get_path_info
(
self
):
if
self
.
use_gfk
:
return
self
.
_get_gfk_case_path_info
(
direct
=
True
)
else
:
return
self
.
_get_mm_case_path_info
(
direct
=
True
)
def
get_reverse_path_info
(
self
):
if
self
.
use_gfk
:
return
self
.
_get_gfk_case_path_info
(
direct
=
False
)
else
:
return
self
.
_get_mm_case_path_info
(
direct
=
False
)
def
get_joining_columns
(
self
,
reverse_join
=
False
):
if
reverse_join
:
return
((
"id"
,
"object_id"
),)
else
:
return
((
"object_id"
,
"id"
),)
def
get_extra_restriction
(
self
,
where_class
,
alias
,
related_alias
):
extra_col
=
self
.
through
.
_meta
.
get_field_by_name
(
'content_type'
)[
0
]
.
column
content_type_ids
=
[
ContentType
.
objects
.
get_for_model
(
subclass
)
.
pk
for
subclass
in
_get_subclasses
(
self
.
model
)]
return
ExtraJoinRestriction
(
related_alias
,
extra_col
,
content_type_ids
)
def
get_reverse_joining_columns
(
self
):
return
self
.
get_joining_columns
(
reverse_join
=
True
)
@property
def
related_fields
(
self
):
return
[(
self
.
through
.
_meta
.
get_field_by_name
(
'object_id'
)[
0
],
self
.
model
.
_meta
.
pk
)]
@property
def
foreign_related_fields
(
self
):
return
[
self
.
related_fields
[
0
][
1
]]
class
_TaggableManager
(
models
.
Manager
):
def
__init__
(
self
,
through
,
model
,
instance
):
...
...
@@ -207,6 +300,9 @@ class _TaggableManager(models.Manager):
def
get_query_set
(
self
):
return
self
.
through
.
tags_for
(
self
.
model
,
self
.
instance
)
# Django 1.6 renamed this
get_queryset
=
get_query_set
def
_lookup_kwargs
(
self
):
return
self
.
through
.
lookup_kwargs
(
self
.
instance
)
...
...
tests/forms.py
View file @
599f3df1
...
...
@@ -8,15 +8,19 @@ from .models import Food, DirectFood, CustomPKFood, OfficialFood
class
FoodForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Food
fields
=
'__all__'
class
DirectFoodForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
DirectFood
fields
=
'__all__'
class
CustomPKFoodForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
CustomPKFood
fields
=
'__all__'
class
OfficialFoodForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
OfficialFood
fields
=
'__all__'
tests/tests.py
View file @
599f3df1
...
...
@@ -190,7 +190,6 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
apple
.
tags
.
add
(
"red"
,
"green"
)
pear
=
self
.
food_model
.
objects
.
create
(
name
=
"pear"
)
pear
.
tags
.
add
(
"green"
)
self
.
assertEqual
(
list
(
self
.
food_model
.
objects
.
filter
(
tags__name__in
=
[
"red"
])),
[
apple
]
...
...
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