python应用篇之Web应用程序——Django入门(中)

     阅读:27

前言

  从上篇文章开始给大家介绍Django的入门,一套用于帮助开发交互式网站的工具。Django能够响应网站请求,还能让你更轻松地读写数据库、管理用户等。主要包括制定规范、建立虚拟环境、安装virtualenv、激活虚拟环境、安装Django以及在Django中创建项目、创建数据库以及最后查看项目。本文给大家介绍创建应用程序的相关内容。

创建应用程序

  Django项目是由一系列应用程序组成,它们协同工作,让项目成为一个整体。我们暂时只创建一个应用程序,它将完成项目的大部分工作。
  当前,在前面打开的终端窗口中应该还运行着runserver。请再打开一个终端窗口(或标签页),并切换到manage.py所在目录。激活该虚拟环境,在执行命令startapp,具体执行情况如下:

source ll_env/bin/activate
python manage.py startapp learning_logs
dir
dir learning_logs/

  具体执行的结果如下:

  命令startapp.appname让Django建立创建应用程序所需的基础设施。如果现在查看项目目录,将看到其中新增一个文件夹learning_logs。打开这个文件夹,看看Django都创建了什么。具体内容如下:

  其中最重要的文件是models.pyadmin.pyviews.py。我们将使用models.py来定义我们要在应用程序中管理的数据。其中的admin.pyviews.py将在稍后介绍。

一、定义模型

  我们来想想涉及的数据。每位用户都需要在学习笔记中创建很多主题。用户输入的每个条目都与特定主题相关联,这些条目将以文本的方式显示。我们还需要存储每个条目的时间戳,以便能够告诉用户各个条目都是什么时候创建的。
  我们打开文件models.py,看看它当前包含哪些内容:

from django.db import models
# 在这里创建模型

  这为我们导入了模块models,还让我们创建自己的模型。模型告诉Django如何处理应用程序中存储的数据。在代码
层面,模型就是一个类,就像前面讨论的每个类一样,包含属性和方法。下面是表示用户将要存储的主题模型:

class Topic(models.Model):
    """用户学习的主题"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示"""
        return self.text

  我们创建了一个名为Topic的类,它继承了Model——Django中一个定义了模型基本功能的类。Topic类只有两个属性:textdata_added。属性text是一个CharField——由于字符和文本组成的数据。需要存储少量的文本,如名称、标题或城市时,可使用CharField。定义CharField属性时,必须告诉Django该在数据库中预留多少空间。在这里,我们将max_length设置成了200(即200个字符),对这存储大多数主题的名来说足够了。
  属性date_added是一个DateTimeField——记录日期和时间的数据。我们传递了实参——auto_now_add=True,每当用户创建新主题时,这都让Django将这个属性自动设置成当前日期和时间。

  这里需要注意的是:要获悉可在模型中使用各种字段,请参考Django模型字段参考。就当前而言,我们无需全面了解其中的所有内容,但自己开发应用程序时,这些内容会提供极大的帮助。

  我们需要告诉Django,默认应使用哪个属性来显示有关主题的信息。Django调用方法__str()__来显示模型的简单表示。在这里,我们呢编写了方法__str__(),它返回存储在属性text中的字符串。

  这里需要注意的是:如果我们使用的是Python2.7,应调用方法__unicode__(),而不是__str()__,但其中的代码相同。

二、激活模型

  要使用模型,必须让Django将应用程序包含到项目中。为此,打开settings.py(它位于目录learning_log/learning_log中),我们将看到一个这样的片段,即告诉Django哪些应用程序安装在项目中,具体setting的位置如下图所示:

  具体settings.py中的内容如下:

"""
Django settings for learning_log project.

Generated by 'django-admin startproject' using Django 1.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'klx8i)7p@fa&jc=(wtc^0l^08p*jfuygqg_+d58h%#4k+e$juh'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'learning_log.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'learning_log.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

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


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

  这是一个数组,告诉Django项目是由哪些应用程序组成的。请将INSTALLED_APPS修改成下面这样,将前面的应用程序添加到这个元组中:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 添加我们自己的应用
    'learning_logs',
]

  具体的书写位置如下图所示:

  通过将应用程序编组,在项目不断增大,包含更多的应用程序时,有助于对应用程序进行跟踪。这里新建了一个名为My apps的片段,当前它只包含应用程序learning_logs。接下来,需要让Django修改数据库,使其能够存储与模型topic相关信息。为此,在终端窗口中执行下面的命令:

python manage.py makemigrations learning_logs

  命令makemigrations让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。输出表明Django创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中为模型topic创建一个表。具体如下:

  下面来应用迁移,让Django替我们修改数据库:

python manage.py migrate

  这个命令的大部分输出都与我们首次执行命令migrate的输出相同。我们需要检查的是相应的输出行,在这里,Django确认为learning_logs应用迁移时一切OK。具体运行情况如下:

  每当需要修改“学习笔记”管理的数据时,都采取如下三步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目。

三、Django管理网站

  为应用程序定义模型时,Django提供的管理网站让我们能够轻松地处理模型。网站的管理员可使用管理网站,但普通用户不能使用。接下来,我们将建立管理网站,并通过它使用模型topic来添加一些主题。

1、创建超级用户

  Django允许我们创建具备所有权限用户——超级用户。权限决定了用户可执行操作。最严格的权限设置只允许用户阅读网站的公开信息;注册了的用户通常可阅读自己的私有数据,还可以查看一些只有会员才能看的信息。为了有效地管理web应用程序,网站所有者通常需要访问网站存储的所有信息。优秀的管理员会小心对待用户的敏感信息,因为用户对其访问的应用程序有极大的信任。
  为在Django中创建用户,请执行下面的命令并按提示做:

python manage.py createsuperuser
ll_admin

  当我们执行命令createsuperuser时,Django提示我们输入超级用户的用户名。这里我们输入的是ll_admin,但我们可以输入任何用户名,比如电子邮件地址,也可让这个字段为空。我们需要输入密码两次,具体内容如下:

  具体体现在网站如下,我们这个网站出来后会让输入用户名和密码:

  这里需要注意的是:可能会对网站管理员隐藏有些敏感的信息。例如,Django并不存储我们输入的密码,而存储从该密码派生出来的一个字符串——散列值,当我们输入密码时,Django都计算其散列值,并将结果与存储的散列值进行比较。如果这两个散列值相同,就通过了身份验证。通过存储散列值,即便黑客获得了网站数据库的访问权,也只能获取其中存储的散列值,而无法获得的密码。在网站配置正确的情况下,几乎无法根据散列值推导出原始密码。

2、向管理网站注册模型

  Django自动在管理网站中添加了一些模型,如usergroup,但对于我们创建的模型,必须手工进行注册。我们是创建应用程序learning_logs时,Django在models.py所在目录中创建了一个名为admin.py的文件,具体如下:

from django.contrib import admin
# 在这里注册你的模板

  为向管理网站注册Topic,请输入以下的代码:

from django.contrib import admin
from learning_logs.models import Topic, Entry
admin.site.register(Topic)

  这些代码导入我们注册的模型Topic,再使用admin.site.register()让Django通过管理网站管理我们的模型。
  现在,可使用超级用户账户访问管理网站,并输入我们刚创建的超级用户的用户名和密码,我们将看到类似于如下所示的屏幕。这个网站让我们能够添加修改用户和用户组,还可以管理与刚才定义的模型topic相关的数据。具体如下:

  这里需要注意的是:如果我们在浏览器中看到一条消息,指出访问的网页不可用,请确认我们在终端窗口运行的Django服务器。如果没有,请激活虚拟环境,并执行命令python manage.py runserver

3、添加主题

  向管理网站注册Topic后,我们来添加第一个主题。为此,单击Topic进入主题网页,它几乎是空的,这是因为我们还没有添加任何主题。单击Add,你将看到一个用于添加新主题的表单。在第一个方框中输入Chess,再单击save,这将返回到主题管理页面,其中包含刚新建的主题。
  下满再创建一个主题,以便有更多的数据可供使用。再次单击Add,并在创建另一个主题Python。当我们单击save时,将重新回到主题管理页面,其中包含主题java和chess。

四、定义模型Entry

  要记录学到的Python知识,需要为用户可在学习笔记中添加的条目定义模型。每个条目都与特定主题相关联,这种关系被称为多对一关系,即多个条目可关联到同一个主题。下面是模型Entry的代码:

class Entry(models.Model):
    """学到的有关某个主题的具体知识"""
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)
    class Meta:
        verbose_name_plural = 'entries'
    def __str__(self):
        """返回模型的字符串表示"""
        return self.text[:50] + "..."

  像Topic一样,Entry也继承了Django基类Model。第一个属性Topic是一个ForeignKey实例。外键是一个数据库术语,它引用了数据库中额另一条记录;这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(或ID)。需要在两项数据之间建立联系时,Django使用与每项信息相关联的键。稍后我们将根据这些联系获取特定的主题相关联的所有条目。
  接下来属性text,它是一个TextField实例。这种字段不需要长度限制,因为我们不想限制条目的长度。属性data_added让我们能够按创建顺序来呈现条目,并在每个条目旁边放置。
  最后,我们在Entry中嵌入了Meta类。Meta存储用于管理模型的额外信息,在这里,它让我们能够设置一个特殊属性,让Django在需要时使用Entries来表示多个条目。如果没有这个类,Django将使用entrys来表示这个多个条目。最后,方法__str__()告诉Django,呈现条目时应显示哪些信息。由于条目包含的文本可能很长,我们让Django只显示text的前50个字符。我们还添加了一个省略号,指出显示的并非整个条目。

五、迁移模型Entry

  由于我们添加了一个新模型,因此需要再次迁移数据库。我们将慢慢地对这个过程了如指掌:修改models.py,执行命令python manage.py makemigrations app_name,再执行命令python manage.py migrate。下面来迁移数据库并查出输出:

python manage.py makemigrations learning_logs
python manage.py migrate

  生成了一个新的迁移文件——0002_entry.py,它告诉Django如何修改数据库,使其能够存储与模型entry相关信息。执行命令migrate,我们发下Django应用了这种迁移且一切顺利。具体如下:

六、向管理网站注册Entry

  我们还需要注册模型Entry,为此,需要将admin.py修成类似于下面这样:

from django.contrib import admin

from learning_logs.models import Topic, Entry

admin.site.register(Topic)
admin.site.register(Entry)

  返回到http://localhost:8000/admin,你将看到learning_logs下列出了Entries。单击Entries的Add链接,或者单击Entries再选择Add entry。具体如下:

  我们将看到一个下拉列表,让你能够选择要为哪个主题创建条目,还有一个用于输入条目的文本框。从下拉列表中选择Python,并添加一个条目。下面是我们添加的第一条条目:

  The Python Package Index (PyPI) hosts thousands of third-party modules for Python. Both Python’s standard library and the community-contributed modules allow for endless possibilities.

  当我们单击save的时候,将返回的主条目管理页面。在这里,我们将使用text[:50]作为条目的字符串表示的好处;管理界面中,只显示了条目的开发部分而不是所有文本,这使得管理多个条目容易的多。具体过程如下:

  创建好的效果如下:

  再来创建两条Python的相关内容,具体内容如下:

  The community hosts conferences and meetups, collaborates on code, and much more. Python’s documentation will help you along the way, and the mailing lists will keep you in touch.
  Python can be easy to pick up whether you’re a first time programmer or you’re experienced with other languages. The following pages are a useful first step to get on your way writing programs with Python!

  创建好的这三条数据效果如下:

  我们继续接着往下开发“学习笔记”时,这三个条目可为我们提供使用的数据。

七、Django shell

  输入一些数据后,就可以通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称为Django shell,是测试项目和排除其故障的理想之地。下面是一个交互式shell会话示例:

python manage.py shell
from learning_logs.models import Topic
Topic.objects.all()

  在活动的虚拟环境中执行时,命令python manage.py shell启动一个Python解释器,可使用它来探索存储在项目数据库中的数据。在这里,我们导入了模块learning_logs.models中的模型Topic,然后使用方法Topic.objects.all()来获取模型Topic的所有实例;它返回的是一个列表,称为查询接。具体过程如下:

  我们可以像遍历列表一样遍历查询集。下面演示了如何查看分配给每个主题对象的ID:

topics = Topic.objects.all()
for topic in topics:
	print(topic.id, topic)

  我们将返回的查询集存储在topics中,然后打印每个主题的id属性和字符串表示。从输出可知,主题Python的ID为3,具体如下:

  知道对象的ID后,就可获得该对象并查看其任何属性。下面来看看主题Python的属性textdate_add的值,具体如下:

t = Topic.objects.get(id = 1)
t.text
t.date_added

  具体的结果如下:

  我们还可以查看与主题相关联的条目。前面我们给模型Entry定义属性topic,这是一个ForeignKey,将条目与主题关联起来,Django能够获取与特定主题相关联的所有条目,具体如下:

t.entry_set.all()

  具体结果如下:

  为通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set。例如,假设你有模型Pizza和Topping,而Topping通过一个外键关联到Pizza;如果我们有一个my_pizza的对象,表示一张比萨,就可使用代码my_pizza.topping_set.all()来获取这张比萨的所有配料。
  在编写用户可请求的网页时,我们将使用这种语法。确认代码能获取所需的数据时,shell很有帮助。如果代码在shell中的行为符合预期,那么它们在项目文件中也能正确地工作。如果代码引发了错误或获取的数据不符合预期,那么在简单的shell环境中排除故障要比在生成网页的文件中排除故障容易的多。我们不会太多地使用shell,但应继续使用它阿里熟悉对存储在项目中的数据进行访问Django语法。

  这里需要注意的是:每次修改玩模型后,我们需要重启shell,这样才能看到修改的效果。要退出shell的话,可按Ctrl+D;如果我们使用的是windows系统,应按Ctrl+Z,再按回车键。

总结

  从上篇文章开始给大家介绍Django的入门,一套用于帮助开发交互式网站的工具。Django能够响应网站请求,还能让你更轻松地读写数据库、管理用户等。主要包括制定规范、建立虚拟环境、安装virtualenv、激活虚拟环境、安装Django以及在Django中创建项目、创建数据库以及最后查看项目。本文给大家介绍创建应用程序的相关内容,主要包括定义、激活模型、Django管理网站以及定义和迁移模型entry和最后的Django shell的简单使用。Python是一门注重实际操作的语言,它是众多编程语言中最简单,也是最好入门的。当你把这门语言学会了,再去学习java、go以及C语言就比较简单了。当然,Python也是一门热门语言,对于人工智能的实现有着很大的帮助,因此,值得大家花时间去学习。生命不息,奋斗不止,我们每天努力,好好学习,不断提高自己的能力,相信自己一定会学有所获。加油!!!