Test suite updated to Django 1.4 + much needed performance and API fixes #99

Closed
wants to merge 18 commits into
from
View
@@ -12,3 +12,7 @@ Frank Wiles
Jonathan Buchanan
idle sign <idlesign@yandex.ru>
Charles Leifer
+Diederik van der Boor <vdboor@edoburu.nl>
+Henrique Carvalho Alves <hcarvalhoalves@gmail.com>
+Marco Fucci <info@marcofucci.com>
+
View
File renamed without changes.
View
@@ -4,7 +4,7 @@
from taggit import VERSION
-f = open(os.path.join(os.path.dirname(__file__), 'README.txt'))
+f = open(os.path.join(os.path.dirname(__file__), 'README.md'))
readme = f.read()
f.close()
@@ -32,6 +32,5 @@
'Programming Language :: Python',
'Framework :: Django',
],
- test_suite='taggit.tests.runtests.runtests'
+ test_suite='taggit.tests.runtests.runtests',
)
-
View
@@ -6,8 +6,10 @@
class TaggedItemInline(admin.StackedInline):
model = TaggedItem
+
class TagAdmin(admin.ModelAdmin):
- list_display = ["name"]
+ list_display = ("name", 'slug')
+ search_fields = ('name', 'slug')
inlines = [
TaggedItemInline
]
View
@@ -27,8 +27,8 @@ def all(iterable):
class TaggableRel(ManyToManyRel):
- def __init__(self):
- self.related_name = None
+ def __init__(self, related_name=None):
+ self.related_name = related_name
self.limit_choices_to = {}
self.symmetrical = True
self.multiple = True
@@ -37,9 +37,9 @@ def __init__(self):
class TaggableManager(RelatedField):
def __init__(self, verbose_name=_("Tags"),
- help_text=_("A comma-separated list of tags."), through=None, blank=False):
+ help_text=_("A comma-separated list of tags."), through=None, blank=False, related_name=None):
self.through = through or TaggedItem
- self.rel = TaggableRel()
+ self.rel = TaggableRel(related_name)
self.verbose_name = verbose_name
self.help_text = help_text
self.blank = blank
@@ -109,6 +109,9 @@ def related_query_name(self):
def m2m_reverse_name(self):
return self.through._meta.get_field_by_name("tag")[0].column
+
+ def m2m_reverse_field_name(self):
+ return self.through._meta.get_field_by_name("tag")[0].name
def m2m_target_field_name(self):
return self.model._meta.pk.name
View
@@ -1,9 +1,11 @@
import django
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey
-from django.db import models, IntegrityError, transaction
+from django.db import models, transaction
+from django.db.models.query import QuerySet
from django.template.defaultfilters import slugify as default_slugify
from django.utils.translation import ugettext_lazy as _, ugettext
+from django.db import utils
class TagBase(models.Model):
@@ -38,7 +40,7 @@ def save(self, *args, **kwargs):
res = super(TagBase, self).save(*args, **kwargs)
transaction.savepoint_commit(sid, **trans_kwargs)
return res
- except IntegrityError:
+ except utils.IntegrityError:
transaction.savepoint_rollback(sid, **trans_kwargs)
self.slug = self.slugify(self.name, i)
else:
@@ -137,11 +139,18 @@ def lookup_kwargs(cls, instance):
@classmethod
def bulk_lookup_kwargs(cls, instances):
- # TODO: instances[0], can we assume there are instances.
- return {
- "object_id__in": [instance.pk for instance in instances],
- "content_type": ContentType.objects.get_for_model(instances[0]),
- }
+ if isinstance(instances, QuerySet):
+ # Can do a real object_id IN (SELECT ..) query.
+ return {
+ "object_id__in": instances,
+ "content_type": ContentType.objects.get_for_model(instances.model),
+ }
+ else:
+ # TODO: instances[0], can we assume there are instances.
+ return {
+ "object_id__in": [instance.pk for instance in instances],
+ "content_type": ContentType.objects.get_for_model(instances[0]),
+ }
@classmethod
def tags_for(cls, model, instance=None):
View
@@ -6,29 +6,25 @@
if not settings.configured:
settings.configure(
- DATABASE_ENGINE='sqlite3',
+ DATABASES={
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ }
+ },
INSTALLED_APPS=[
'django.contrib.contenttypes',
'taggit',
'taggit.tests',
]
)
-from django.test.simple import run_tests
+from django.test.simple import DjangoTestSuiteRunner
-def runtests(*test_args):
- if not test_args:
- test_args = ['tests']
- parent = os.path.join(
- os.path.dirname(os.path.abspath(__file__)),
- "..",
- "..",
- )
- sys.path.insert(0, parent)
- failures = run_tests(test_args, verbosity=1, interactive=True)
+def runtests():
+ runner = DjangoTestSuiteRunner()
+ failures = runner.run_tests(['tests'], verbosity=1, interactive=True)
sys.exit(failures)
-
if __name__ == '__main__':
- runtests(*sys.argv[1:])
+ runtests()
View
@@ -211,10 +211,31 @@ def test_lookup_by_tag(self):
cat.tags.add("fuzzy")
self.assertEqual(
- map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"])),
- [kitty.pk, cat.pk]
+ set(map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"]))),
+ set([kitty.pk, cat.pk])
)
+ def test_lookup_bulk(self):
+ apple = self.food_model.objects.create(name="apple")
+ pear = self.food_model.objects.create(name="pear")
+ apple.tags.add('fruit', 'green')
+ pear.tags.add('fruit', 'yummie')
+
+ def lookup_qs():
+ # New fix: directly allow WHERE object_id IN (SELECT id FROM ..)
+ objects = self.food_model.objects.all()
+ lookup = self.taggeditem_model.bulk_lookup_kwargs(objects)
+ list(self.taggeditem_model.objects.filter(**lookup))
+
+ def lookup_list():
+ # Simulate old situation: iterate over a list.
+ objects = list(self.food_model.objects.all())
+ lookup = self.taggeditem_model.bulk_lookup_kwargs(objects)
+ list(self.taggeditem_model.objects.filter(**lookup))
+
+ self.assert_num_queries(1, lookup_qs)
+ self.assert_num_queries(2, lookup_list)
+
def test_exclude(self):
apple = self.food_model.objects.create(name="apple")
apple.tags.add("red", "green", "delicious")