从0开始学习Django-web开发(2)

接着我们的上一篇文章继续往下进行.在这一篇文章当中我们会设置一个数据库,创建我们的第一个model.并且快速的介绍一下Django自动生成admin站点.

数据库设置

首先打开mysite/settings.py文件, setting.py是存储Django设置信息的地方.
简单介绍一下settings.py文件里INSTALLED_APPS的含义:

django.contrib.admin : #admin站点, 稍后我们会用到
django.contrib.auth : #authentication系统
django.contrib.contenttypes : #content types的框架
django.contrib.sessions : #session框架
django.contrib.messages :#messaging框架
django.contrib.staticfiles : #管理静态文件的框架

在这些应用程序中至少需要使用一个数据库, 所以在使用之前我们需要先创建数据库.只要运行下面的代码就可以了:

python manage.py migrate

migrate指令会查看INSTALLED_APPS中的设置,并根据mysite/settings.py文件中的设置创建数据库并将数据库关联到APP.

创建models

接下来会定义我们的models.
在我们的poll APP 中会创建两个模型QuestionChoice.
Question有一个问题的描述字段和发布日期字段.Choice有一个文本描述字段和和统计字段.每一个Choice都关联着一个'Question'.
这是最简单的Pyhton类.按照下面的样子编辑polls/models.py文件.

from django.db import models


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


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

代码非常的简单明了,每一个model都是的django.db.models.Model
的子类.每一个model都有几个变量, 每一个变量都对应着model在数据库中的一个字段.
每一个field都是 Field
类的一个实例.CharField
是用来存储字符的,DateTimeField
是用来存储时间的.这些告诉了Django每一个字段存储的数据类型.
每一个Field
实例的名字, 就是字段的名字(例如上面的question_textpub_date).你会在Python的代码中使用这些值, 数据库则会使用这些字段名作为每一列的名字.
某些Field
需要洗一些必须的参数, 比如 CharField
需要你指定max_length
.这些不仅是数据库需要的信息,而且会用来做验证, 待会就知道了.
一个Field
也可以有几个可选参数.在这个例子中我们会将votes的默认值设置为0.
最后需要注意的是我们用ForeignKey
来定义两个模型之间的关联关系.这让Django知道每一个Choice都关联这一个单独的Question.
Django支持所有的关系类型: 一对多, 多对都, 一对一.

激活models

上面那一点点代码给了Django很多信息.根据上面的信息, Django能够:

  1. 为我们的APP创建一个数据库的表
  2. 创建可以用Python访问数据库的API来访问Question 和 Choice对象.
    但是首先我们应该让我们的项目知道polls app已经被安装了.
    为了将app包含进我们项目里, 我们需要在
    INSTALLED_APPS
    中配置一个引用,PollsConfig类在'polls/apps.py'文件中,所以用点语法的话, 他的路径应该是polls.apps.PollsConfig, 编辑mysite/settings.py文件, 并且将配置文件的路径添加在INSTALLED_APPS
    中:
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

现在Django知道他包含了polls APP,现在我们运行另外一个命令:

ython manage.py makemigrations polls

你在终端中应该看到下面这些输出:

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

运行makemigrations指令相当于你告诉Django你的models做了一些改变并且你想保存这些改变.
Django会将你对Models的改变存储为一个文件, 文件的名字和路径polls/migrations/0001_initial.py,你可以通过查看这个文件来查看你所做的改变.
migrate
命令可以让数据库自动应用这些改变,我们稍后就会用到.但是首先我们来看一下这些改变会用到哪些SQL语句.sqlmigrate
可以输出这些改变名字, 并且输出这些SQL语句.

python manage.py sqlmigrate polls 0001

你应该会看到类似下面的输出:
<pre>
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" serial NOT NULL PRIMARY KEY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Add field question to choice
--
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")
DEFERRABLE INITIALLY DEFERRED;
COMMIT;
</pre>

如果你有兴趣的话你也可以运行python manage.py check
,这个指令会检查你项目中遇到的问题,并且不会将这些改变应用到数据库上, 不会对数据库造成任何影响.
现在, 再次运行 migrate
指令, 来创建那些模型在数据库中所对应的table.

python manage.py migrate

migrate
指令会应用之前没有应用的改变.
Migrations指令非常有用,可以让你在开发项目的过程中随时改变models,而不用删除数据库也造成任何数据的丢失.后面我们会深入讨论这些内容,但是现在请记住下面这三步对models做出的改变:

  1. 修改models(在 models.py文件中)

  2. 运行python manage.py makemigrations
    来存储这些改变

  3. 运行python manage.py migrate
    将这些改变应用到数据库
    之所以将将这些改变的存储和应用分成几个指令是为了在你项目的版本控制系统中记录这些操作.它不仅会让你的开发工作变得非常简单, 而且这对其他开发者非常有用.

使用这些API

接下来我们进入, Python与shell的交互环节,并练习使用Django 给我们提供的API.使用下面的命令调用Python shell:

python manage.py shell

我们可以通过输入简单的 python指令代替上面的指令,因为 manage.py文件里设置了DJANGO_SETTINGS_MODULE这个环境变量.它给Django的mysite/settings.py文件提供了Python的导入路径.
注意:接下来的操作是在虚拟环境下进行的, 因为时间的关系, 在完成上面的内容后, 我退出了服务器的操作.后来在家继续进行接下来的操作的时候没办法继续往下尽心.然后就想是不是没有进入虚拟环境的问题,然后就进到虚拟环境下在自己建的项目mystie目录下继续往下操作. 果然OK!
当我们进入了shell以后, 我们就可以浏览 database API:

