民意调查Django实现(一)

经过两天的python2.7的学习和Django的基础部分的了解,在Django的官网上,我看到了一个实例程序,该实例程序是通过一个基本民意调查程序的完成来深入理解Django框架。

该民意调查有两个部分:

  • 一个用于用户查看民意调查问卷并且投票网页
  • 一个管理端用于你去添加,修改和删除民意调查项

在之前的博客中,我已经明确的说明了Django的安装和使用。同时也说明了如何使用python函数来查看Django的版本号。在这里,我使用的是Django 1.7。

这里写图片描述

我的python版本使用的是python2.7.9,在上面的图片中也显示的很透明了。

创建一个项目

首先需要说明的是,我会在我的目录~/Documents/Polls/ 下面创建我的Django项目。

在我们使用Django的脚本创建项目的时候,就会自动生成一个带有原始代码的项目,这个项目是Django一些设置的集合,其中包括数据库配置,Django特有选项和应用特有的设置。

下面创建我们的新项目:

首先我需要切换到我要保存代码的目录:

cd  ~/Documents/current/Polls
django-admin startproject mysite

django-admin命令将会在你的当前目录下创建一个项目。

下面我们来看一下创建的项目的目录。

这里写图片描述

这些文件是:

  • 外部的mysite是刚刚我们创建的项目的名称,同时也是我们项目的容器。可以随意命名
  • manage.py : 该脚本提供了多种使你和Django项目交互的方法。
  • 内部的mysite目录是你项目的真实的Python包。他的名字是Python的包名,你在它内部来导入你需要的东西
  • mysite/init.py:一个空文件,该文件告诉Python这个目录是一个Python包
  • mysite/settings.py:该Django项目的设置/配置文件。
  • mysite/urls.py:该Django项目的URL声明;
  • mysite/wsgi.py:ASGI web服务器的入口,在部署你的Django项目的时候会了解到。

数据库安装

现在,打开,mysite/settings.py文件。他是一个代表Django设置的Python模块。

在默认情况下,配置使用的是SQLite数据库。SQLite是内置在Python中的,所以如果你要使用SQLite的话,无需安装其他任何东西。如果你想要使用其他数据录,需要去安装合适的数据库绑定,并且修改下面的语句来使用你的数据库连接设置。

在默认情况下,我们的settings.py文件中的有关数据库的配置是这样的:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

由于我们现在使用的是mysql,所以,我们需要把这个地方修改一下,改成这样的:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db_polls',
        'USER':'root',
        'PASSWORD':'0504zhao,',
        'HOST':'',
        'PORT':'',
    }
}

其中,default下面的各个选项的意思为:

  • ENGINE: 代表我们使用的数据库引擎,其中常用的有’django.db.backends.sqlites3’,’django.db.backends.postgresql_psycopg2’,’django.db.backends.mysql’,’django.db.backends.oracle’。当然,他也支持其他数据库。
  • NAME: 你所使用的数据库的名称。如果你使用的是SQLite的话,数据库应该是你计算机上的一个文件,这样的话,NAME就应该是文件的全路径。
  • USER: 连接数据库所使用的用户名
  • PASSWORD: 连接数据库所使用的密码
  • HOST: 数据库所在的主机地址
  • PORT: 数据库所占有的端口

接着编辑我们的mysite/settings.py文件,讲其中的TIME_ZONE设置成我们中国的时区’Asia/Shanghai’。

TIME_ZONE = 'Asia/Shanghai'

注意位于setting.py上面的INSTALLED_APPS设置。他承载这在Django实例中被激活的应用的名称。App可以用到多个项目中,你可以打包和发布他们被别人的项目使用。

在默认情况下,INSTALL_APPS包含下面的app,所有的这些都来自Django.

  • django.contrib.admin - admin站点。在后面会用到
  • django.contrib.auth - 一个验证系统
  • django.contrib.contenttypes - 用于内容类型的框架
  • django.contrib.sessions - 一个session框架
  • django.contrib.messages - 一个信息框架
  • django.contrib.staticfiles - 管理静态文件的框架

这些应用都是被默认包含的用于常用功能。

这些应用中有些至少使用一个数据库表,所以,我们在我们使用他们之前,我们需要在数据库中创建表格。我们需要运行下面的命令来实现:

# 在项目工程下
python manage.py migrate

下面我们来执行一下这个命令:

这里写图片描述

migrate会查看INSTALLED_APPbiaogeS设置来创建必要的数据库表。我们连接我们的mysql数据库看一下都生成了哪些表格。

