limodou的学习记录
limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source ...

导航

Blog统计
  • 文章 - 927
  • 收藏 - 0
  • 评论 - 2911
  • Trackbacks - 16
公告

文章

收藏

    相册

      DocBook

      python

      Pythoner in 中国

      Python开源项目

      技术

      其它

      我的东东

      我的开源项目

      存档


      正在读取评论……
       

      Generic Relation 并不是一个新出的东西,不过此前我一直没有使用过。现在为了将 SharePlat 中的某些功能独立出来,我开始使用它了。在 django 源码中的文档中并没有 Generic Relation 的说明,你可以从 django 的网站找到这一文档

      在文档中描述得很清楚。基本上有两种使用:GenericForeignKey和GenericRelation。比如我有一个Topic表,它用来保存讨论主题。然后有一个Comment表,它用来保存回复。为了使用Comment通用,Comment并不直接保存到Topic的关系。这两个表的Model可以为:

      from django.contrib.contenttypes.models import ContentType

      class Topic(models.Model):
          title = models.CharField(maxlength=200)
          content = models.TextField()
          comments = models.GenericRelation(Comment)

      class Comment(models.Model):
          content = models.TextField(default='')
          content_type = models.ForeignKey(ContentType)
          object_id = models.IntegerField()
          content_object = models.GenericForeignKey()

      这是两个简化后的Model。这里体现了两种用法。

      先看Comment。Comment中使用GenericForeignKey()来指向其它的Model实例。为了使用它,你还需要在Model中定义content_type和object_id才可以。其中content_type指向ContentType这个Model。在示例的最上面可以看出,它是定义在django.contrib.contenttypes.models中的一个Model。是不是感觉麻烦,没办法。想当初我在 Woodlog 中也想实现类似的功能,当时我是使用了一个字符串,包括了Model名和记录的id值,通过'/'来分隔。所以处理时,要每次拆分。比这个还要麻烦。其实仔细想一想这是没有办法的事。在django中,你如何定位一条记录?一般要三个值:appname, modelname和object_id。在ContentType就是保存了appname和modelname。因此使用GenericForeignKey你就只要两个值了。但GenericForeignKey本身还是要定义一下的。结果还是三项。使用其实还是挺简单的。看文档就清楚了。

      再看Topic。它定义了一个GenericRelation(Comment)。这样你可以通过instance.comments.all()来访问instance对应的所有的Comment实例。当然这个定义并不是必须的,如果不定义,你需要手工去Comment中查找,比如你已经有了一个topic的实例,现在要查找它的回复:

      ctype = ContentType.objects.get_for_model(topic)
      Comment.objects.filter(content_type__pk=ctype.id, object_id=topic.id)

      同时在一个Model中可以定义多个GenericForeignKey,因为GenericForeignKey在定义时可以指定content_type和object_id字段的名字,缺省是这两个,如果指定新的名字,就可以定义新的GenericForeignKey了。如:

          content_type = models.ForeignKey(ContentType, related_name='content_type')
          object_id = models.IntegerField()
          content_object = models.GenericForeignKey()
          own_type = models.ForeignKey(ContentType, related_name='own_type')
          own_id = models.IntegerField()
          own_object = models.GenericForeignKey(ct_field='own_type', fk_field='own_id')

      使用Generic Relation可能还有一些功能是不够充分的,在 Django 的邮件列表中有人提过。我发现的就是 create_or_get()好象不行。

      不管怎么样,如果你想让你的App可以处理不同的Model,如你的App是Tag, Comment等,可以考虑GenericForeignKey和GenericRelation来处理,可以简化你的处理。



      Trackback: http://tb.donews.net/TrackBack.aspx?PostId=1106217


      [点击此处收藏本文]  发表于2006年12月31日 5:09 PM




      正在读取评论……
      大名
      网址
      验证码
      评论