See http://www.djangoproject.com/documentation/models/generic_relations/.
Note: As of today, 13-DEC-06, this admonishment applies:
Generic relations: a "generic foreign key" feature is currently under development, but not yet completed. There is no support for it yet in the admin application, and it is probably unwise to attempt to use it in a production application.
--from http://code.djangoproject.com/
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.
Model Source Code
class AttributeManager(models.Manager): def with_attr(self, attr_name): return Attribute.objects.filter(name=attr_name) def type_with_attr(self, type_name, attr_name): return Attribute.objects.filter(content_type__name=type_name, name=attr_name) def type_with_attr_value(self, type_name, attr_name, value): return Attribute.objects.filter(content_type__name=type_name, name=attr_name, value=value) def obj_attr_list(self, obj): ctype = ContentType.objects.get_for_model(obj) return Attribute.objects.filter(content_type__pk=ctype.id, object_id=obj.id) def obj_attr_value(self, obj, attr_name): ctype = ContentType.objects.get_for_model(obj) try: av = Attribute.objects.get(name=attr_name, content_type__pk=ctype.id, object_id=obj.id) except Attribute.DoesNotExist: return None return av.value class Attribute(models.Model): name = models.CharField(maxlength=25) content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() value = models.CharField(maxlength=255) content_object = models.GenericForeignKey() objects = AttributeManager() class meta: unique_together = (('name', 'content_type', 'object_id'),) def __str__(self): return "%s.%s.%s=%s" % (self.content_type.name, self.content_object, self.name, self.value,)
Sample API usage
This sample code assumes you added the above models to the sample found at http://www.djangoproject.com/documentation/models/generic_relations/.
>>> quartz = Mineral.objects.create(name="Quartz", hardness=10) >>> emerald = Mineral.objects.create(name="Emerald", hardness=6) >>> Attribute.objects.create(content_object=quartz, name='color', value='black') <Attribute: mineral.Quartz.color=black> >>> Attribute.objects.create(content_object=emerald, name='color', value='green') <Attribute: mineral.Emerald.color=green> >>> Attribute.objects.with_attr('color') [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>] >>> Attribute.objects.type_with_attr('mineral', 'color') [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>] >>> Attribute.objects.create(content_object=eggplant, name='color', value='purple') <Attribute: vegetable.Eggplant.color=purple> >>> Attribute.objects.with_attr('color') [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>, <Attribute: vegetable.Eggplant.color= purple>] >>> Attribute.objects.type_with_attr('mineral', 'color') [<Attribute: mineral.Quartz.color=black>, <Attribute: mineral.Emerald.color=green>] >>> Attribute.objects.type_with_attr_value('mineral', 'color', 'green') [<Attribute: mineral.Emerald.color=green>] >>> Attribute.objects.type_with_attr_value('mineral', 'color', 'red') [] >>> Attribute.objects.obj_attr_list(quartz) [<Attribute: mineral.Quartz.color=black>] >>> Attribute.objects.obj_attr_value(quartz, 'color') 'black'
Last modified
14 years ago
Last modified on Jun 25, 2010, 3:01:51 PM
Note:
See TracWiki
for help on using the wiki.