Django教程之四-----编写你的第一个Django应用(2)

这个教程接着第一个部分。我们将安装数据库,创建你的第一个模型,并且得到一个快速的介绍关于Django自动生成的管理站点。

1. 数据库安装

现在,打开mysite/settings.py。他是一个正常的Python模块,带有模块级的变量表明Django的设置。


默认的,配置使用SQLITE.如果你是一个数据新手,或者你仅仅对Django感兴趣,这将是最简单的选择。SQLite包含在Python中,所以你不需要安装任何其他的东西来支持你的数据库。当开始你的第一个真是项目时,然而你也许想使用一个可扩展的数据库例如PostgreSQL,来避免在路上切换数据库的麻烦。


如果你想使用另外一个数据库,安装喜爱的数据库绑定并且在数据库”默认“项中更改如下键来匹配你的数据库连接设置:

  • ENGINE--要么'django.db.backends.sqlite3','django.db.backends.postgresql','django.db.backends.mysql',或者'django.db.backends.oracle'.其他后端同样可以。
  • NAME--你的数据库的名称。如果你使用SQLite,数据库是你电脑上的一个文件;在那种情况下,NAME应该是全部的绝对地址,包括文件名。默认值,os.path.join(BASE_DIR,'db.sqlite3'),将文件储存在你的项目目录下。
如果你不是使用的SQLite作为你的数据,额外的数据诸如USER,PASSWORD,和HOST必须要添加。

非SQLite的其他数据库
如果你使用的数据库不是SQLite,请确认你现在已经创建了一个数据库。用"CREATE DATABASE database_name"来创建数据库,在你的数据库的交互提示符下。

还要确保在mysite/settings.py下用户提供的数据库有"创建数据库"的权力。这允许我们稍后要用到的一个测试数据库的自动创建。

如果你使用SQLite,你不需要在事先做任何事--数据库文件将会在他们使用的时候自动创建。

当你在编辑mysite/settings.py时,将TIME_ZONE添加到你的时区。


同样,注意在文件顶部的INSTALLED_APPS设置。那是在Django实例中激活的所有Django应用的名称。应用可以被用于多个项目,你可以打包并分发它们,以供其他人在他们的项目中使用。


默认的,INSTALLED_APPS包含如下的应用,都是伴随Django的:

  • django.contrib.admin -- 管理站点。你稍后就将使用它。
  • django.contrib.auth -- 一个计算系统。
  • django.contrib.contenttypes -- 内容类型的框架。
  • django.contrib.sessions -- 会话框架。
  • django.contrib.messages -- 消息框架。
  • django.contrib.staticfiles -- 管理静态文件的框架。
默认情况下,这些应用为了方便通用的情况下被包含的。

这里面的一些应用至少使用了一个数据表,所以,我们要在用之前在数据库中创建表。为了完成这个,运行如下命令:
$ python manage.py migrate
migrate命令搜寻INSTALLED_APPPS设置并且根据你的mysite/settings.py文件中的数据库设置来创建需要的数据表,并且应用程序附带迁移数据库(稍后)。你可以看到它应用的每一个迁移。如果你感兴趣,运行你数据库的命令行工具并且输入\dt(PostgreSQL),SHOW TABLES;(MySql),schema(SQLite),或者SELECT TABLE_NAME FROM USER_TABLES;(Oracle)来显示Django创建的表。

为了极简主义
像上面说的,默认的应用包含在普通的情况中,但并不是每个人都需要。如果你不需要任何它们或者不需要所有的,你可以在运行migrate之前从INSTALLED_APPS中自由注释或者删除相关的行。migrate命令只会运行在INSTALLED_APPS中的应用。

2. 创建模型 

现在我们来定义你的模型--本质上,你的数据库布局,带有额外的元数据。

哲理

模型是一个关于你的数据的单独的,明确的源的真相。它包含必要的字段和你储存数据的行为。Django遵循DRY Principle。目的是在一个地方定义你的数据模型并且自动从里面获取东西。


