2006-06-17 03:18:30 +08:00
|
|
|
"""
|
2007-03-24 04:17:04 +08:00
|
|
|
34. Generic relations
|
2006-06-17 03:18:30 +08:00
|
|
|
|
|
|
|
Generic relations let an object have a foreign key to any object through a
|
|
|
|
content-type/object-id field. A generic foreign key can point to any object,
|
|
|
|
be it animal, vegetable, or mineral.
|
|
|
|
|
2006-06-20 11:03:43 +08:00
|
|
|
The canonical example is tags (although this example implementation is *far*
|
2006-06-17 03:18:30 +08:00
|
|
|
from complete).
|
|
|
|
"""
|
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2007-05-08 18:59:35 +08:00
|
|
|
from django.contrib.contenttypes import generic
|
2006-06-17 03:18:30 +08:00
|
|
|
|
|
|
|
class TaggedItem(models.Model):
|
|
|
|
"""A tag on an item."""
|
|
|
|
tag = models.SlugField()
|
|
|
|
content_type = models.ForeignKey(ContentType)
|
|
|
|
object_id = models.PositiveIntegerField()
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2007-05-08 18:59:35 +08:00
|
|
|
content_object = generic.GenericForeignKey()
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2006-06-17 03:18:30 +08:00
|
|
|
class Meta:
|
|
|
|
ordering = ["tag"]
|
2007-12-09 15:12:07 +08:00
|
|
|
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
def __unicode__(self):
|
2006-06-17 03:18:30 +08:00
|
|
|
return self.tag
|
|
|
|
|
|
|
|
class Animal(models.Model):
|
2007-08-05 13:14:46 +08:00
|
|
|
common_name = models.CharField(max_length=150)
|
|
|
|
latin_name = models.CharField(max_length=150)
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2007-05-08 18:59:35 +08:00
|
|
|
tags = generic.GenericRelation(TaggedItem)
|
2006-06-17 03:18:30 +08:00
|
|
|
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
def __unicode__(self):
|
2006-06-17 03:18:30 +08:00
|
|
|
return self.common_name
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2006-06-17 03:18:30 +08:00
|
|
|
class Vegetable(models.Model):
|
2007-08-05 13:14:46 +08:00
|
|
|
name = models.CharField(max_length=150)
|
2006-06-17 03:18:30 +08:00
|
|
|
is_yucky = models.BooleanField(default=True)
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2007-05-08 18:59:35 +08:00
|
|
|
tags = generic.GenericRelation(TaggedItem)
|
2007-12-09 15:12:07 +08:00
|
|
|
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
def __unicode__(self):
|
2006-06-17 03:18:30 +08:00
|
|
|
return self.name
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2006-06-17 03:18:30 +08:00
|
|
|
class Mineral(models.Model):
|
2007-08-05 13:14:46 +08:00
|
|
|
name = models.CharField(max_length=150)
|
2006-06-17 03:18:30 +08:00
|
|
|
hardness = models.PositiveSmallIntegerField()
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2006-06-17 03:18:30 +08:00
|
|
|
# note the lack of an explicit GenericRelation here...
|
2007-12-09 15:12:07 +08:00
|
|
|
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
def __unicode__(self):
|
2006-06-17 03:18:30 +08:00
|
|
|
return self.name
|
2007-12-09 15:12:07 +08:00
|
|
|
|
2006-08-27 21:59:47 +08:00
|
|
|
__test__ = {'API_TESTS':"""
|
2006-06-17 03:18:30 +08:00
|
|
|
# Create the world in 7 lines of code...
|
|
|
|
>>> lion = Animal(common_name="Lion", latin_name="Panthera leo")
|
|
|
|
>>> platypus = Animal(common_name="Platypus", latin_name="Ornithorhynchus anatinus")
|
|
|
|
>>> eggplant = Vegetable(name="Eggplant", is_yucky=True)
|
|
|
|
>>> bacon = Vegetable(name="Bacon", is_yucky=False)
|
|
|
|
>>> quartz = Mineral(name="Quartz", hardness=7)
|
|
|
|
>>> for o in (lion, platypus, eggplant, bacon, quartz):
|
|
|
|
... o.save()
|
|
|
|
|
|
|
|
# Objects with declared GenericRelations can be tagged directly -- the API
|
2006-06-20 04:19:01 +08:00
|
|
|
# mimics the many-to-many API.
|
2006-06-17 03:18:30 +08:00
|
|
|
>>> bacon.tags.create(tag="fatty")
|
|
|
|
<TaggedItem: fatty>
|
|
|
|
>>> bacon.tags.create(tag="salty")
|
|
|
|
<TaggedItem: salty>
|
2007-01-25 19:24:17 +08:00
|
|
|
>>> lion.tags.create(tag="yellow")
|
|
|
|
<TaggedItem: yellow>
|
|
|
|
>>> lion.tags.create(tag="hairy")
|
|
|
|
<TaggedItem: hairy>
|
2006-06-17 03:18:30 +08:00
|
|
|
|
|
|
|
>>> lion.tags.all()
|
|
|
|
[<TaggedItem: hairy>, <TaggedItem: yellow>]
|
|
|
|
>>> bacon.tags.all()
|
|
|
|
[<TaggedItem: fatty>, <TaggedItem: salty>]
|
|
|
|
|
2006-06-20 04:19:01 +08:00
|
|
|
# You can easily access the content object like a foreign key.
|
2006-06-17 03:18:30 +08:00
|
|
|
>>> t = TaggedItem.objects.get(tag="salty")
|
|
|
|
>>> t.content_object
|
|
|
|
<Vegetable: Bacon>
|
|
|
|
|
|
|
|
# Recall that the Mineral class doesn't have an explicit GenericRelation
|
2006-06-20 04:19:01 +08:00
|
|
|
# defined. That's OK, because you can create TaggedItems explicitly.
|
2006-06-17 03:18:30 +08:00
|
|
|
>>> tag1 = TaggedItem(content_object=quartz, tag="shiny")
|
|
|
|
>>> tag2 = TaggedItem(content_object=quartz, tag="clearish")
|
|
|
|
>>> tag1.save()
|
|
|
|
>>> tag2.save()
|
|
|
|
|
2006-06-20 04:19:01 +08:00
|
|
|
# However, excluding GenericRelations means your lookups have to be a bit more
|
|
|
|
# explicit.
|
2006-06-17 03:18:30 +08:00
|
|
|
>>> from django.contrib.contenttypes.models import ContentType
|
|
|
|
>>> ctype = ContentType.objects.get_for_model(quartz)
|
|
|
|
>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
|
|
|
|
[<TaggedItem: clearish>, <TaggedItem: shiny>]
|
|
|
|
|
2006-06-20 04:19:01 +08:00
|
|
|
# You can set a generic foreign key in the way you'd expect.
|
2006-06-17 03:18:30 +08:00
|
|
|
>>> tag1.content_object = platypus
|
|
|
|
>>> tag1.save()
|
|
|
|
>>> platypus.tags.all()
|
|
|
|
[<TaggedItem: shiny>]
|
|
|
|
>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
|
|
|
|
[<TaggedItem: clearish>]
|
2007-01-25 19:24:17 +08:00
|
|
|
|
|
|
|
# If you delete an object with an explicit Generic relation, the related
|
|
|
|
# objects are deleted when the source object is deleted.
|
|
|
|
# Original list of tags:
|
|
|
|
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'hairy', <ContentType: animal>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2), (u'yellow', <ContentType: animal>, 1)]
|
2007-01-25 19:24:17 +08:00
|
|
|
|
|
|
|
>>> lion.delete()
|
|
|
|
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
|
2007-01-25 19:24:17 +08:00
|
|
|
|
2007-12-09 15:12:07 +08:00
|
|
|
# If Generic Relation is not explicitly defined, any related objects
|
2007-01-25 19:24:17 +08:00
|
|
|
# remain after deletion of the source object.
|
|
|
|
>>> quartz.delete()
|
|
|
|
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
[(u'clearish', <ContentType: mineral>, 1), (u'fatty', <ContentType: vegetable>, 2), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
|
2007-01-25 19:24:17 +08:00
|
|
|
|
2007-12-09 15:12:07 +08:00
|
|
|
# If you delete a tag, the objects using the tag are unaffected
|
2007-01-25 19:24:17 +08:00
|
|
|
# (other than losing a tag)
|
|
|
|
>>> tag = TaggedItem.objects.get(id=1)
|
|
|
|
>>> tag.delete()
|
|
|
|
>>> bacon.tags.all()
|
|
|
|
[<TaggedItem: salty>]
|
|
|
|
>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
[(u'clearish', <ContentType: mineral>, 1), (u'salty', <ContentType: vegetable>, 2), (u'shiny', <ContentType: animal>, 2)]
|
2007-01-25 19:24:17 +08:00
|
|
|
|
2007-12-09 15:12:07 +08:00
|
|
|
>>> ctype = ContentType.objects.get_for_model(lion)
|
|
|
|
>>> Animal.objects.filter(tags__content_type=ctype)
|
|
|
|
[<Animal: Platypus>]
|
|
|
|
|
2006-08-27 21:59:47 +08:00
|
|
|
"""}
|