Django学习笔记(二)App创建之Model

通过实例学习, 构建一个投票(Polls)Application, 目标结果包含两个site, 一个site用来显示投票问题以及投票结果(即将展示出来的网站), 另一个site用来管理Poll实例的增删改查(即后台内容管理CMS).

1.   创建工程

django-admin.py startproject mysite

在当前目录下, 会创建一个mysite的工程目录. 那么我们的代码放在哪里比较好呢? 可能会放到OS自带的server根目录(document root)下, 比如/var/www, 这样我们可以直接通过浏览器访问到代码. 不过这样代码的安全性不是很好,所以建议放到server根目录以外的目录下.

工程结构:

 1   mysite/
 2     manage.py
 3     mysite/
 4       __init__.py
 5       settings.py
 6       urls.py
 7       wsgi.py
 8 
 9   外层的mysite目录, 是工程的整个容器, 对django是没什么意义的, 所以随便改什么名字都可以.
10   manage.py是一个命令行工具, 来管理整个工程, --help来查看相应的命令.
11   内层的mysite目录, 是工程的一个包, 同时也是工程的入口, 我们需要通过这个包名来引用我们需要的各种配置和变量.
12   mysite/__init__.py: 说明当前这个目录mysite/是一个python包.
13   mysite/settings.py: 工程的配置文件
14   mysite/urls.py:工程的路由调度
15   mysite/wsgi.py:wsgi服务器的入口点(How to deploy with WSGI)

2.   内部开发服务器

python manage.py runserver

进入工程目录下,执行以上命令,django内部自带开发服务器(一个纯粹由python写的轻量级服务器)将会启动. 浏览器中访问localhost:8000, 

我们会看到一个“Welcome to Django”, it worked.

注:改变监听端口命令:python manage.py runserver 8080      改变监听所有公共IPs: python manage.py runserver 0.0.0.0:8000

3.   数据库设置

更改DATABASES ’default’选项

Engine - django.db.backends.*, oracle、mysql或者sqlite3等, 其他的后端比如(south.db.) sql_server.pyodbc
NAME – 数据库名称,如果使用sqlite3,此处应该是文件的绝对路径(e.g.C:/homes/user/mysite/sqlite3.db).请注意此处用斜杠,而不是反斜杠.
USER – 数据库用户名(sqlite不需要)
PASSWORD – 数据库密码(sqlite不需要)
HOST – 数据库主机地址 “127.0.0.1” or "**.**.com"
PORT - 主机开放端口 一般为3306 如果使用mysql或者PostgreSQL,首先必须在数据库服务器端口,执行创建数据库命令,确保设置中的数据库是存在的,而sqlite不需要,同步数据时会默认创建.

python manage.py syncdb(即将删除,用migrate替代)

django会自动同步 INSTALLED_APPS 下的所有Apps到数据库中,表现形式为各个App创建相应的数据表,与此同时,第一次执行会创建一个用于管理数据表的超级管理员 super administrator.

4.   Model创建

项目中所有用到的Apps其实都是由python的包组成的.

  Project和 App的区别:

  App是一个旨在专门完成某项工作的Web应用, 比如Blog、Session记录等, 而Project是配置文件和一系列Apps集合所组成的. 一个工程中可以有多个App, 一个App可以存在多个Project中(即可复用性). 一个App可以放在任意地方, 只需要添加到Python path中, 让工程可以找到.

python manage.py startapp polls

执行后会在工程根目录下创建一个polls目录, 包含__init__.py view.py models.py etc. 如果想把某个App包含在单独的目录下, 比如/mysite/apps, 进入到apps目录后, python ../manage.py startapp polls, 不过以后引用要从apps开始导入, from apps.polls.models import Poll, Choice.

下面在pollsmodels.py中输入如下代码:

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

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

代码清晰明了, 两个类均继承于django.db.models.Model, 变量都是Filed实例, 两个类的关系由models.ForeignKey(多对一)确定, Poll是Choice的外键, 即一个Poll对应多个Choice.

将Polls配置到setting.py文件的 INSTALLED_APPS 中(不要忘记每个App配置后用逗号分隔), 然后执行python manage.py syncdb, 在数据库中创建好Polls App的数据表. python manage.py sql polls, manage.py validate等命令可以用来进一步研究django在后台运作的原理.

5.   DB API交互

python manage.py shell

运行此命令后, manage.py命令会设置 DJANGO_SETTINGS_MODUL 环境变量, 这提供了django引用python全局路径., 我们需要的资源都有了出处.

 1 >>> from polls.models import Poll, Choice   # Import the model classes we just wrote.
 2 # No polls are in the system yet.
 3 
 4 >>> Poll.objects.all()
 5 []
 6 
 7 >>> from django.utils import timezone
 8 >>> p = Poll(question="What's new?", pub_date=timezone.now())
 9 # Save the object into the database. You have to call save() explicitly.
10 >>> p.save()
11 
12 >>> p.id
13 1
14 
15 >>> Poll.objects.all()
16 [<Poll: Poll object>]

稍等一下, [<Poll: Poll object>]显示不清晰, 对直观的感受没什么帮助, 解决办法是: 在models.py中为不同的类添加一个__unicode__方法, 在python3中, 因为规范了字符串的统一处理, 需要用 __str__ 进行替换.

1 class Poll(models.Model):
2     # ...
3     def __unicode__(self):  # Python 3: def __str__(self):
4         return self.question
5 
6 class Choice(models.Model):
7     # ...
8     def __unicode__(self):  # Python 3: def __str__(self):
9         return self.choice_text

python2.*版本没有统一unicode和Ascii编码的处理, 所以针对字符串会经常出现错误, 比如在__unicode__中return self.id, CMD中遍历输出unicode数据, 都是编解码错误的原因.

重新载入python manage.py shell,

>>> from polls.models import Poll, Choice
# 确保 __unicode__() 已工作. >>> Poll.objects.all() [<Poll: What's up?>] # 以下语句相当于 Poll.objects.get(id=1). >>> Poll.objects.get(pk=1) <Poll: What's up?> >>> p = Poll.objects.get(pk=1) # 显示所有与p相关的choice集合 -- 目前为止为none. >>> p.choice_set.all() [] # 创建三个choice实例. >>> p.choice_set.create(choice_text='Not much', votes=0) <Choice: Not much> >>> p.choice_set.create(choice_text='The sky', votes=0) <Choice: The sky> >>> c = p.choice_set.create(choice_text='Just hacking again', votes=0) # 可通过choice实例访问外键, 由于__unicode__, 只返回“What's up”. >>> c.poll <Poll: What's up?> # 取得所有P下的choice集合. >>> p.choice_set.all() [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] >>> p.choice_set.count() 3

That's it.