这包含迁移--不像Ruby On Rails,例如,迁移完全从你的模型文件中派生,并且实际是Django能读取来更新你的数据结构来匹配你当前的模型。

在我们简单的poll应用中,我们将创建2个模型:Question和Choice。一个Question有一个问题和一个出版日期。一个Choice有2个字段:choice的文本和一个投票结果。每一个Choice都关联到一个Question。


这些概念由简单的Python类展示。编辑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)

代码很直接明了.每一个模型都被一个继承自django.db.models.Model.的子类展示。每个模型都有很多类变量,每一个都代表了模型的数据库字段。


每一个字段都由一个Field类的实例展示--例如,CharField是指字符字段并且DateTimeField是指日期时间。这告诉Django每个字段应该存储什么类型。


每个Field实例的名称(例如question_text或pub_data)都是字段的名称,以一种机器友好的格式。你将在Python代码中使用这个值,你的数据库会将它用作一个列名称。


你可以对一个Field使用一个可选的第一位置参数来设计一个人类可读的名称。那被用在许多Django的内置部分,作为文档的时候更多。如果这个字段没有提供,Django将会使用机器可读名称。在上面例子中,我们只定义了一个人类可读的名称Question.pub_data。对于这个模型的所有其他字段来说,这个字段的机器可用名称足以作为人类可读名称。


一些Field类有需要的参数,CharField,例如,需要你给他max_length。那不仅仅在数据结构中使用,同样也在校验的时候,我们稍后会看到。


一个Field同样有不同的可选参数;在这个例子中,我们将votes的default指设为0.


最终,注意一个关联被定义了,使用ForeignKey。它告诉Django每一个Choice被关联到了一个Question。Django支持所有的常见的数据库关系:多对一,多对多,一对一。


3. 激活模型

那一点模型代码给Django提供了很多信息。使用它,Django可以:

  • 为这个应用创建一个数据库结构(CREATE TABLE 语句)。
  • 创建一个Python数据库访问API用于访问Question和Choice对象。
但首先,我们需要告诉我们的项目,polls应用已经被安装了。

哲理
Django应用是“可插拔的”:你可以在多个项目中使用一个应用,你也可以分开应用,因为他们不必和一个指定的Django安装绑定在一起

为了在我们的项目中包含应用,我们需要在他的INSTALLED_APPS设置的配置类中添加一个引用。PollsConfig类在Polls/apps.py文件中,所以它的带点路径是polls.apps.PollsConfig。编辑mysite/settings.py文件并且添加点路径到INSTALLED_APPS设置里。像这样:

mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

让我们执行另一个命令:
$ python manage.py makemigrations polls
你将会看到如下相似的东西:
Migrations for 'polls':
  polls/migrations/0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice
通过运行makegrations,你告诉Django你对你的模型做了一个改变(在这种情况下,你创建了一个新的)并且你想让这些改变作为一个迁移储存。

数据库迁移就是Django如何将改变储存到你的模型中(和你的数据库模式)--它们仅仅是磁盘上的文件。如果你喜欢你也可以阅读你新模型的迁移;它在polls/migrations/0001_initial.py。不用担心,我们不需要每次Django生成一个的时候就去阅读它们,但它们被设计为是人类可编辑的以防你想要手工的去改变Django如何改变的东西。

