thirdparty/google_appengine/lib/django/tests/modeltests/generic_relations/models.py
changeset 2866 a04b1e4126c4
parent 2864 2e0b0af889be
child 2868 9f7f269383f7
equal deleted inserted replaced
2864:2e0b0af889be 2866:a04b1e4126c4
     1 """
       
     2 34. Generic relations
       
     3 
       
     4 Generic relations let an object have a foreign key to any object through a
       
     5 content-type/object-id field. A generic foreign key can point to any object,
       
     6 be it animal, vegetable, or mineral.
       
     7 
       
     8 The canonical example is tags (although this example implementation is *far*
       
     9 from complete).
       
    10 """
       
    11 
       
    12 from django.db import models
       
    13 from django.contrib.contenttypes.models import ContentType
       
    14 
       
    15 class TaggedItem(models.Model):
       
    16     """A tag on an item."""
       
    17     tag = models.SlugField()
       
    18     content_type = models.ForeignKey(ContentType)
       
    19     object_id = models.PositiveIntegerField()
       
    20     
       
    21     content_object = models.GenericForeignKey()
       
    22     
       
    23     class Meta:
       
    24         ordering = ["tag"]
       
    25     
       
    26     def __str__(self):
       
    27         return self.tag
       
    28 
       
    29 class Animal(models.Model):
       
    30     common_name = models.CharField(maxlength=150)
       
    31     latin_name = models.CharField(maxlength=150)
       
    32     
       
    33     tags = models.GenericRelation(TaggedItem)
       
    34 
       
    35     def __str__(self):
       
    36         return self.common_name
       
    37         
       
    38 class Vegetable(models.Model):
       
    39     name = models.CharField(maxlength=150)
       
    40     is_yucky = models.BooleanField(default=True)
       
    41     
       
    42     tags = models.GenericRelation(TaggedItem)
       
    43     
       
    44     def __str__(self):
       
    45         return self.name
       
    46     
       
    47 class Mineral(models.Model):
       
    48     name = models.CharField(maxlength=150)
       
    49     hardness = models.PositiveSmallIntegerField()
       
    50     
       
    51     # note the lack of an explicit GenericRelation here...
       
    52     
       
    53     def __str__(self):
       
    54         return self.name
       
    55         
       
    56 __test__ = {'API_TESTS':"""
       
    57 # Create the world in 7 lines of code...
       
    58 >>> lion = Animal(common_name="Lion", latin_name="Panthera leo")
       
    59 >>> platypus = Animal(common_name="Platypus", latin_name="Ornithorhynchus anatinus")
       
    60 >>> eggplant = Vegetable(name="Eggplant", is_yucky=True)
       
    61 >>> bacon = Vegetable(name="Bacon", is_yucky=False)
       
    62 >>> quartz = Mineral(name="Quartz", hardness=7)
       
    63 >>> for o in (lion, platypus, eggplant, bacon, quartz):
       
    64 ...     o.save()
       
    65 
       
    66 # Objects with declared GenericRelations can be tagged directly -- the API
       
    67 # mimics the many-to-many API.
       
    68 >>> bacon.tags.create(tag="fatty")
       
    69 <TaggedItem: fatty>
       
    70 >>> bacon.tags.create(tag="salty")
       
    71 <TaggedItem: salty>
       
    72 >>> lion.tags.create(tag="yellow")
       
    73 <TaggedItem: yellow>
       
    74 >>> lion.tags.create(tag="hairy")
       
    75 <TaggedItem: hairy>
       
    76 
       
    77 >>> lion.tags.all()
       
    78 [<TaggedItem: hairy>, <TaggedItem: yellow>]
       
    79 >>> bacon.tags.all()
       
    80 [<TaggedItem: fatty>, <TaggedItem: salty>]
       
    81 
       
    82 # You can easily access the content object like a foreign key.
       
    83 >>> t = TaggedItem.objects.get(tag="salty")
       
    84 >>> t.content_object
       
    85 <Vegetable: Bacon>
       
    86 
       
    87 # Recall that the Mineral class doesn't have an explicit GenericRelation
       
    88 # defined. That's OK, because you can create TaggedItems explicitly.
       
    89 >>> tag1 = TaggedItem(content_object=quartz, tag="shiny")
       
    90 >>> tag2 = TaggedItem(content_object=quartz, tag="clearish")
       
    91 >>> tag1.save()
       
    92 >>> tag2.save()
       
    93 
       
    94 # However, excluding GenericRelations means your lookups have to be a bit more
       
    95 # explicit.
       
    96 >>> from django.contrib.contenttypes.models import ContentType
       
    97 >>> ctype = ContentType.objects.get_for_model(quartz)
       
    98 >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
       
    99 [<TaggedItem: clearish>, <TaggedItem: shiny>]
       
   100 
       
   101 # You can set a generic foreign key in the way you'd expect.
       
   102 >>> tag1.content_object = platypus
       
   103 >>> tag1.save()
       
   104 >>> platypus.tags.all()
       
   105 [<TaggedItem: shiny>]
       
   106 >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
       
   107 [<TaggedItem: clearish>]
       
   108 
       
   109 # If you delete an object with an explicit Generic relation, the related
       
   110 # objects are deleted when the source object is deleted.
       
   111 # Original list of tags:
       
   112 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
       
   113 [('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('hairy', <ContentType: animal>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2), ('yellow', <ContentType: animal>, 1)]
       
   114 
       
   115 >>> lion.delete()
       
   116 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
       
   117 [('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)]
       
   118 
       
   119 # If Generic Relation is not explicitly defined, any related objects 
       
   120 # remain after deletion of the source object.
       
   121 >>> quartz.delete()
       
   122 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
       
   123 [('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)]
       
   124 
       
   125 # If you delete a tag, the objects using the tag are unaffected 
       
   126 # (other than losing a tag)
       
   127 >>> tag = TaggedItem.objects.get(id=1)
       
   128 >>> tag.delete()
       
   129 >>> bacon.tags.all()
       
   130 [<TaggedItem: salty>]
       
   131 >>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]
       
   132 [('clearish', <ContentType: mineral>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)]
       
   133 
       
   134 """}