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
543471cd
authored
Sep 07, 2010
by
Alex Gaynor
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote branch 'origin/master'
parents
377bb478
18566407
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
55 additions
and
61 deletions
+55
-61
taggit/forms.py
+1
-1
taggit/managers.py
+6
-12
taggit/models.py
+6
-6
taggit/tests/models.py
+9
-9
taggit/tests/tests.py
+33
-33
No files found.
taggit/forms.py
View file @
543471cd
...
...
@@ -12,7 +12,7 @@ class TagWidget(forms.TextInput):
class
TagField
(
forms
.
CharField
):
widget
=
TagWidget
def
clean
(
self
,
value
):
try
:
return
parse_tags
(
value
)
...
...
taggit/managers.py
View file @
543471cd
from
django.contrib.contenttypes.generic
import
GenericRelation
from
django.contrib.contenttypes.models
import
ContentType
from
django.db
import
models
from
django.db.models.fields.related
import
ManyToManyRel
from
django.db.models.fields.related
import
ManyToManyRel
,
RelatedField
from
django.db.models.related
import
RelatedObject
from
django.utils.translation
import
ugettext_lazy
as
_
from
taggit.forms
import
TagField
from
taggit.models
import
Tag
,
Tag
gedItem
,
GenericTaggedItemBase
from
taggit.models
import
TaggedItem
,
GenericTaggedItemBase
from
taggit.utils
import
require_instance_manager
...
...
@@ -35,7 +35,7 @@ class TaggableRel(ManyToManyRel):
self
.
through
=
None
class
TaggableManager
(
object
):
class
TaggableManager
(
RelatedField
):
def
__init__
(
self
,
verbose_name
=
_
(
"Tags"
),
through
=
None
):
self
.
use_gfk
=
through
is
None
or
issubclass
(
through
,
GenericTaggedItemBase
)
self
.
through
=
through
or
TaggedItem
...
...
@@ -71,12 +71,6 @@ class TaggableManager(object):
def
save_form_data
(
self
,
instance
,
value
):
getattr
(
instance
,
self
.
name
)
.
set
(
*
value
)
def
get_prep_lookup
(
self
,
lookup_type
,
value
):
return
models
.
Field
()
.
get_prep_lookup
(
lookup_type
,
value
)
def
get_db_prep_lookup
(
self
,
*
args
,
**
kwargs
):
return
models
.
Field
()
.
get_db_prep_lookup
(
*
args
,
**
kwargs
)
def
formfield
(
self
,
form_class
=
TagField
,
**
kwargs
):
defaults
=
{
...
...
@@ -121,13 +115,13 @@ class TaggableManager(object):
class
_TaggableManager
(
models
.
Manager
):
def
__init__
(
self
,
through
):
self
.
through
=
through
def
get_query_set
(
self
):
return
self
.
through
.
tags_for
(
self
.
model
,
self
.
instance
)
def
_lookup_kwargs
(
self
):
return
self
.
through
.
lookup_kwargs
(
self
.
instance
)
@require_instance_manager
def
add
(
self
,
*
tags
):
for
tag
in
tags
:
...
...
@@ -163,7 +157,7 @@ class _TaggableManager(models.Manager):
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
:
...
...
taggit/models.py
View file @
543471cd
...
...
@@ -9,13 +9,13 @@ from django.utils.translation import ugettext_lazy as _, ugettext
class
TagBase
(
models
.
Model
):
name
=
models
.
CharField
(
verbose_name
=
_
(
'Name'
),
max_length
=
100
)
slug
=
models
.
SlugField
(
verbose_name
=
_
(
'Slug'
),
unique
=
True
,
max_length
=
100
)
def
__unicode__
(
self
):
return
self
.
name
class
Meta
:
abstract
=
True
def
save
(
self
,
*
args
,
**
kwargs
):
if
not
self
.
pk
and
not
self
.
slug
:
self
.
slug
=
slug
=
slugify
(
self
.
name
)
...
...
@@ -57,7 +57,7 @@ class ItemBase(models.Model):
"object"
:
self
.
content_object
,
"tag"
:
self
.
tag
}
class
Meta
:
abstract
=
True
...
...
@@ -81,7 +81,7 @@ class TaggedItemBase(ItemBase):
tag
=
models
.
ForeignKey
(
Tag
,
related_name
=
"
%(class)
s_items"
)
else
:
tag
=
models
.
ForeignKey
(
Tag
,
related_name
=
"
%(app_label)
s_
%(class)
s_items"
)
class
Meta
:
abstract
=
True
...
...
@@ -114,7 +114,7 @@ class GenericTaggedItemBase(ItemBase):
class
Meta
:
abstract
=
True
@classmethod
def
lookup_kwargs
(
cls
,
instance
):
return
{
...
...
taggit/tests/models.py
View file @
543471cd
...
...
@@ -6,17 +6,17 @@ from taggit.models import TaggedItemBase, GenericTaggedItemBase, TagBase
class
Food
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
50
)
tags
=
TaggableManager
()
def
__unicode__
(
self
):
return
self
.
name
class
Pet
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
50
)
tags
=
TaggableManager
()
def
__unicode__
(
self
):
return
self
.
name
...
...
@@ -41,7 +41,7 @@ class DirectPet(models.Model):
name
=
models
.
CharField
(
max_length
=
50
)
tags
=
TaggableManager
(
through
=
TaggedPet
)
def
__unicode__
(
self
):
return
self
.
name
...
...
@@ -61,7 +61,7 @@ class CustomPKFood(models.Model):
name
=
models
.
CharField
(
max_length
=
50
,
primary_key
=
True
)
tags
=
TaggableManager
(
through
=
TaggedCustomPKFood
)
def
__unicode__
(
self
):
return
self
.
name
...
...
@@ -69,7 +69,7 @@ class CustomPKPet(models.Model):
name
=
models
.
CharField
(
max_length
=
50
,
primary_key
=
True
)
tags
=
TaggableManager
(
through
=
TaggedCustomPKPet
)
def
__unicode__
(
self
):
return
self
.
name
...
...
@@ -88,7 +88,7 @@ class OfficialFood(models.Model):
name
=
models
.
CharField
(
max_length
=
50
)
tags
=
TaggableManager
(
through
=
OfficialThroughModel
)
def
__unicode__
(
self
):
return
self
.
name
...
...
@@ -96,7 +96,7 @@ class OfficialPet(models.Model):
name
=
models
.
CharField
(
max_length
=
50
)
tags
=
TaggableManager
(
through
=
OfficialThroughModel
)
def
__unicode__
(
self
):
return
self
.
name
...
...
taggit/tests/tests.py
View file @
543471cd
...
...
@@ -7,7 +7,7 @@ from taggit.tests.forms import (FoodForm, DirectFoodForm, CustomPKFoodForm,
OfficialFoodForm
)
from
taggit.tests.models
import
(
Food
,
Pet
,
HousePet
,
DirectFood
,
DirectPet
,
DirectHousePet
,
TaggedPet
,
CustomPKFood
,
CustomPKPet
,
CustomPKHousePet
,
TaggedCustomPKPet
,
OfficialFood
,
OfficialPet
,
OfficialHousePet
,
TaggedCustomPKPet
,
OfficialFood
,
OfficialPet
,
OfficialHousePet
,
OfficialThroughModel
,
OfficialTag
)
from
taggit.utils
import
parse_tags
,
edit_string_for_tags
...
...
@@ -34,11 +34,11 @@ class TagModelTestCase(BaseTaggingTransactionTestCase):
def
test_unique_slug
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
apple
.
tags
.
add
(
"Red"
,
"red"
)
def
test_update
(
self
):
special
=
self
.
tag_model
.
objects
.
create
(
name
=
"special"
)
special
.
save
()
def
test_add
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
yummy
=
self
.
tag_model
.
objects
.
create
(
name
=
"yummy"
)
...
...
@@ -62,7 +62,7 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
housepet_model
=
HousePet
taggeditem_model
=
TaggedItem
tag_model
=
Tag
def
test_add_tag
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
self
.
assertEqual
(
list
(
apple
.
tags
.
all
()),
[])
...
...
@@ -93,14 +93,14 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
tag
=
self
.
tag_model
.
objects
.
create
(
name
=
"delicious"
)
apple
.
tags
.
add
(
tag
)
self
.
assert_tags_equal
(
apple
.
tags
.
all
(),
[
"red"
,
"delicious"
])
apple
.
delete
()
self
.
assert_tags_equal
(
self
.
food_model
.
tags
.
all
(),
[
"green"
])
def
test_require_pk
(
self
):
food_instance
=
self
.
food_model
()
self
.
assertRaises
(
ValueError
,
lambda
:
food_instance
.
tags
.
all
())
def
test_delete_obj
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
apple
.
tags
.
add
(
"red"
)
...
...
@@ -109,24 +109,24 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
strawberry
.
tags
.
add
(
"red"
)
apple
.
delete
()
self
.
assert_tags_equal
(
strawberry
.
tags
.
all
(),
[
"red"
])
def
test_delete_bulk
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
kitty
=
self
.
pet_model
.
objects
.
create
(
pk
=
apple
.
pk
,
name
=
"kitty"
)
apple
.
tags
.
add
(
"red"
,
"delicious"
,
"fruit"
)
kitty
.
tags
.
add
(
"feline"
)
self
.
food_model
.
objects
.
all
()
.
delete
()
self
.
assert_tags_equal
(
kitty
.
tags
.
all
(),
[
"feline"
])
def
test_lookup_by_tag
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
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
]
...
...
@@ -146,25 +146,25 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
)
tag
=
self
.
tag_model
.
objects
.
get
(
name
=
"woof"
)
self
.
assertEqual
(
list
(
self
.
pet_model
.
objects
.
filter
(
tags__
name__
in
=
[
tag
])),
[
dog
])
self
.
assertEqual
(
list
(
self
.
pet_model
.
objects
.
filter
(
tags__in
=
[
tag
])),
[
dog
])
cat
=
self
.
housepet_model
.
objects
.
create
(
name
=
"cat"
,
trained
=
True
)
cat
.
tags
.
add
(
"fuzzy"
)
self
.
assertEqual
(
map
(
lambda
o
:
o
.
pk
,
self
.
pet_model
.
objects
.
filter
(
tags__name__in
=
[
"fuzzy"
])),
[
kitty
.
pk
,
cat
.
pk
]
)
def
test_exclude
(
self
):
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
apple
.
tags
.
add
(
"red"
,
"green"
,
"delicious"
)
pear
=
self
.
food_model
.
objects
.
create
(
name
=
"pear"
)
pear
.
tags
.
add
(
"green"
,
"delicious"
)
guava
=
self
.
food_model
.
objects
.
create
(
name
=
"guava"
)
self
.
assertEqual
(
map
(
lambda
o
:
o
.
pk
,
self
.
food_model
.
objects
.
exclude
(
tags__name__in
=
[
"red"
])),
[
pear
.
pk
,
guava
.
pk
],
...
...
@@ -202,12 +202,12 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
self
.
tag_model
.
objects
.
filter
(
**
lookup_kwargs
),
[
'scary'
]
)
def
test_taggeditem_unicode
(
self
):
ross
=
self
.
pet_model
.
objects
.
create
(
name
=
"ross"
)
# I keep Ross Perot for a pet, what's it to you?
ross
.
tags
.
add
(
"president"
)
self
.
assertEqual
(
unicode
(
self
.
taggeditem_model
.
objects
.
all
()[
0
]),
"ross tagged with president"
...
...
@@ -237,16 +237,16 @@ class TaggableManagerOfficialTestCase(TaggableManagerTestCase):
housepet_model
=
OfficialHousePet
taggeditem_model
=
OfficialThroughModel
tag_model
=
OfficialTag
def
test_extra_fields
(
self
):
self
.
tag_model
.
objects
.
create
(
name
=
"red"
)
self
.
tag_model
.
objects
.
create
(
name
=
"delicious"
,
official
=
True
)
apple
=
self
.
food_model
.
objects
.
create
(
name
=
"apple"
)
apple
.
tags
.
add
(
"delicious"
,
"red"
)
pear
=
self
.
food_model
.
objects
.
create
(
name
=
"Pear"
)
pear
.
tags
.
add
(
"delicious"
)
self
.
assertEqual
(
map
(
lambda
o
:
o
.
pk
,
self
.
food_model
.
objects
.
filter
(
tags__official
=
False
)),
[
apple
.
pk
],
...
...
@@ -256,7 +256,7 @@ class TaggableManagerOfficialTestCase(TaggableManagerTestCase):
class
TaggableFormTestCase
(
BaseTaggingTestCase
):
form_class
=
FoodForm
food_model
=
Food
def
test_form
(
self
):
self
.
assertEqual
(
self
.
form_class
.
base_fields
.
keys
(),
[
'name'
,
'tags'
])
...
...
@@ -271,11 +271,11 @@ class TaggableFormTestCase(BaseTaggingTestCase):
apple
=
self
.
food_model
.
objects
.
get
(
name
=
'apple'
)
self
.
assert_tags_equal
(
apple
.
tags
.
all
(),
[
'green'
,
'red'
,
'yummy'
,
'delicious'
])
self
.
assertEqual
(
self
.
food_model
.
objects
.
count
(),
1
)
f
=
self
.
form_class
({
"name"
:
"raspberry"
})
raspberry
=
f
.
save
()
self
.
assert_tags_equal
(
raspberry
.
tags
.
all
(),
[])
f
=
self
.
form_class
(
instance
=
apple
)
self
.
assertEqual
(
str
(
f
),
"""<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>
\n
<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="delicious, green, red, yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>"""
)
...
...
@@ -287,7 +287,7 @@ class TaggableFormTestCase(BaseTaggingTestCase):
f
=
self
.
form_class
(
instance
=
apple
)
self
.
assertEqual
(
str
(
f
),
"""<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>
\n
<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value=""has space", "has,comma", delicious, green, red, yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>"""
)
class
TaggableFormDirectTestCase
(
TaggableFormTestCase
):
form_class
=
DirectFoodForm
food_model
=
DirectFood
...
...
@@ -315,18 +315,18 @@ class TagStringParseTestCase(UnitTestCase):
self
.
assertEqual
(
parse_tags
(
'one two'
),
[
u'one'
,
u'two'
])
self
.
assertEqual
(
parse_tags
(
'one two three'
),
[
u'one'
,
u'three'
,
u'two'
])
self
.
assertEqual
(
parse_tags
(
'one one two two'
),
[
u'one'
,
u'two'
])
def
test_with_comma_delimited_multiple_words
(
self
):
"""
Test with comma-delimited multiple words.
An unquoted comma in the input will trigger this.
"""
"""
self
.
assertEqual
(
parse_tags
(
',one'
),
[
u'one'
])
self
.
assertEqual
(
parse_tags
(
',one two'
),
[
u'one two'
])
self
.
assertEqual
(
parse_tags
(
',one two three'
),
[
u'one two three'
])
self
.
assertEqual
(
parse_tags
(
'a-one, a-two and a-three'
),
[
u'a-one'
,
u'a-two and a-three'
])
def
test_with_double_quoted_multiple_words
(
self
):
"""
Test with double-quoted multiple words.
...
...
@@ -338,19 +338,19 @@ class TagStringParseTestCase(UnitTestCase):
self
.
assertEqual
(
parse_tags
(
'"one two"'
),
[
u'one two'
])
self
.
assertEqual
(
parse_tags
(
'a-one "a-two and a-three"'
),
[
u'a-one'
,
u'a-two and a-three'
])
def
test_with_no_loose_commas
(
self
):
"""
Test with no loose commas -- split on spaces.
"""
self
.
assertEqual
(
parse_tags
(
'one two "thr,ee"'
),
[
u'one'
,
u'thr,ee'
,
u'two'
])
def
test_with_loose_commas
(
self
):
"""
Loose commas - split on commas
"""
self
.
assertEqual
(
parse_tags
(
'"one", two three'
),
[
u'one'
,
u'two three'
])
def
test_tags_with_double_quotes_can_contain_commas
(
self
):
"""
Double quotes can contain commas
...
...
@@ -359,7 +359,7 @@ class TagStringParseTestCase(UnitTestCase):
[
u'a-one'
,
u'a-two, and a-three'
])
self
.
assertEqual
(
parse_tags
(
'"two", one, one, two, "one"'
),
[
u'one'
,
u'two'
])
def
test_with_naughty_input
(
self
):
"""
Test with naughty input.
...
...
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