服务端编程(六)- Django - 工程的安装与配置 详解原理 ORM sql urlpattern 数据库迁移

前言 ´・ᴗ・`

  • 本节 就是我们学习Django的开端 我们将带您一步步构建出自己的一个图书馆应用
    类似我们现在图书馆的一套管理系统
    Django的学习大概是10篇文章的篇幅
    那 我们现在开始吧 ψ(`∇´)ψ
  • 本节默认您已经安装了
    • Pycharm
    • Django 3.0
    • 建议直接用pycharm安装django 实在不行采用pip
    • 本篇测试环境:
      • Pycharm 2020.1
      • django 3.0.2
      • python 3.7
  • 本篇内容将会帮助你学习…
    • 如何建立自己的第一个网站(有着django小火箭2333)
    • django工程目录的结构 以及相应文件目录的含义
    • 如何注写自己的应用
    • 如何进行数据库迁移
    • ORM 与 原生sql语句的概念
    • url 模式的配置 了解path() 转发重定向
    • 如何运行网站

框架的基本概念

unopinioned vs opinioned
这是个新词
意思就是 web框架的一种特点

  • opinioned 有主见的
    有种web框架擅长搞定特定的web建站问题 但是除了那些擅长点 其他的方面只有很有限的选择
  • un-opinioned 没主见的
    有些web框架 则是所有方面都会让你自由发展 你都可以自定义 或者说 选择的范围很大

scalable
scale 有点"尺寸"相关的概念 意思就是你的web应用 可大可小 适合很方便的调节 而不像传统的那种 牵一发而动全身

创建Django工程

我们直接利用pycharm的terminal终端 无需cmd
找到 你想放置django工程的文件夹 比如我选定了django_MDN 文件夹

在这里插入图片描述

然后terminal 输入:

django-admin startproject locallibrary

locallibrary 是项目名称 你可以随便改
在这里插入图片描述
然后你就会看到这样的层级目录:

在这里插入图片描述

工程文件解释

  • init.py 只是说明这玩意是个python package(包)
  • settings.py 包含所有网站的设定 即
    • 注册所有的web应用
    • 所有的静态文件的地址
    • 所有数据库的配置细节
  • urls.py 定义 一些url参数能够映射到资源的真实地址 或者 是处理此项请求的对象
    甚至可以用于映射一些web应用
  • wsgi.py 帮助你的web应用与服务器通信的
  • manage.py 创建应用 与db交互 启动服务器等

创建应用

在manage.py 同级目录 terminal运行:

python manage.py startapp catalog

如果不行 试试

python3 manage.py startapp catalog
py manage.py startapp catalog
py-3 manage.py startapp catalog

之后就能看到pycharm的目录显示:
在这里插入图片描述
或者你dir 查看目录内文件 更可信:
在这里插入图片描述

应用目录文件讲解

我们的目录应该是现在这样的:

locallibrary/
    manage.py
    locallibrary/
    catalog/
        admin.py
        apps.py
        models.py
        tests.py
        views.py
        __init__.py
        migrations/

大部分文件都是可以顾名思义的

  • views.py 存放view
    • view 你可以理解为 一些对象可以帮我们通过url 找到我们想要的资源 这些的东西 都在view下面 无论是object 继承于view 还是函数 —— 作为view的方法
  • models.py 存放data models
    也就是所谓的ORM —— 我们通过django的model 对数据库建立模型 然后就像操作对象 对象实例 对象属性 一样改变数据库的表 行 与 列的数据
  • tests.py 存放tests
  • admin.py 管理网站的一些配置(configuration)
    比如你作为图书馆借阅应用的 admin 你可以在admin 网页(应该是admin site) 后台管理书本信息的录入
    意味着 给你一个空间操作这些数据库信息 只不过不对用户开放
  • apps.py web应用的登记(register)
  • migrations folder 当你用python更改数据库以后 我们需要迁移(migration),意思自动帮你更新数据库 当然你学过MySQL直接用sql 再事务commit 就是真正更新了
  • init.py 照旧 这玩意就是说明这目录是个py包 可以被工程的别的部分引用

注册应用

