钉子の次元

Dimpurr – 千里之行,始於足下。

Django 学习手记 二 建立模型层

这篇文章记录了如何创建 Django 项目的一个子应用并编写 models.py 。如有错误,请不吝赐教。

Django 框架同样遵循 MVC 开发模式。在 Django 中,我们定义 Model 数据模型并自动同步生成数据库和后台,由 Template 和 Views 处理界面并转交 URLconf 控制器。

因为 MVC 中 C (Controller) 的部分主要交给框架进行,我们也将 Django 称为 MTV (Model, Template, Views) 模式。 参见

一个 Django 项目有两种层级,称为 project 项目 和 app 应用。一般来说,一个 project 就是一个完整的站点,比如一个大型论坛或者门户站点。而一个 app 就是一个有完整功能、可复用的应用,比如一个私信组件,一个投票组件或者一个讨论版。

一个 project 即使没有 app 也能独立运行,但是一个独立的 app 可以在不同的 project 中复用。另外,如果你要使用 Django 的模型功能即数据库层,模型必须存放在 app 中。

创建应用并建立模型

执行 ./manage.py startapp polls 命令,来创建一个名为 polls 的 app 。同样, Django 会自动在项目根目录下创建一个名为 polls 的目录和一系列文件。我们会以 Django 官方教程为例,先编写一个投票应用。

在这个应用中,我们需要 Quesntion 问题和 Choice 选项两个类,并且添加一系列的属性。

首先,我们编辑 polls/models.py ,这个文件就是你的模型:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    authors = models.ManyToManyField(Author)

        # class Meta:
        # date = ["pub_date"]
        # text_filed_name = “question”

class Choice(models.Model):
    question = models.ForeignKey(Question)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

代码很容易理解。为 question_text 这样的属性名提供一个易读的名字会方便接下来的开发。

对于一个类,提供一个名为 Meta 的内嵌类,可以存放一些「不是 Field」的 Field ,比如排序信息,数据库名。详见

应用更改

编辑完成后,我们修改 project 根目录的 settings.py ,找到 INSTALLED_APPS ,在已安装应用列表的底部加上我们自己的新 app 'polls' 。这里也列出了其他的自带 app ,如果用不着,可以注释掉。

运行 ./manage.py makemigrations polls 以生成更改。这个命令同时会生成类似 polls/migrations/0001_initial.py 的脚本文件,它们是人类可读的,但是一般你不需要太过在意。使用 ./manage.py sqlmigrate polls 0001 命令可以查看生成的数据库命令。

最后使用 ./manage.py migrate 迁移命令,应用更改到数据库。

下篇文章将会介绍如何使用 ./manage.py shell 测试当前的数据模型、以及关于元素间互相绑定和关联的详情。元素绑定详见

Field 类型参考

下面是一些常用的 Field 类型和部分特有的参数。

  • ForeignKey(Class_Name, limit_choices_to={‘key_name’: value}, on_delete=models.SET_NULL)
    • 绑定一个其他类的元素(类名、可以是 ‘self’, 对于目标的属性的限制条件,关联目标被删除时的操作)
    • 一般会生成一个下拉列表
  • ManyToManyField # 多对多关联,用法同上
  • OneToOneField # 单对单关联,用法同上
  • CharField(max_length = 100) # 字符
  • TextField(max_length = 100) # 字符
  • SlugField # 为 CMS 预留的别名栏,用法同上
  • DateField(auto_now/auto_now_add)
    • 日期 (自动设为最后编辑日期/自动设为首次创建日期)
  • TimeField # 时间
  • DateTimeField # 日期和时间,参数同上
  • IntegerField # 实数
  • BigIntegerField # 大实数
  • FloatField # 浮点数
  • BooleanField # True or False 单选
  • EmailField # 邮件
  • IPAddressField # IP 地址
  • GenericIPAddressField(protocol=ipv4, unpack_ipv4=False)
    • 自动获得 IP 地址(协议限制,解包去掉 ::ffff: 前缀)
  • URLField # URL 地址
  • FileField(upload_to = ‘photos/%Y/%m/%d’ )
  • ImageField
    • 图片,参数同上,可以通过 height_field 和 width_field 熟悉拿到宽高
  • FilePathField(path="/home/images", match=“*.png”, recursive=True, allow_files = True, allow_folders = False)
    • 文件路径(起始路径,正则匹配,包含子目录,允许选择文件,允许选择目录)

Field 参数参考

