Index: tests/modeltests/generic_relations/tests.py
===================================================================
--- tests/modeltests/generic_relations/tests.py	(revision 16244)
+++ tests/modeltests/generic_relations/tests.py	(working copy)
@@ -3,12 +3,18 @@
 from django.contrib.contenttypes.models import ContentType
 from django.test import TestCase
 
-from models import (TaggedItem, ValuableTaggedItem, Comparison, Animal,
-    Vegetable, Mineral)
+from models import (TaggedItem, ValuableTaggedItem, TaggedItemTextID,
+    Comparison, Animal, Vegetable, Mineral)
 
 
 class GenericRelationsTests(TestCase):
     def test_generic_relations(self):
+        self.base_generic_relations(TaggedItem, 'tags')
+
+    def test_generic_relations_string_id(self):
+        self.base_generic_relations(TaggedItemTextID, 'stringtags')
+
+    def base_generic_relations(self, tag_model, reverse_name):
         # Create the world in 7 lines of code...
         lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo")
         platypus = Animal.objects.create(
@@ -18,53 +24,44 @@
         bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
         quartz = Mineral.objects.create(name="Quartz", hardness=7)
 
+        # Helper function
+        def tags(obj): return getattr(obj, reverse_name)
+
         # Objects with declared GenericRelations can be tagged directly -- the
         # API mimics the many-to-many API.
-        bacon.tags.create(tag="fatty")
-        bacon.tags.create(tag="salty")
-        lion.tags.create(tag="yellow")
-        lion.tags.create(tag="hairy")
-        platypus.tags.create(tag="fatty")
-        self.assertQuerysetEqual(lion.tags.all(), [
-            "<TaggedItem: hairy>",
-            "<TaggedItem: yellow>"
-        ])
-        self.assertQuerysetEqual(bacon.tags.all(), [
-            "<TaggedItem: fatty>",
-            "<TaggedItem: salty>"
-        ])
+        tags(bacon).create(tag="fatty")
+        tags(bacon).create(tag="salty")
+        tags(lion).create(tag="yellow")
+        tags(lion).create(tag="hairy")
+        tags(platypus).create(tag="fatty")
+        self.assertQuerysetEqual(tags(lion).all(), ["hairy", "yellow"], unicode)
+        self.assertQuerysetEqual(tags(bacon).all(), ["fatty", "salty"], unicode)
 
         # You can easily access the content object like a foreign key.
-        t = TaggedItem.objects.get(tag="salty")
+        t = tag_model.objects.get(tag="salty")
         self.assertEqual(t.content_object, bacon)
 
         # Recall that the Mineral class doesn't have an explicit GenericRelation
         # defined. That's OK, because you can create TaggedItems explicitly.
-        tag1 = TaggedItem.objects.create(content_object=quartz, tag="shiny")
-        tag2 = TaggedItem.objects.create(content_object=quartz, tag="clearish")
+        tag1 = tag_model.objects.create(content_object=quartz, tag="shiny")
+        tag2 = tag_model.objects.create(content_object=quartz, tag="clearish")
 
         # However, excluding GenericRelations means your lookups have to be a
         # bit more explicit.
         ctype = ContentType.objects.get_for_model(quartz)
-        q = TaggedItem.objects.filter(
+        q = tag_model.objects.filter(
             content_type__pk=ctype.id, object_id=quartz.id
         )
-        self.assertQuerysetEqual(q, [
-            "<TaggedItem: clearish>",
-            "<TaggedItem: shiny>"
-        ])
+        self.assertQuerysetEqual(q, ["clearish", "shiny"], unicode)
 
         # You can set a generic foreign key in the way you'd expect.
         tag1.content_object = platypus
         tag1.save()
-        self.assertQuerysetEqual(platypus.tags.all(), [
-            "<TaggedItem: fatty>",
-            "<TaggedItem: shiny>"
-        ])
-        q = TaggedItem.objects.filter(
+        self.assertQuerysetEqual(tags(platypus).all(), ["fatty", "shiny"], unicode)
+        q = tag_model.objects.filter(
             content_type__pk=ctype.id, object_id=quartz.id
         )
-        self.assertQuerysetEqual(q, ["<TaggedItem: clearish>"])
+        self.assertQuerysetEqual(q, ["clearish"], unicode)
 
         # Queries across generic relations respect the content types. Even
         # though there are two TaggedItems with a tag of "fatty", this query
@@ -73,10 +70,13 @@
             "<Animal: Lion>",
             "<Animal: Platypus>"
         ])
-        self.assertQuerysetEqual(Animal.objects.filter(tags__tag='fatty'), [
+
+        print Animal.objects.filter(**{reverse_name + '__tag': 'fatty'}).query
+        self.assertQuerysetEqual(Animal.objects.filter(**{reverse_name + '__tag': 'fatty'}), [
             "<Animal: Platypus>"
         ])
-        self.assertQuerysetEqual(Animal.objects.exclude(tags__tag='fatty'), [
+        print Animal.objects.exclude(**{reverse_name + '__tag': 'fatty'}).query
+        self.assertQuerysetEqual(Animal.objects.exclude(**{reverse_name + '__tag': 'fatty'}), [
             "<Animal: Lion>"
         ])
 
@@ -84,27 +84,27 @@
         # objects are deleted when the source object is deleted.
         # Original list of tags:
         comp_func = lambda obj: (
-            obj.tag, obj.content_type.model_class(), obj.object_id
+            obj.tag, obj.content_type.model_class(), unicode(obj.object_id)
         )
 
-        self.assertQuerysetEqual(TaggedItem.objects.all(), [
-                (u'clearish', Mineral, quartz.pk),
-                (u'fatty', Animal, platypus.pk),
-                (u'fatty', Vegetable, bacon.pk),
-                (u'hairy', Animal, lion.pk),
-                (u'salty', Vegetable, bacon.pk),
-                (u'shiny', Animal, platypus.pk),
-                (u'yellow', Animal, lion.pk)
+        self.assertQuerysetEqual(tag_model.objects.all(), [
+                (u'clearish', Mineral, unicode(quartz.pk)),
+                (u'fatty', Animal, unicode(platypus.pk)),
+                (u'fatty', Vegetable, unicode(bacon.pk)),
+                (u'hairy', Animal, unicode(lion.pk)),
+                (u'salty', Vegetable, unicode(bacon.pk)),
+                (u'shiny', Animal, unicode(platypus.pk)),
+                (u'yellow', Animal, unicode(lion.pk))
             ],
             comp_func
         )
         lion.delete()
-        self.assertQuerysetEqual(TaggedItem.objects.all(), [
-                (u'clearish', Mineral, quartz.pk),
-                (u'fatty', Animal, platypus.pk),
-                (u'fatty', Vegetable, bacon.pk),
-                (u'salty', Vegetable, bacon.pk),
-                (u'shiny', Animal, platypus.pk)
+        self.assertQuerysetEqual(tag_model.objects.all(), [
+                (u'clearish', Mineral, unicode(quartz.pk)),
+                (u'fatty', Animal, unicode(platypus.pk)),
+                (u'fatty', Vegetable, unicode(bacon.pk)),
+                (u'salty', Vegetable, unicode(bacon.pk)),
+                (u'shiny', Animal, unicode(platypus.pk))
             ],
             comp_func
         )
@@ -113,31 +113,31 @@
         # remain after deletion of the source object.
         quartz_pk = quartz.pk
         quartz.delete()
-        self.assertQuerysetEqual(TaggedItem.objects.all(), [
-                (u'clearish', Mineral, quartz_pk),
-                (u'fatty', Animal, platypus.pk),
-                (u'fatty', Vegetable, bacon.pk),
-                (u'salty', Vegetable, bacon.pk),
-                (u'shiny', Animal, platypus.pk)
+        self.assertQuerysetEqual(tag_model.objects.all(), [
+                (u'clearish', Mineral, unicode(quartz_pk)),
+                (u'fatty', Animal, unicode(platypus.pk)),
+                (u'fatty', Vegetable, unicode(bacon.pk)),
+                (u'salty', Vegetable, unicode(bacon.pk)),
+                (u'shiny', Animal, unicode(platypus.pk))
             ],
             comp_func
         )
         # If you delete a tag, the objects using the tag are unaffected
         # (other than losing a tag)
-        tag = TaggedItem.objects.order_by("id")[0]
+        tag = tag_model.objects.order_by("id")[0]
         tag.delete()
-        self.assertQuerysetEqual(bacon.tags.all(), ["<TaggedItem: salty>"])
-        self.assertQuerysetEqual(TaggedItem.objects.all(), [
-                (u'clearish', Mineral, quartz_pk),
-                (u'fatty', Animal, platypus.pk),
-                (u'salty', Vegetable, bacon.pk),
-                (u'shiny', Animal, platypus.pk)
+        self.assertQuerysetEqual(tags(bacon).all(), ["salty"], unicode)
+        self.assertQuerysetEqual(tag_model.objects.all(), [
+                (u'clearish', Mineral, unicode(quartz_pk)),
+                (u'fatty', Animal, unicode(platypus.pk)),
+                (u'salty', Vegetable, unicode(bacon.pk)),
+                (u'shiny', Animal, unicode(platypus.pk))
             ],
             comp_func
         )
-        TaggedItem.objects.filter(tag='fatty').delete()
+        tag_model.objects.filter(tag='fatty').delete()
         ctype = ContentType.objects.get_for_model(lion)
-        self.assertQuerysetEqual(Animal.objects.filter(tags__content_type=ctype), [
+        self.assertQuerysetEqual(Animal.objects.filter(**{reverse_name + '__content_type': ctype}), [
             "<Animal: Platypus>"
         ])
 
Index: tests/modeltests/generic_relations/models.py
===================================================================
--- tests/modeltests/generic_relations/models.py	(revision 16244)
+++ tests/modeltests/generic_relations/models.py	(working copy)
@@ -31,6 +31,19 @@
 class ValuableTaggedItem(TaggedItem):
     value = models.PositiveIntegerField()
 
+class TaggedItemTextID(models.Model):
+    tag = models.SlugField()
+    content_type = models.ForeignKey(ContentType)
+    object_id = models.TextField()
+
+    content_object = generic.GenericForeignKey()
+
+    class Meta:
+        ordering = ["tag", "content_type__name"]
+
+    def __unicode__(self):
+        return self.tag
+
 class Comparison(models.Model):
     """
     A model that tests having multiple GenericForeignKeys
@@ -54,6 +67,7 @@
     latin_name = models.CharField(max_length=150)
 
     tags = generic.GenericRelation(TaggedItem)
+    stringtags = generic.GenericRelation(TaggedItemTextID)
     comparisons = generic.GenericRelation(Comparison,
                                           object_id_field="object_id1",
                                           content_type_field="content_type1")
@@ -66,6 +80,7 @@
     is_yucky = models.BooleanField(default=True)
 
     tags = generic.GenericRelation(TaggedItem)
+    stringtags = generic.GenericRelation(TaggedItemTextID)
 
     def __unicode__(self):
         return self.name