有一个命令将会为你迁移并且自动管理你的数据库结构--那就是migrate,并且我们稍后会讨论它--但首先,让我们看看那个迁移将会运行什么SQL。sqlmigrate命令将会提取迁移的名称并返回他们的SQL:
$ python manage.py sqlmigrate polls 0001
你将会看到如下相似的东西:
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;
注意如下:
  • 准确的输出取决你你使用的数据库。上面的例子是由PostgreSQL产生的。
  • 表名通过组合应用的名字和模型的小写名字--question和choice来自动产生(你可以覆写这个行为。)
  • 主键(IDs)是自动被添加的。(你也可以覆写这个)
  • 根据惯例,Django添加“_id”在外键的字段名称上。(是的,你也可以覆写这个。)
  • 外键关系是通过FOREIGN KEY的约束来显示形成的。不要担心DEFERRABLE部分;那就是告诉PostgreSQL在事务结束前不要强制执行外键。
  • 它会根据你使用的数据库来自适应,所以数据库指定的特殊字段诸如auto_increment(MySql),serial(PostgreSQL),或者integer primary key autoincrement(SQLite)将会为你自动处理。引用字段名也一样--例如,使用双引号或单引号。
  • sqlmigrate命令实际上不会在你的数据库上执行迁移--它仅仅将它打印到屏幕上所以你可以看到Django认为什么样的SQL是需要的。检查Django将做的事情是很重要的或者如果你的数据库管理员要求改变SQL脚本。
如果你敢兴趣,你可以运行python manage.py check;这个能检查你项目上的任何问题,而不需要执行迁移或者访问数据库。

现在运行migrate再一次来在你的数据库上创建这些模型表:
$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK
migrate命令获取所有未应用的迁移(Django跟踪这些使用在你的数据库中称为django_migrations的特殊的表应用的东西)并且在你的数据库中运行它们--本质上,将你对你模型做的的改变同步到你的你的数据库结构中。

迁移非常强大并且让你可以随着时间的推移修改你的模型,当你开发你的项目的时候,不需要去删除你的数据库或者表并且创建新的--它专门用于升级数据库,而不会丢失数据。我们会在稍后的教程中深入了解,但现在,记住做模型改变的3个步骤:
  • 改变你的模型(在models.py)
  • 执行python manage.py makemigrations来为这些改变创建迁移
  • 执行python manage.py migrate来讲这些改变应用到你的数据库
分开生成迁移和执行迁移的命令的原因就是您将提交迁移到您的版本控制系统并且将它们发送到你的应用中;它们不仅仅使你的开发更简单,它们也可以由其他的开发人员使用或者在生产中使用。

阅读django管理文档来获得关于manage.py套件能做什么的完整信息。

4.  使用API

现在,让我们跳到交互式的Python shell中并且来使用Django提供的免费API。为了调用Python shell,使用这个命令:
$ python manage.py shell
我们使用这个来代替简单的输入‘python’,因为manage.py设置DJANGO_SETTINGS_MODULE环境变量,它为Django提供了Python导入路径到你的mysite/settings.py文件中。

绕过manage.py

如果你不想使用manage.py,没问题。只要设置在mysite.settings中的DJANGO_SETTINGS_MODULE环境变量,启动一个普通的Python shell,设置Django:

>>> import django
>>> django.setup()

如果这抛出一个AttributeError,你可能正在使用一个不匹配这个教程版本的Django版本。那么你可以切换到老的教程或者升级你的Django版本。

你必须从manage.py相同的路径来运行python,或者确保那个路径在Python的路径中,那样import mysite才会生效。

想看更多关于这个的嘻嘻,你可以阅读django管理文档。

一旦你在shell,就可以探索数据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>]>
稍等一分钟。<Question:Question object>是,绝对的,关于这个对象的一个毫无帮助的展示。让我们通过编辑Question模型(在polls/models.py文件)来修正这个并且给Question和Choice都添加一个__str__():
polls/models.py
from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible  # only if you need to support Python 2
class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

@python_2_unicode_compatible  # only if you need to support Python 2
class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text
给你的模型添加__str__()方法是很重要的。不仅仅是方便你在和交互式提示符打交道,同样因为对象的展现是在Django的自动生成管理中使用的。

注意这是正常的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 datetime和from django.utils import timezone的添加。来指定Python的标准datetime模块和Django的在django.utils.timezone中的时区相关组件,各自地。如果你不熟悉Python中的时区,你可以了解更多在时区支持文件中。