我们已经创建了一个名为catalog的应用
现在 我们在setting.py 中进行注册
找到 INSTALLED APP 这个列表 添加上catalog 如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth', # authentic 验证
    'django.contrib.contenttypes',
    'django.contrib.sessions', # session 会话
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'catalog'
]

可见django已经帮我们内置了一些应用 比如用户验证authentication 会话session 等

添加数据库信息

还是在setting.py

  • MySQL 我就接着我的MySQL教程 来继续配置数据库了 如下:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "django", #数据库名字
        'USER':'root', # 一般默认就是root
        'PASSWORD':'2333', # 你的密码 
        'HOST':'localhost', # 我们现在还是本地服务器跑着学习 后面上真的云服务器
        'PORT':'3306' # 端口号
    }
}

你得在mysql创建一个空数据库,把名字填在“NAME”里面

  • 或者你也可以用默认的sqlite 虽然不适合实际的商业应用 但是自己玩玩还是ok的
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

如果是其他数据库 你可以参考官网
或者google csdn等等

别的setting

  • timezone
    我们设成中国的时间咯:
    TIME_ZONE = ‘Asia/Shanghai’
    TIME_ZONE = ‘Asia/Hong_Kong’
    当然你可以设成别的 请看
    主要是database name那边
  • SECRET_KEY. 目前我们一个demo不用管 不过到产品环节的时候就要更改了 涉及安全问题
  • DEBUG. 这个就是打印debug的日志用的 生产环节就设计成False就行了

url.py 配置 (hook up)

我们说过 url.py管得是url参数的映射 具体来说 我们用path()函数 将url的参数对应一个view(视图)
可以想象一下 我们通过一个url参数 比如\best 去查看NBA MVP的时候 肯定出来的是一个页面 也就是一个视图 所以path就是帮我们找到 我们要的网页

大概有三种用法 后面还会补充更多 这里只是混个脸熟:)

  • 绑定到函数——view.function
    1. 添加包 from my_app import views
    2. 书写正则表达式'^home' 匹配网址 path(r’^home’, views.home, name=‘home’)
  • 绑定到对象_class 继承于 view
    1. 添加包 from other_app.views import Home
    2. 书写正则表达式'catalog/<id>/' 匹配网址 path(r’‘catalog//’’, Home.as_view(), name=‘home’)
    3. 注意 id 匹配任何在catalog/任何字符/ 里面的任何字符 也就是可以传参 然后用来 比如展现到你的前端网页上
  • 将另一种path连接方式绑定到你想要的连接方式(重新使用)
    1. import: from django.urls import include, path
    2. path(‘blog/’, include(‘blog.urls’))

然后当你的path()太多的时候 我们直接用url pattern —— 一个列表 来装他们 于是我们也可以这么添加新的path

from django.urls import include
from django.urls import path

urlpatterns += [
    path('catalog/', include('catalog.urls')),
]

urlpattern 这个列表包含所有path

注意 django已经默认给我们url pattern 加了一项:

urlpatterns = [
    path('admin/', admin.site.urls),
]

这个意思就是 使用admin/ 可以访问所有站点(site)上的url 也就是我们写在url pattern里面的一堆path
为啥要有这句?-- admin是管理者(我们)访问的 当然应该可以测试所有的url(也是我们写的url模式)

当url太多该怎么办?urlpattern

可以想象 假设你的网站有100个web应用 你应当怎么管理至少上百个url pattern?
很明显我们会把一些细小的url匹配模式 放到我们应用里面去 这就是我们必须在我们的应用catalog里面
加上一个url.py 文件 内容如下:

from django.urls import path
from catalog import views

urlpatterns = [

]

那么 当浏览器请求的url 到达我们网站(site) 有点类似根目录 我们site会调用根目录的url.py
然后根目录的url.py就应该转发(或者说重定向redirect)到 应用catalog的URL.py 也就是上面我们写的那个

问题是 如何写清楚“转发” 这个操作

我们在根目录的url.py 里面写上:

urlpatterns = [
    path('admin/', admin.site.urls),                     #1
    path('catalog/', include('catalog.urls')),           #2
    path('', RedirectView.as_view(url='/catalog/', permanent=True)),             #3
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) #4

第二句就是 意思 你访问我网站的catalog 我就把这个请求转给catalog.urls 也就给catalog目录下的url.py处理
第三句很有意思

  • 观察到 写url pattern的地方是空的 意思是 所有 url请求
  • 因为我们只有一个应用 干脆所有网站的事交给catalog去做
  • 于是我们把所有url 转发到 ‘/catalog/’ —— 第二句 我们已经定义过了的 url映射套路
  • 所以就是 第二句把访问catalog的全部踢皮球给 catalog/url.py
  • 然后第三句把皮球踢给第二句catalog/url.py (从未见过如此厚颜无耻之徒)
    第1句不解释 上面讲了

第四句 你或许这么访问过 提供vue.js 的官方网站
也就是地址栏输入网址 得到的是人家的源码
那么有没有想过 我们的服务器也可以这么提供我们写的前端代码呢?比如.html .js .css
这就是返回静态文件
当然Django倒是默认不支持这么弄 但是不方便我们debug
于是第四句就是搞定这个的——让我们的服务器也能返回 前端代码

总之 最后我们要往根目录urls.py 写的代码是:

from django.contrib import admin
from django import views
from django.urls import include
from django.urls import path
from django.views.generic import RedirectView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
    path('admin/', admin.site.urls),                     #1
    path('catalog/', include('catalog.urls')),           #2
    path('', RedirectView.as_view(url='/catalog/', permanent=True)),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) #4