>>> from polls.models import Question, Choice   # Import the model classes we just wrote.

# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> q.save()

# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> q.id
1

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object>]>

一定要注意每一行语句前面的空格数量, 因为Python对代码样式的要求非常严格, 如果空格数量过多会包语法错误.一定要注意.
<Question: Question object>完全无法帮助我们了解Question对象的详细信息.所以接下来, 我们来修复这个问题, 编辑Question model (在 polls/models.py 文件里)然后在QuestionChoice添加一个 str()
方法.当然有些对Python语法不是很熟悉的同学可能不知道如何退出shell环境, 只需要在终端里输入:

>>> exit()

就可以了.
编辑polls/models.py文件:

vim polls/models.py

为我们的models添加str()
方法是非常重要的,它不仅在我们开发的时候提供参考, 而且在Django自动生成的admin在使用这些对象的时候也会用到.
这些只是普通的python方法, 让我们添加一个自定义的方法, 哪怕仅仅只是做一个示范.
polls/models.py文件中, 加入下面的代码:

import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

注意开头添加的import datetimefrom django.utils import timezone两行代码分别引用了Python标准的 datetime
模块和Django中django.utils.timezone
时间相关的工具类.
保存这些改动.
这里给对Vim编辑器不熟悉的同学一些提示, 通过vim filename打开文件后点击i键可以进入编辑模式, 如果要退出vim的编辑模式, 先点击`esc`键, 然后点击`:wq`可以保存并退出编辑模式.
保存上面的更改并通过键入python manage.py shell重新进入python的交互模式.

>>> from polls.models import Question, Choice

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>

# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

想要了解更多关于模型的信息可以参考 Accessing related objects.想要了解更多或者如何使用双下划线通过API查看字段信息,可以参考 Field lookups.想要了解更多的关于数据API的详细信息可以参考 Database API reference.

Django Admin的介绍

创建一个admin用户

首先我们需要创建一个可以登录admin站点的用户.运行下面的这个命令:

python manage.py createsuperuser

输入你想要的用户名并且按enter键

Username: admin

然后会提示你输入邮件地址

Email address: admin@example.com

最后一步是输入你的密码,会提示你输入两次, 第二次是确认第一次输入的密码.

Password: **********
Password (again): *********
Superuser created successfully.
开始开发服务器

Django的admin站点, 默认是激活的.接下来我们开始开发服务器并且访问它.
如果服务器并没有运行起来, 用下面的指令启动它:

python manage.py runserver

(如果按照之前我写的从0开始搭建nginx-uWSGI-Django-python服务器配置好了uWSGI的自启动服务, 那么是不需要执行上面的指令的站点默认试运行的')
在浏览器中输入http://139.xxx.xxx.129:8000/admin/ 访问admin站点.
你应该会看到admin的登录界面

Paste_Image.png
进入admin站点

现在用你上一步创建的超级用户登录admin站点, 你应该会看到Django admin站点的首页.

Paste_Image.png

你应该看到了可以编辑groups和users, 这些是有Django的与认证相关的django.contrib.auth
框架提供的.

让poll app在admin中可以编辑

但是我们Polls APP去哪里了呢?它并没有显示在admin站点的首页.
只要做一件事就可以了: 我们只用告诉 adminQuestion对象是admin的一个接口就可以了.所以我们打开polls/admin.py文件, 并按照下面编辑:

from django.contrib import admin

from .models import Question

admin.site.register(Question)
探索自由的管理功能

现在我们注册了Question,现在Django知道了他应该在首页显示Question.
注意: 这里我遇到了一个坑, 就是我按照上面的步骤在admin.py中导入了Question 以后, 刷新admin首页并没有出现Question 列表, 而是再我重新启动服务器以后再访问的时候才出现了Question 列表
点击Questions, 现在你应该位于questions的修改修改列表页,这里显示了数据库中所有的questions你可以选择并修改他们.这里有一个我们之前创建的“What’s up?”的question.

Paste_Image.png

点击“What’s up?” question并且编辑它.

Paste_Image.png

这里有几点需要注意:

  1. 这个表单是从Question model中自动生成的
  2. model中不同类型的属性字段((DateTimeField
    , CharField
    ))有相应类型的输入框.Django的adimn站点知道如何正确的显示不同类型的输入框
  3. 每一个 DateTimeField
    都会有相应的JavaScript的快捷按钮, 日期有一个Today的快捷按钮并且有一个日历的弹框,时间有一个Now的快捷按钮, 并且有一个快捷按钮让你可以选择时间.
    在这个页面的底部有几个选项:
  4. Save - 爆粗努修改并返回上一页
  5. Save and continue editing - 保存修改并且重新加载这一页
  6. Save and add another - 保存修改, 并且加载一个这种类型的对象的空表单.
  7. Delete - 显示一个确认删除的页面.
    如果“Date published”的值与你在上一篇文章中创建的时候的时间不一致.
    通过点击 “Today” 和 “Now”按钮改变“Date published”的值.然后点击页面下面的“Save and continue editing.”.然后点击右上角“History” .你就会看到通过Django的admin站点对这个对象所有的修改历史, 包括修改的时间和修改的人.
Paste_Image.png

.
现在了你已经熟悉了models 的API和admin站点.在下移偏重我们会学习如何为我们的 polls app添加更多的views.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容