保存这些改变并且通过再次运行python manage.py shell开始一个新的Python交互式shell:
>>> 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()
想了解更多关于模型关系的信息,阅读 访问相关对象 。想了解如何使用双下划线来通过API执行字段查找,阅读 字段查找 。想要完全了解数据库API的详细信息,阅读 数据库API引用

5. 引进Django管理

哲理

为你的工作人员或者客户生成管理站点来添加,修改和删除内容是不需要太多创造性的乏味的工作。因为那个原因,Django使用模型完全自动创建了管理接口。

Django是在一个新闻工作室环境下编写的,它在“内容出版商”和“公共”站点上分隔的非常清楚。站点管理者使用系统来添加新闻故事,时间,体育得分等等,并且那些内容显示在公共站点上。Django解决了这个问题,创建一个统一的接口给站点管理员和内容编辑者。

管理界面并不是为站点访问者准备的,它是给站点管理员使用的。

5.1 创建一个管理用户

首先我们需要创建一个能登陆到管理站点的用户。执行下面的命令:
$ python manage.py createsuperuser
收入你需要的用户名和密码。
Username: admin
你将会被提示输入你想要的email地址:
Email address: admin@example.com
最后一步式输入你的密码。你将会被要求输入密码2次,第二次是密码确认。
Password: **********
Password (again): *********
Superuser created successfully.

5.2 启动开发服务器

Django管理站点默认是激活的。让我们启动开发服务器来体验它。如果服务没有启动,可以使用如下命令:
$ python manage.py runserver
现在,打开一个浏览器并在你的基础域名后面添加'/admin/'。例如,http://127.0.0.1:8000/admin/。你将会看到管理登录界面。
                                                
由于缺省情况下翻译是自动打开的,所以登录界面会以你自己的语言来显示,这取决于你的浏览器设置并且如果Django有这个语言的翻译。

5.3 进入管理站点

现在,尝试使用之前创建的超级用户帐号登录。你应该看到Django管理首页:

你将会看到几个可编辑的内容:groups和users。它们由django.contrib.auth提供,Django的认证框架。

5.4  让poll应用在管理站点可修改

但是我们的poll应用在哪里?它不会显示在管理站点首页。

只有一件事要做:我们要告诉管理站点Question对象有一个管理接口。为了做成这样,打开polls/admin.py文件,并且像这样编辑它:
polls/admin.py
from django.contrib import admin

from .models import Question

admin.site.register(Question)

5.5 体验免费的管理功能

既然我们已经注册了Question,Django知道它应该被现实在管理站点首页:

点击“Questions ”。现在你在questions的“修改列表”页面。这个页面显示所有在数据库中的questions并且让你选择一个去修改。这里有我们之前创建的“What's up?”question:

点击“What's up?”question来编辑它:

需要注意的事情:
  • 表单自动从Question模型生成。
  • 不同的模型字段类型(DateTimeFiled,CharField)对应于适当的HTML输入小部件。每一个字段的类型都知道如何在Django管理站点显示自己。
  • 每一个DateTimeField都有免费的JavaScript缩写。Dates有“Today”缩写和日历弹窗,times有一个“Now”的缩写和一个方便的弹窗,列出了日常输入的时间。
页面的底部给你提供了一些选项:
  • save --保存修改并且返回这个对象的修改列表页面
  • Save and continue editing -- 保存修改并重载这个对象的管理页面
  • Save and add another -- 保存修改并且加载一个这个对象类型的新的,空白的形式。
  • Delete -- 显示一个删除确认页面。
如果“Date published”值不匹配你在前一个教程中创建的时间。那么点击“Save and continue editing”然后点击“History”在右上角。你将会看到一个页面,列出了通过Django管理对这个对象作出的所有修改,带有时间戳和修改的用户名:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值