第一个Django demo
平台:Pycharm Django
使用 Pycharm 进行开发,需要提前在 Pycharm 中(File > Settings > Project: Python > Project Interpreter)下载 Django ,安装过程会自动把 Django 路径加载到系统的环境变量中。
进入 cmd 查询 Django 是否安装成功。出现以下一系列命令,说明已安装成功。
创建第一个项目 guest ,可在 Pycharm 的 Terminal 中使用命令行创建
G:\Python>django-admin startproject guest
创建完成,Django 自动生成以下目录结构
guest/ manage.py guest/ __init__.py settings.py urls.py wsgi.py
guest/manage.py : Django 项目的命令行工具,三种命令模式可选:
$ django-admin <command> [options] $ manage.py <command> [options] $ python -m django <command> [options]
guest/guest/__init__.py : 空文件夹,表示 guest 目录是 python 的标准包
guest/guest/settings.py : 项目的配置文件,包含Django 模块应用配置、数据库配置、模板配置等
guest/guest/urls.py : 关于项目的 URL 声明,定义 URLconf
guest/guest/wsgi.py : 提供服务的入口,暂未知 wsgi 有何用
guest/manage.py : 一个命令行工具,通过 命令 python manage.py 可以查看 manage 所提供的命令
创建第一个应用
G:\Python\guest>python mangage.py startapp sign
在 Terminal 中使用以上命令创建 sign 应用后,会自动生成一些文件(templates 目录不是自动生成),如下面目录结构:
目录文件说明:
migrations/ : 用于记录models 中数据的变更
admin.py : 映射 models 中的数据到 Django 自带的后台
apps.py : 用于应用程序配置
models.py : 创建数据表模型,与数据库相关操作对应
views.py : 视图文件,控制向前端输送内容
启动项目,使用 runserver 命令
G:\Python\guest>python manage.py runserver
Django 默认在127.0.0.1:8000 进行监听,在浏览器输入 http://127.0.0.1:8000 , 若可见 It worked! 提示,说明 Django 已经可以工作。
PS: Django 在 settings.py 中默认开启 DEBUG = True,若改为 False ,则无法正常打开网页。 127.0.0.1 指向本机(本电脑)
使用模板
创建模板使用 templates 目录,Django 会默认去查找该目录下面的 HTML 文件,在上面已创建的 sign 应用下面,创建了一个
templates/index.html 文件
简述 Django 工作流(以默认访问的地址为例):
向浏览器发送一个请求,如 http://127.0.0.1:8000/index/ ,Django 默认在127.0.0.1地址,端口8000 上进行监听,根据 URL 的路径 /index/,
到 urls.py 文件中对 /index/ 路径进行匹配(前提:在 urls.py 中对该路径已进行配置),匹配到该路径,则调用相应的视图函数,匹配不到,则提示网页找不到(404)。
url 路径匹配模式如下:
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index), #添加index/ 路径配置
]
上面/index/ 路径已经提前配置好,下一步根据路径,去调用相应的视图函数 views.index (请求指向 sign 应用下的 views.py 文件中的 index 函数)。该函数定义如下:
def index(request):
return render(request, "index.html")
该函数使用 render 模板,返回一个已经写好的 HTML 页面。该模板放在 templates 目录下,使用render() 函数进行调用,浏览器最终呈现 index.html 页面的内容(返回响应)。
各模块要点
Django MTV 开发模式
M(Models): 代表模型,进行数据存取。处理与数据相关的事物,既如何存取,如何验证有效。
T(Template): 代表模板,表现层。处理如何展示相关页面或其它类型文档。
V(View): 代表视图,业务逻辑层。处理如何存取模型及调用恰当的模板展现数据,可看做是模型与模板之间的桥梁。
URLconf模块 urls.py
1、URLconf 模块包含了 URL 模式(简单的正则表达式)到视图函数(views.py)的简单映射。URLconf的值通过 ROOT_URLCONF 进行设置, 在 /settings.py 中
'''python ROOT_URLCONF = 'guest.urls' ''' Django 会加载 urls.py 文件,并在 urlpatterns 中依次匹配每个 URL 模式,匹配到就指向对应的视图函数处理。
2、使用正则表达式定义URL模式,使用 re_path() 方法而不是 path() ,命名正则表达式组的语法是(?P <name> pattern),其中name是参数变量的名称,pattern是要匹配的模式。
例子:
from django.urls import path, re_path from sign import views urlpatterns = [ re_path('sign_index/(?P<eid>[0-9]+)/', views.sign_index), # 签到 ]
URL调度器使用参考:https://docs.djangoproject.com/zh-hans/2.0/topics/http/urls/
3、在 guest/url.py 文件的 urlpatterns的
path() 中插入 include() 方法,在当包括其它 URL 模式时你应该使用 include()。函数 include() 允许引用其它 URLconfs。每当 Django
遇到 :func:~django.urls.include 时,它会截断与此项匹配的 URL 的部分,并将剩余的字符串发送到 URLconf 以供进一步处理。
例子:
from django.urls import path, re_path, include # 导入 sign 应用 views 文件 from sign import views urlpatterns = [ path('api/', include('sign.urls', namespace="sign")), # 接口根路径 ]
sign.urls 有自己的路径,任意一个都可以放在 /api/ 后面,形成完成的路径。例如其中某一个匹配例子(在 sign.urls 中的 urlpatterns):
from django.urls import path from sign import views_if app_name = "sign" urlpatterns = [ # sign system interface: # ex : /api/add_event/ path('add_event/', views_if.add_event, name='add_event'), ]
include() 使用 参考:https://docs.djangoproject.com/zh-hans/2.0/intro/tutorial01/
views.py
(Django 中的视图的概念是「一类具有相同功能和模板的网页的集合」)
1、 index() 视图函数,接受 Web 请求并且返回 Web 响应。(Django 只要求视图返回的是一个 HttpResponse
,或者抛出一个异常)
2、 login_action(request) 处理登录请求,客户端发送的请求信息都包含在 request 中。request.POST 通过 .get() 方法获取“username”和“password”所获取的用户名和密码
3、 HttpResponseRedirect() 对路径进行重定向,将登录成功后的请求指向了 /event_manage/ 目录
4、 render()方法:render(request, template_name, context=None, content_type=None, status=None, using=None)
作用:把 context(一个给定的上下文字典)的内容, 加载进 templates(一个给定的模板)中定义的文件, 并通过浏览器渲染呈现. 参数讲解: request: 是一个固定参数.
template_name: templates 目录下定义的文件, 要注意路径名. 比如'templates\polls\index.html', 参数就要写‘polls\index.html’
context: 要传入文件中用于渲染呈现的数据, 默认是字典格式
content_type: 生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值。
status: http的响应代码,默认是200.
using: 用于加载模板使用的模板引擎的名称。
5、auth.authenticate() 方法,用于登录认证。它接受两个参数,用户名 username 和 密码 password ,并在用户名和密码正确的情况下返回一个 User 对象。 否则 authenticate() 返回None。
6、auth.login() 方法,用于用户登录。该函数接受一个 HttpRequest 对象和一个 User 对象作为参数并使用Django的会话(session)框架把用户的ID保存在该会话中。
7、user.is_active 判断用户名和密码是否有效。
8、 @login_required 此装饰器显限制某个视图函数必须登录才能访问,默认跳转的 URL 中会包含“/accounts/login/”,需要在 urls.py 中添加新的路径配置。
9、Django 中 objects.all()、objects.get()、objects.filter() 的区别
· all 返回的是QuerySet(查询集)对象,程序并没有真的在数据库中执行SQL语句查询数据,但支持迭代,使用for循环可以获取数据。
· get(** kwargs) 返回的是Model对象,类型为列表,说明使用get方法会直接执行sql语句获取数据。
· filter(** kwargs) 和get类似,但支持更强大的查询功能,查询到的值唯一且不变。
10、request.session.get('user') 为了获取 sessionid ,用于认证用户
11、Paginator(guest_list, 2),Django提供了一个分页器类Paginator(django.core.paginator.Paginator),可以很容易的实现分页的功能。该类有两个构造参数,一个是数据的集合,另一个是每页放多少条数据
分页器相关源码参考
https://docs.djangoproject.com/zh-hans/2.2/_modules/django/core/paginator/
12、table.objects.get()返回一个对象,而table.objects.filter()返回一个对象列表
13、get_object_or_404(klass, *args, **kwargs) 用特定查询条件获取某个对象,成功则返回该对象,否则引发一个 Http404
参数: · klass 接受一个 Model 类,Manager 或 QuerySet 实例,表示你要对该对象进行查询
· **kwargs 查询条件,格式需要被 get() 和 filter() 接受
Django 文档解释
为什么我们使用辅助函数 get_object_or_404() 而不是自己捕获 ObjectDoesNotExist 异常呢?还有,为什么模型 API 不直接抛出 ObjectDoesNotExist 而是抛出 Http404 呢?
因为这样做会增加模型层和视图层的耦合性。指导 Django 设计的最重要的思想之一就是要保证松散耦合。一些受控的耦合将会被包含在 django.shortcuts 模块中。
14、
templates 模板
1、使用模板动态的生成 HTML
2、简单了解两个方法:GET 和 POST
GET: 从指定的资源请求数据,一般用于查询数据;
POST: 向指定的资源提交要被处理的数据,一般用于更新数据,提交表单。
3、GET 方法将用户提交的数据添加到 URL 中,路径后面跟问号 “?”,用于区分路径和参数(问号后面是参数),多个参数之间用“&”隔开。
4、 index.html 中{% csrf_token %},是CSRF令牌(跨站请求伪造),通过该令牌判断POST请求是否来自同一个网站
5、 form 表单中的 action="/login_action" 指定了提交的路径,根据该路径去 urls.py 中匹配 URL 模式,再去 views.py 中执行相应的视图。
models.py
1、模型基础知识
· 每一个 model 都是 Python 类,都要继承 django.db.models.Model 类 · 模型的每个属性表示数据库的表字段 · Django 把这一些已经给了一个自动生成的访问数据库的 API · 创建模型时,后台会在数据库自动生成一个 id 作为主键,这个主键可以被覆盖
2、str()是被 print 函数调用的,str()返回的内容以字符串形式输出,该方法告诉 Python 如何将对象以 str 的方式显示出来。
3、类 Meta 的作用:
模型元数据是“任何不是字段的数据”,比如排序选项(ordering),数据库表名(db_table)或者人类可读的单复数名称(verbose_name 和verbose_name_plural)。在模型中添加class Meta是完全可选的,所有选项都不是必须的。
更多 Django 元数据选项
4、makemigrations 与 migrate 命令的作用
在 models.py 中设计好模型后,需要将模型中的各个属性(或改动)映射到数据库中,首先通过 makemigrations 命令操作\guest> python manage.py makemigrations sign
相当于在该 sign 应用中的 migrations 目录,记录了所有的关于 modes.py 的改动(比如添加字段,删除模型等),会自动生成 0001_initial.py 记录操作, 但是这个改动还没有作用到数据库文件\guest> python manage.py migrate
将对模型的改动作用到数据库文件,比如产生 table ,修改字段的类型等
注意:若更换数据库,数据库迁移前要保证在建模阶段,把相关字段都填写正确和规划完整,不然迁移过程会暴露许多问题。这里说的是数据库迁移,迁移执行的是同步表字段,在 MySQL 数据库中生成表,而数据是无法复制过去的,可能迁移后需要重新造数据,不然就提前导出数据,迁移完后再导入。
数据库
1、在 django 中配置 mysql,在 setting.py 修改 DATABASES 就好
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '127.0.0.1', 'PORT': '3306', 'NAME': 'test', 'USER': 'root', 'PASSWORD': '', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, } }
test.py
(该部分编写单元测试代码,对发布会、嘉宾管理、嘉宾搜索等进行测试)
Django shell
1、进入 Django shell 模式\guest> python manage.py shell
在 Ipython 模式下编辑
2、获得某个 table 中的所有对象
table.objects.all()
In [3]: Event.objects.all()
Out[3]: <QuerySet [<Event: 荣耀发布会>]>
In [4]: Guest.objects.all()
Out[4]: <QuerySet []>
2、插入数据的两种方式
In [7]: e1 = Event(id=2, name='红米发布会', limit=20, status=True, address='北京', start_time=datetime(2016,8,10,14,0,0))
...: e1.save()
Event.objects.create(id=1, name='荣耀发布会', limit=200, status=True, address='深圳会展中心', start_time=datetime(2018,9,22,14,0,0))
3、查询数据
table.objects.get()
In [14]: e1 = Event.objects.get(name='红米 MAX 发布会')
In [15]: e1
Out[15]: <Event: 红米 MAX 发布会>
In [16]: e1.address
Out[16]: '北京会展中心'
4、过滤数据
table.objects.filter() 相当于 SQL 语句中的 LIKE 语句
In [18]: e2 = Event.objects.filter (name__contains='发布会')
In [19]: e2
Out[19]: <QuerySet [<Event: 荣耀发布会>, <Event: 红米发布会>, <Event: 红米 MAX 发布会>]>
5、删除数据
table.objects.get().delete()
In [20]: Guest.objects.get(phone='13423454334').delete()
Out[20]: (1, {'sign.Guest': 1})
6、更新数据
In [21]: g3 = Guest.objects.get(phone='13012345690')
In [22]: g3.realname = 'andy2'
In [23]: g3.save()
In [24]: Guest.objects.select_for_update().filter(phone='13012345690').update(realname='andy')
Out[24]: 1
其它
1、创建 django_session 表,存放用户 sessionid 对应的信息
命令:\guest> python manage.py migrate 使用 “migrate” 进行数据迁移,Django 会同时生成 auth_user 表
2、Django 自带 Admin 管理后台,创建登录 Admin 后台的管理员账号
命令:\guest> python manage.py createusperuser
Admin 管理后台登录地址: http:127.0.0.1:8000/admin/
问题
1、当对手机号进行查询,若将手机号进行 encode ,则无法正常进行查询,且分页器按每页2条记录进行划分。
原因:查询手机号时,输入的数字,网页按照默认的编码格式将参数进行提交。后台获取该参数后,在进行一次 encode ,则无法与正确的手机号进行匹配,故
无法使用手机号成功查询,且分页器因为手机号无法正常匹配,也无法显示分页。
2、在 sign_index() 方法 和 sign_index_action() 方法中,传入的第二个参数无法更换为其它值,如 event_id ,否则报错,
sign_index() got an unexpected keyword argument 'eid 将 event_id 换为 eid 后,传参变得正常。
在谷歌看了挺多资料,也看了相关源码,仍未找到该问题原因。猜测, eid 在这里作为一个位置参数,且名字不可更改。