zoukankan      html  css  js  c++  java
  • Django 中的 ForeignKey ContentType GenericForeignKey 对应的数据库结构

    在建立数据库时,通常会把各个对象的属性放在一个一个表中,通过表之间的关系即外键来描述和约束业务逻辑。

    Django 的 ORM 模型简化了一些数据库的操作,特别是外键,以及查询等功能,使得我们不用再写复杂的sql语句。

    表和关系的逻辑清晰并且可以跨数据库平台使用。

    下面主要记录一下 Django 在数据库中是怎样处理 ForeignKey 的。

    app 都是 Pinax 中所集成的。

    1、ManyToManyField

     

    class Url(models.Model):
    .........
        class Meta:
            verbose_name = _('url')
            verbose_name_plural = _('url')
    
    class Rule(models.Model):
    .........
    
        allowed = models.ManyToManyField(Url, blank=True, related_name="allowed",
                                         help_text=_("The URLs which are allowed "
                                                     "to be accessed by bots."))
    
        disallowed = models.ManyToManyField(Url, blank=True, related_name="disallowed",
                                            help_text=_("The URLs which are not "
                                                        "allowed to be accessed "
                                                        "by bots."))
        sites = models.ManyToManyField(Site)
    

    如上是 robots.models

    在数据库中表现为

    图[1]

    robots_rule 和 robots_url 两个表对应两个 model

    robots_rule_allowed, robots_rule_disallowed, robots_rule_sites 三个表分别对应 ManyToManyField

    如果在 rule 中查询 rule.allowed,Django 会自动锁定外键对应的表为 robots_rule_allowed 通过查询这个表得到对应的 url_id(多个),然后去 robots_url 表中提取相应记录。

    2、ForeignKey

    class ThreadedComment(models.Model):
    .......
        # Generic Foreign Key Fields
        content_type = models.ForeignKey(ContentType)
        object_id = models.PositiveIntegerField(_('object ID'))
        content_object = generic.GenericForeignKey()
        
        # Hierarchy Field
        parent = models.ForeignKey('self', null=True, blank=True, default=None, related_name='children')
            
        # User Field
        user = models.ForeignKey(User)
    

    先看 ForeignKey 字段。

    在表 threadedcomments_threadedcomment 中的结构如下(注意这个表名是由 <app_label>_<models_model> 组成)

    图[2]

    parent 是指向自身表的约束(用来表示一组回复,可以呈现 tree 形式的回复),允许为空,字段值为父 item 的 pk 值(即 id )。

    查询时,Django 会提取 parent_id 值,然后直接在自身表中搜索到父 id,即被回复的评论。

    注,所有的 model 不用给出 id 字段描述,因为 Django 会自动给出,而且做外键关联都是由 id 字段唯一确定的,当然这可以改...看document。

    user 是指向另一个表(Django 默认app User,用于登陆后台 admin)的外键,提取 user_id 值,再去 User 表中查询即可。


    ForeignKey 的 related_name='children' 标注了反向关系名称。

    例如,这个例子中指向的是 parent,而 parent 中没有任何标注,但是我们可以通过 <parent对象>.<children>+<_set> 

    parent对象.children_set() 来得到所有的 children 关联记录。


    3、GenericForeignKey

    这个东西比较好用,在我没有知道这个好东西之前,解决一个表关联多个外键时,是通过定义一个 type 字段来确定当前记录中的哪个外键是有效的。

    当然他这个原理也是这样的,不过多加了一个全局的 ContentType 表,使整体结构更加清晰。

    例如,我们还是拿上面的评论来做例子。为了使数据表结构清晰,评论都放在一个表中,那么,一个评论就可能是 blog 的, tweets 的,也可能是 shop 的。

    那就要定义一个 ContentType GenericForeignKey 来动态存储和得到外键所关联的表信息。

    content_type 是关联到 ContentType model 上的一个外键,实际上是一个 integer ,表示所关联的表类别,例如 blog post 表。

    object_id 标识的是所关联表中记录的 id 值,例如 post 表中的一个 blog 记录。

    content_type, object_id 是默认的值,如果需要更改可以在创建 GenericForeignKey 时传参。

    下面看看 django_content_type 表的结构

    图[3]

    app_label, model 组合是 UNIQUE

    app_label 是 app 的名称。

    model 是 app models 中的 model 名称。

    图[2]中content_type_id 和 object_id 分别对应的就是 model 中声明的 content_type 和 object_id 字段。

    通过content_type_id 可以在图[3]django_content_type 表中查询到对应关联的 

    名称name(verbose_name) 名称app_label(app名称) model名称(model的小写)


    通过 app_label, model 两个字段的拼接就可以得到表名,例如 id=41 blog_post 即为 content_type_id=41 对应的数据表,

    说明 comment(id=1-7) 对应的是 blog app 的 post 数据表。


    OK就是这样,其实很简单的东西,框架非常清晰,看文档的时候晕晕的。

  • 相关阅读:
    错误:CS0234: 命名空间“System”中不存在类型或命名空间名称“Linq”的解决方法
    DotNetNuke中Membership Provider机制
    解决异常“SqlParameterCollection 只接受非空的 SqlParameter 类型对象。”
    使用 Membership.ValidateUser(Login1.UserName, Login1.Password)验证用户
    布隆过滤器应用
    Paxos在大型系统中常见的应用场景(转)
    淘宝MapReduce作业特性分析(转)
    淘宝Hadoop集群的概况(转)
    内核模块管理(转)
    Centos启动流程(转)
  • 原文地址:https://www.cnblogs.com/sunblackshine/p/1947795.html
Copyright © 2011-2022 走看看