+----------------------------+
| Tables_in_db_polls         |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+

这都是生成的和app相关的数据库表格。

开发服务器

下面我们来验证一下我们的Django项目是否成功运行。切换到我们的项目根目录下,运行下面的命令:

python manage.py runserver

我们将会看到命令行下会有这样的输出:

这里写图片描述

我们可以看到,在上面的输出中,已经告诉我们如何去打开我们的网站。在浏览器中输入下面的网址:

https://127.0.0.1:8000

如果成功运行,则网页会打开下面的内容:

这里写图片描述

但是有一个需要说明的是,如果你要部署该项目,不能使用开发服务器,因为他仅仅用于开发测试使用。

当然,在我们运行服务器的时候,可以指定IP和端口来访问该网站。
python manage.py runserver 0.0.0.0:9000

注意:runserver是会自动重新加载的,当你便携完成代码之后,无需重新运行该服务器。

创建模板

你的app可以在你的Python项目的任何位置。在这里,我们创建一个app和manage,py在一个目录下,所以,他可以被引入作为顶层模块而不是mysite的一个子模块。

我们使用下面的命令来创建一个模块,名字叫做polls。

python manage.py startapp polls

创建完成polls之后,我们看一下我们项目的目录列表。

.
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── settings.py
│   ├── settings.pyc
│   ├── urls.py
│   ├── urls.pyc
│   ├── wsgi.py
│   └── wsgi.pyc
└── polls
    ├── admin.py
    ├── __init__.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

3 directories, 15 files

这个目录结构会支持一个民意调查应用.

我们开始的第一步就是在你的Django中编写一个数据库Web app来定义你的模块 - 也就是你的数据库布局,带有传统的元数据。

一个模型是你的数据的真实的单一的,传统的源码。他包含必要的域和你要存储的数据的行为。Django遵循DRY规则。目标就是在一个地方定义你的数据模型并且自动从他那里导出字符串。

在我们实例项目中,我们创建两个模型:Question和Choice。Question拥有一个question域和一个发布时间域。Choice有两个域:选项的文本和一个总的投票结果。每一个Choice都和一个Question相连。

这些概念都是通过简单的Python类来实现的。编辑polls/models.py文件。

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length = 20)
    pub_date = models.DateTimeField('date published')

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

上面的代码是非常直接的。每一个模型都是’django.db.models.Model’的子类。每一个模型都有一些类变量,每一个变量都代表这在模型中的一个数据库表域。

每一个域都是由Field类的一个实例代表的–例如CharField 用于字符域和DateTimeField用于日期时间。这告诉Django每一个域是什么样的数据类型。

每一个Field实例的名字就是域的名称(例如question_text或者是pub_date)。你可以在你的Python代码中使用这些值,你的数据库将会使用他们作为列名称。

每一个Field类可能需要有多个参数。

最后,注意关系的定义,使用ForeignKey。那告诉Django每一个Choice是和一个单一的Question相关的。Django支持所有通用的数据库关系:多对一,多对多和一对一。

激活模型

刚刚那一小段代码给了Django很多信息,使用它,Django能够:

  • 为这个app创建一个表格(CREATE TABLE statements)
  • 创建一个用于访问Question和Choice对象的Python数据库访问API

但是,首先我们需要告诉我们的项目polls app被安装了。

编辑mysite/settings.py文件,修改INSTALLED_APP设置,最后添加’polls’。就像下面这样:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

接着,我们运行下面的命令来通知Django创建相应的表格。

python manage.py makemigrations polls

你将会看到下面的输出:

Migrations for 'polls':
  0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice

通过运行makemigrations,你就会告诉Django你对你的模型做了修改(在这里,我们创建了新的模型),这些改变将会被存储为migration。

Migration是Django如何保存你的模型的改变-他们是在你磁盘上的文件。你可以读取你的新模型的migration。他是文件polls/mogrations/0001_initail.py。我们来看一下:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Choice',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('choice_text', models.CharField(max_length=200)),
                ('votes', models.IntegerField(default=0)),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.CreateModel(
            name='Question',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('question_text', models.CharField(max_length=20)),
                ('pub_date', models.DateTimeField(verbose_name=b'date published')),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.AddField(
            model_name='choice',
            name='question',
            field=models.ForeignKey(to='polls.Question'),
            preserve_default=True,
        ),
    ]

在这里我们可以看出,他自动为我们的每一个数据表生成了一个id键值。不要担心。不必在修改或者是新建模型之后就查看这个文件。他仅仅就是设计来用户可编辑来做一些人工的改变。