以下是一些其他常用的通用参数。

  • blank = true # 该属性可为空
  • null = Ture # 该属性可为 null
  • choices = a_list_or_a_tuple # 该属性从一个列表中选择,值的具体写法见列表结束
  • default = 'A default value' # 设置默认值
  • validators = [validate_even] # 设置数据有效性验证器 详见

使用如下形式的,最终的每个元素是 (‘option value’, ‘option name’) 形式的元组的多层嵌套元组,可以定义一个任意层级的可选列表。最终将会在 HTML 中生成多个 select 下拉列表的形式。第一项是 None 的元组会被作为默认选项。详见

MEDIA_CHOICES = (
    ( None, 'Unknown' ),
    ( 'Audio', ( ('vinyl', 'Vinyl'), ('cd', 'CD'), ) ),
    ( 'Video', ( ('vhs', 'VHS Tape'), ('dvd', 'DVD'), ) ),
)
  1. CDog酱说道:

    当年高二的时候研究的呢~好怀念的感觉 >_<

  2. Ad说道:

    比3D建模还要复杂

  3. exoticknight说道:

    简单易懂好好好

  4. 192.168.1.1说道:

    保存下来慢慢看,好好学习下

  5. LancerComet说道:

    搜索至此,孩子你真不得了。

    1. LancerComet说道:

      rhytune还会有下文么?高中生毕竟学业还是很紧张的,保持关注

      1. Dimpurr说道:

        我完全不打算放弃这个项目,不过具体是什么时候重启开发,就不太好说了 …… 最坏的情况也许要等到高中毕业。但愿不会。

  6. 悖论说道:

    最近也在研究这个框架。。。但感觉路途漫漫。。。。

  7. Rakume说道:

    新主题好赞,不过留言板那边完全没回复框?

    1. Dimpurr说道:

      五一回到家之后除了睡觉都在赶工码代码 Orz 到现在字体还没弄好、单页模版忘了做、移动响应式还没好 …… TvT 希望今晚能搞定

      1. Rakume说道:

        这字体的确挺蛋疼ww

        1. Dimpurr说道:

          上述的那些玩意儿都弄好了,响应式也 600px – 1000px 做了三段,球建议 QvQ

          1. Rakume说道:

            响应式貌似没做完?还有谁回复谁看的有点乱。。

            1. Dimpurr说道:

              手机版响应式有 Bug ,刚才才修订好 …… 子回复这个是取消了缩进,就分割线那对一级评论有点区分,不知道还有什么不影响美观的柔和的表示评论层级的办法 ……

              1. Rakume说道:

                前面加个箭头?还有为何名字要斜体?

                1. Rakume说道:

                  手机回复的时候,底下也错位了Orz

                  1. Dimpurr说道:

                    我把子回复的作者名前加了箭头了 …… 错位的问题我这边没发现呢 …… 可以的话球截图?

                    名字的话是因为 WordPress 默认输出 cite 我没有动。因为要给名字区分的话,感觉加粗、下划线这些效果都不太好,干脆留着一开始的斜体了。语义上斜体的确符合「作者」的标识。

                    1. Rakume说道:

                      又是没强刷的结果,醉了醉了。

  8. Jimmy说道:

    要不是点击发表评论浏览器有提醒,不然根本没发现这里居然有个评论框==
    给子评论加缩进吧,看着怪难受

    1. Dimpurr说道:

      现在评论已经做了适配宽屏的居中布局了,再做缩进就 …… 奇怪了吧
      话说为什么你们都不萌这种布局呢 (´・_・`) 明明回复的谁根本就不重要嘛 ((

      1. Jimmy说道:

        看惯了单栏&双栏 (:3 」∠) 不知道回复的谁感觉就乱套了

      2. oott123说道:

        因为讨论的确是有上下文的……

    2. Dimpurr说道:

      给评论框加上了内阴影不知道会不会明显一点 TvT

      1. Jimmy说道:

        没看出区别╮(╯◇╰)╭

      2. LancerComet说道:

        其实作者以外的评论在左侧加5em的padding就好很多.

        1. Dimpurr说道:

          试了下,那样真心有点难看 Orz

          1. Rakume说道:

            其实回复他人的全小头怎么样?

  9. xloger说道:

    诶,话说你这个新主题首页的那种滚动模式跟我想做的很类似,可惜我还不会(:з)∠)

    1. Dimpurr说道:

      还新主题,你做出来过几个 ((
      这个是用了个 jQuery 库,你翻翻我引用的 JS 文件就有了,使用方法也就两行。