迁移数据库 migration

这 是我们运行网站前的最后一步 :)

你会好奇 我们并没有进行任何数据库的编写 那么 为啥还迁移数据库呢?
事实上 django帮你写好了一部分数据库的结构 用于后续管理 (别找了 不在model.py里面^_^)
我们创建的应用 应用相关信息等等 都会保存在django自动创建的数据库中

另外 希望你别忘了
Django 使用对象关系映射器(ORM)将Django代码中的模型定义映射到底层数据库使用的数据结构。
那么 纯ORM 纯原生sql 或者两者混用都是ok得了 个人项目无所谓 团体项目 这个得沟通好:)

这里 我们要安装好 mysql-client 库 直接用pycharm安装就行
然后
我们在terminal 与manage.py 同级目录 逐行运行:

python manage.py makemigrations 
python manage.py migrate

注意理解这个迁移过程:实际上 make migrations 只是通过我们ORM python代码 (model.py里面的) 转换成sql 语句 然后 真正执行操作的是 migrate
有种说法是 这个migrate 只是我们数据库版本控制(version control)的一个提纲(schema)而已

其他迁移的命令细节 可以看官网

ORM vs sql

如果我不放心他自动生成的那些sql怎么办 也就我不信任ORM呢?
我们可以查看他生成的代码
首先 找到所有的migrations
运行:

python manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
catalog
 (no migrations)
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

我们看到熟悉的auth catalog sessions 意味着这些都是 已经安装好的app (登记好的)
如果没有在setting登记 就会出现:
在这里插入图片描述
第二步 我们拿到app名称 还有相应的migrations的名字 就可以这样运行:

python manage.py sqlmigrate auth 0001

注意 这个migration原名贼长 幸好我们可用代号 0001
然后我们就得到了:

BEGIN;
--
-- Create model Permission
--
CREATE TABLE "auth_permission" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varch
ar(50) NOT NULL, "content_type_id" integer NOT NULL REFERENCES "django_content_type" ("id") D
EFERRABLE INITIALLY DEFERRED, "codename" varchar(100) NOT NULL);
--
-- Create model Group
--
CREATE TABLE "auth_group" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(80
) NOT NULL UNIQUE);
CREATE TABLE "auth_group_permissions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "grou
p_id" integer NOT NULL REFERENCES "auth_group" ("id") DEFERRABLE INITIALLY DEFERRED, "permiss
ion_id" integer NOT NULL REFERENCES "auth_permission" ("id") DEFERRABLE INITIALLY DEFERRED);
--
-- Create model User
--
CREATE TABLE "auth_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "password" varchar
(128) NOT NULL, "last_login" datetime NOT NULL, "is_superuser" bool NOT NULL, "username" varc
har(30) NOT NULL UNIQUE, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL,
 "email" varchar(75) NOT NULL, "is_staff" bool NOT NULL, "is_active" bool NOT NULL, "date_joi