有一个命令能够运行migrations并且自动管理你的数据表–称为migrate。一会我们再看这个命令,首先我们看一下migrations将会运行什么样的SQL语句。我们使用sqlmigrate命令来查看。

python manage.py sqlmigrate polls 0001

下面是运行的结果(其实就是一些sql语句的结合):

BEGIN;
CREATE TABLE `polls_choice` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `choice_text` varchar(200) NOT NULL, `votes` integer NOT NULL);
CREATE TABLE `polls_question` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `question_text` varchar(20) NOT NULL, `pub_date` datetime NOT NULL);
ALTER TABLE `polls_choice` ADD COLUMN `question_id` integer NOT NULL;
ALTER TABLE `polls_choice` ALTER COLUMN `question_id` DROP DEFAULT;
CREATE INDEX `polls_choice_7aa0f6ee` ON `polls_choice` (`question_id`);
ALTER TABLE `polls_choice` ADD CONSTRAINT `polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id` FOREIGN KEY (`question_id`) REFERENCES `polls_question` (`id`);

COMMIT;

注意下面:

  • 真实的输出依赖于你正在使用的数据库。我的例子的输出是mysql的
  • 表的名称自动由app的名称(polls)和小写的模块的名称(question,choice)联合生成(你可以重载这个行为)
  • 主键(IDs)自动被添加(你也可以重载)
  • 按照惯例,Django向外键域名称后附加’_id’(你还是可以重载)
  • 外键关系是明确的FROEIGN KEY限制。
  • sqlmigrate命令不会引用这些sql语句,他仅仅是将应用语句打印出来工大家参考

如果你有兴趣,可以运行命令python manage.py check,他会检查在没有创建数据库的时候的有关你项目的所有的问题。

现在运行migrate命令来创建相应的模型数据表。

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, contenttypes, polls, auth, sessions
Running migrations:
  Applying polls.0001_initial... OK

Migrations是非常强大的,他能够使你在任何时候修改你的模型,而不必删除原来的数据库和表重新构建。他支持更新你的数据库而不会丢失数据。在后面的实践中我们再详细介绍,在这里,只需要记住三个步骤:

  • 修改你的模型(在models.py中)
  • 运行python manage.py makemigrations来创建这些改变的migrations
  • 运行python manage.py migrate向数据库中应用这些改变

玩转API

现在,我们进入交互式Python shell然后尝试使用一个Django给予的API。我们使用下面的命令激活Python shell.

python manage.py shell

我们使用这个命令而不直接使用”python”,因为manage.py设置DJANGO_SETTINGS_MODULE环境变量,这个变量给予Django Python的导入路径到你的mysite/setting.py文件中。

如果你不使用manage.py,也没有问题,那么只需要你手动的设置DJANGO_SETTINGS_MODULE环境变量到mysite.settings中,就是这样:

python
import django
django.setup()

不过这个setup()方法只有Django1.8版本才能使用。

当我们进入shell的时候,探索一下数据录API

>>> from polls.models import Question, Choice   # 导入我们刚刚编写的模块类

# 在系统中还没有Question实例
>>> Question.objects.all()
[]

# 创建一个新的Question
# 在默认设置文件中是支持time zone的
# Django希望pub_date是当前时间,所以使用timezone.now()
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# 保存对象到数据库中。你必须显示的调用save()函数
>>> q.save()

# 现在他有了一个ID。注意,这个可能是"1L"而不是"1"
>>> q.id
1

# 通过Python属性访问模型域值
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# 通过属性修改值,然后调用save()
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all()显示在数据库中所有的问题
>>> Question.objects.all()
[<Question: Question object>]

等一下,对于我们来说是没用的。我们通过编辑Question模型(位于polls/model.py文件中)来完善它,并且向Question和Choice中各添加一个unicode()函数。

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length = 20)
    pub_date = models.DateTimeField('date published')

    def __unicode__(self):    # 在python3中是 __str__()
        return self.question_text

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

    def __unicode__(self):      # 在python3中是 __str__()
        return self.choice_text

这样完成之后,我们退出刚刚的shell,重新进入:

>>> from polls.models import Question,Choice
>>> Question.objects.all()
[<Question: What's up?>]

这样显示的就不是object了,显示的就是Question的名称了。所以,推荐大家以后在编写models模块的时候,新建类的时候尽量加上这个函数。

这一小节就到这里了,后面我们会接着进行学习。

注意:我的代码已经上传到我的github:

下载源码

posted @ 2015-11-23 17:18  陈洪波  阅读(361)  评论(0编辑  收藏  举报