| | 1 | See http://www.djangoproject.com/documentation/models/generic_relations/. |
| | 2 | |
| | 3 | '''Note''': As of today, 13-DEC-06, this admonishment applies: |
| | 4 | {{{ |
| | 5 | Generic relations: a "generic foreign key" feature is currently under development, |
| | 6 | but not yet completed. There is no support for it yet in the admin application, and |
| | 7 | it is probably unwise to attempt to use it in a production application. |
| | 8 | }}} |
| | 9 | --from http://code.djangoproject.com/ |
| | 10 | |
| | 11 | Also, I do not think that this is particularly good data modeling if you have a choice, but when migrating an application and dealing with legacy data as you go, it can be useful if it is not abused. |
| | 12 | |
| | 13 | == Model Source Code == |
| | 14 | {{{ |
| | 15 | #!python |
| | 16 | class AttributeManager(models.Manager): |
| | 17 | def with_attr(self, attr_name): |
| | 18 | return Attribute.objects.filter(name=attr_name) |
| | 19 | |
| | 20 | def type_with_attr(self, type_name, attr_name): |
| | 21 | return Attribute.objects.filter(content_type__name=type_name, name=attr_name) |
| | 22 | |
| | 23 | def type_with_attr_value(self, type_name, attr_name, value): |
| | 24 | return Attribute.objects.filter(content_type__name=type_name, name=attr_name, value=value) |
| | 25 | |
| | 26 | def obj_attr_list(self, obj): |
| | 27 | ctype = ContentType.objects.get_for_model(obj) |
| | 28 | return Attribute.objects.filter(content_type__pk=ctype.id, object_id=obj.id) |
| | 29 | |
| | 30 | def obj_attr_value(self, obj, attr_name): |
| | 31 | ctype = ContentType.objects.get_for_model(obj) |
| | 32 | try: |
| | 33 | av = Attribute.objects.get(name=attr_name, content_type__pk=ctype.id, object_id=obj.id) |
| | 34 | except Attribute.DoesNotExist: |
| | 35 | return None |
| | 36 | return av.value |
| | 37 | |
| | 38 | class Attribute(models.Model): |
| | 39 | name = models.CharField(maxlength=25) |
| | 40 | content_type = models.ForeignKey(ContentType) |
| | 41 | object_id = models.PositiveIntegerField() |
| | 42 | value = models.CharField(maxlength=255) |
| | 43 | |
| | 44 | content_object = models.GenericForeignKey() |
| | 45 | objects = AttributeManager() |
| | 46 | |
| | 47 | class meta: |
| | 48 | unique_together = (('name', 'content_type', 'object_id'),) |
| | 49 | |
| | 50 | def __str__(self): |
| | 51 | return "%s.%s.%s=%s" % (self.content_type.name, self.content_object, self.name, self.value,) |
| | 52 | }}} |
| | 53 | |
| | 54 | == Sample API usage == |
| | 55 | This sample code assumes you added the above models to the sample found at http://www.djangoproject.com/documentation/models/generic_relations/. |
| | 56 | |
| | 57 | {{{ |
| | 58 | #!python |
| | 59 | >>> diamond = Mineral.objects.create(name="Diamond", hardness=10) |
| | 60 | >>> emerald = Mineral.objects.create(name="Emerald", hardness=6) |
| | 61 | >>> Attribute.objects.create(content_object=quartz, name='color', value='black') |
| | 62 | <Attribute: mineral.Quartz.color=black> |
| | 63 | |
| | 64 | >>> Attribute.objects.create(content_object=emerald, name='color', value='green') |
| | 65 | <Attribute: mineral.Emerald.color=green> |
| | 66 | |
| | 67 | >>> Attribute.objects.with_attr('color') |
| | 68 | [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>] |
| | 69 | |
| | 70 | >>> Attribute.objects.type_with_attr('mineral', 'color') |
| | 71 | [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>] |
| | 72 | |
| | 73 | >>> Attribute.objects.create(content_object=eggplant, name='color', value='purple') |
| | 74 | <Attribute: vegetable.Eggplant.color=purple> |
| | 75 | |
| | 76 | >>> Attribute.objects.with_attr('color') |
| | 77 | [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>, <Attribute: vegetable.Eggplant.color= |
| | 78 | purple>] |
| | 79 | |
| | 80 | >>> Attribute.objects.type_with_attr('mineral', 'color') |
| | 81 | [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>] |
| | 82 | |
| | 83 | >>> Attribute.objects.type_with_attr_value('mineral', 'color', 'green') |
| | 84 | [<Attribute: mineral.Emerald.color=green>] |
| | 85 | |
| | 86 | >>> Attribute.objects.type_with_attr_value('mineral', 'color', 'red') |
| | 87 | [] |
| | 88 | |
| | 89 | >>> Attribute.objects.obj_attr_list(quartz) |
| | 90 | [<Attribute: mineral.Quartz.color=black>] |
| | 91 | |
| | 92 | >>> Attribute.objects.obj_attr_value(quartz, 'color') |
| | 93 | 'black' |
| | 94 | }}} |