ned" datetime NOT NULL);
CREATE TABLE "auth_user_groups" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user_id" i
nteger NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED, "group_id" integ
er NOT NULL REFERENCES "auth_group" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE TABLE "auth_user_user_permissions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "
user_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED, "permi
ssion_id" integer NOT NULL REFERENCES "auth_permission" ("id") DEFERRABLE INITIALLY DEFERRED)
;
CREATE UNIQUE INDEX "auth_permission_content_type_id_codename_01ab375a_uniq" ON "auth_permiss
ion" ("content_type_id", "codename");
CREATE INDEX "auth_permission_content_type_id_2f476e4b" ON "auth_permission" ("content_type_i
d");
CREATE UNIQUE INDEX "auth_group_permissions_group_id_permission_id_0cd325b0_uniq" ON "auth_gr
oup_permissions" ("group_id", "permission_id");
CREATE INDEX "auth_group_permissions_group_id_b120cbf9" ON "auth_group_permissions" ("group_i
d");
CREATE INDEX "auth_group_permissions_permission_id_84c5c92e" ON "auth_group_permissions" ("pe
rmission_id");
CREATE UNIQUE INDEX "auth_user_groups_user_id_group_id_94350c0c_uniq" ON "auth_user_groups" (
"user_id", "group_id");
CREATE INDEX "auth_user_groups_user_id_6a12ed8b" ON "auth_user_groups" ("user_id");
CREATE INDEX "auth_user_groups_group_id_97559544" ON "auth_user_groups" ("group_id");
CREATE UNIQUE INDEX "auth_user_user_permissions_user_id_permission_id_14a6b632_uniq" ON "auth
_user_user_permissions" ("user_id", "permission_id");
CREATE INDEX "auth_user_user_permissions_user_id_a95ead1b" ON "auth_user_user_permissions" ("
user_id");
CREATE INDEX "auth_user_user_permissions_permission_id_1fbb5f2c" ON "auth_user_user_permissio
ns" ("permission_id");
COMMIT;

如果不放心 就这么检查

另外 除了我们在ugly的mysql客户端输入sql
我们也可以在sqlyog输入 就好像我们之前做的那样
在这里插入图片描述
当然 还可以调用sql在python的语言接口(implementation)
也就是调用pyMysql库 这是它的官方文档
这几乎就是真的写sql语句了其实 不再是ORM 对象关系映射(Object Relational Mapping)

那 运行网站吧

python3 manage.py runserver

我们就这样运行网站吧 本地服务器 默认端口8000

你可以输入网址到地址栏: http://127.0.0.1:8000/
然后你就会拿到:
在这里插入图片描述
注意 这并不意味你成功了:)
忘了吗?我们的url映射把所有的皮球踢给了catalog/url.py然而那玩意现在是空的:)
所以他说 你并没有做任何 configuration on urls pattern

解决问题 很简单 我们去配置咯
然后这个问题留给下一节 目前 我很享受看到django的小火箭 抖动的样子:)
在这里插入图片描述

将django火箭改成中文

你可以稍微配置一下:
找到根目录的setting.py:
在这里插入图片描述
把这两句改成中国:

LANGUAGE_CODE = 'zh-hans'
 
TIME_ZONE = 'Asia/Shanghai'

然后启动服务器python manage.py runserver
中文版小火箭:
在这里插入图片描述

总结 ´◡`

这一节 我们终于弄出来人生中第一个网站 虽然展现的是django送我们的小火箭
当然不用担心 这是我们的一小步 全栈领域的一大步
在这里插入图片描述
当然对于我来说 这篇文章这么长能够通过审核也是不容易

下一节 我们聊聊数据库的控制ORM

另外,小姐姐祝贺你完成第一个django 的 demo
在这里插入图片描述

发布了52 篇原创文章 · 获赞 57 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43178828/article/details/104276111