Django

BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

web应用的简介

Django框架是一个专门用来开发 web项目的框架。

web应用是?

web应用程序是一种可以通过web访问的应用程序,也就是说只需要一个浏览器即可,不需要其他软件。

应用程序有两种模式C/S、B/S

Django就是开发B/S应用程序的,所以我们就认为浏览器是我们客户端,Django框架就是服务端。

web应用程序的优点

1、只需要一个浏览器即可,不需要安装其他应用软件。

2、节省用户的空间

3、他们不需要更新,是因为服务端只要一更新版本,会直接影响客户端的更新。

4、跨平台使用

web应用程序的缺点

一旦web应用程序的服务端宕机,直接影响客户端的正常访问。

 

web框架

web应用程序主要是B/S架构的,浏览器就是客户端,开发一个服务端即可。

用socket写出一个服务端

关于之前的HTTP协议复习知识:

1、四大特性

  基于请求和响应

  基于TCP协议之上的应用层协议

  无状态

  短链接

2、请求数据格式

  请求首行

  请求头

  /r/n

  请求体

3、响应数据格式

  响应首行

  响应头

  /r/n

  响应体

4、响应状态码

1xx、2xx、3xx、4xx、5xx

 

1、用socket连接客户端

import socket

sever = socket.socket()
sever.bind(('127.0.0.1',8000))
sever.listen(5)

while True:
    conn,addr = sever.accept()
    data = conn.recv(1024)
    print(data.decode('utf-8'))

    conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
    conn.send(b'hihi')
    conn.close()

2、解决问题:在浏览器地址栏填什么后缀就返回什么

import socket

sever = socket.socket()
sever.bind(('127.0.0.1',8000))
sever.listen(5)

while True:
    conn,addr = sever.accept()
    data = conn.recv(1024)
    # print(data.decode('utf8'))
    res = data.decode('utf8')
    re = res.split(' ')
    print(re)
    conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
    if re[1] == '/login':
        conn.send(b'login')
    elif re[1] == '/index':
        conn.send(b'index')
    else:
        conn.send(b'404 erro')


    conn.close()

但是上述方法存在问题:

1、socket部分我们每次都要书写,代码重复

2、我们需要自己处理http格式数据,自己切分,自己取值

3、并发问题没有解决

 

3、借助wsgiref模块解决问题

from wsgiref.simple_server import make_server

from wsgiref.simple_server import make_server

def run(env,response):
#     env就相当于后续的request,当客户端发起请求时,所携带的数据都在这里
#       response:是给后端给浏览器返回数据
#         return:返回给浏览器查看
    print(env)  #这里是个大字典
    response('200 ok',[])
#     字典中的后缀名在PATH_INFO中
    current_path = env.get('PATH_INFO')
# 判断
    if current_path == '/index':
        return [b'index']
    elif current_path == '/login':
        return [b'login']
    else:
        return [b'404 error']



if __name__ == '__main__':
    sever = make_server(host='127.0.0.1',port=8000,app=run)
    #这句话是实时监听上面的地址,只要有客户访问这个地址,服务端就能接收到客户端的请求,就类似于我们socket前端
    # app=run:只要客户端发过去请求,那么就会把处理的请求交给run这个函数处理,run是个函数名(在django中用的就是函数名)
    # 在后续学的flask框架时,app的地方是对象,不是函数名,而对象加()调用的是类下的__call__方法
    # 启动服务端
    sever.serve_forever(0)

4、进一步封装

 视图:

 路由:

 

views.py----------------->视图文件--------->主要就是写后端的逻辑的
urls.py------------------>路由文件(后缀)---------->路由与视图函数的对应关系
templates---------------->专门用来存储html文件的
"""

# 以后我们要想增加一个后缀,只需要在urls.py中写一个路由和在views.py中写一个视图函数即可.

Django框架学习

python中的主流框架:

Django:
主要用来开发web项目的,它比较笨重,一般小型项目不怎么使用它,大而全
flask:
它是一个比较轻量级的框架,它主要依赖于第三方的模块,不断的安装第三方模块,小而精
tornado:
 异步非阻塞,解决高并发比较擅长
 这个框架学起来有点难度.

版本:

1.X(老项目) 2.X(新项目) 3.X(新版本)
1.x和2.x本质上差别不是很大,但是也有区别,我们讲1.x,附带讲2.x的区别

在drf中,都要使用2.x以上版本,drf这个框架要求django的版本必须是2.x以上

注意事项:

1. 你的项目名称和应用名称以及其他文件的名称都要使用英文的,坚决不能够使用中文的
2. 你的计算机名称最后都使用英文的
3. 一个pycharm窗口只打开一个django项目,不能够一个窗口打开很多个django项目

 

安装django

 1、在pycharm里安装

 2、在cmd中安装

先找到pip是否在环境变量里

 在cmd中输入

 pip install django==1.11

注意:django版本要和解释器版本匹配

验证cmd是否安装成功

在cmd中输入:django-admin------>如果有输出内容就说明安装成功

 

创建项目

  1、命令行创建

    将路径切换至想放入放入路径里

    django-admin startpeoject 项目名
    django-admin startproject myfirst_dj

  2、pycharm创建   

    File
      New Project
          django
              ...

启动项目

  1、命令行启动   

  先把路径切到manage.py所在的路径
  python3 manage.py runserver
  """项目启动起来之后,会监听:http://127.0.0.1:8000/"""
  默认端口号是:8000
  如何修改端口号:
  python3 manage.py runserver 127.0.0.1 8001

  2、pycharm启动

    点击绿色按钮

   访问项目: http://127.0.0.1:8000/

  当pycharm创建时会出现报错时,注意setting文件的这个地方,属于版本问题,将其改为, 即可。

1.0版本

2.0版本:

 

创建应用

1、命令行创建

python manage.py startapp [app_label].
python manage.py startapp app01.

2、在pycharm创建,pycharm创建是在建立文件时直接创建

 

注册应用

当应用创建出来需要注册,在配置文件中注册应用,这个应用才会生效

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config', # 全称
'app01', # 简称
]

 

主要文件介绍 

myfirst_dj     # 项目名称
app01      # 应用名称
migrations      这个是用来存储数据库迁移记录
__init__.py
admin.py     # 跟后台项目注册等相关的
apps.py      # 跟一些注册相关
models.py     # 跟数据库打交道的 模型层----->MTV模型
tests.py      # 测试文件
views.py     # 视图文件,写一些后端逻辑
myfirst_dj
__init__.py
settings.py      # 配置文件相关的
urls.py        # 路由相关的
wsgi.py        # 内部封装的wsgiref服务器,uwsgi服务器之后,这个文件就没用了uwsgi.py
db.sqlite3        # Django自带的小型数据库
manage.py        # Django框架的入口文件

 

应用

# django主要开发的就是一款web应用!
Django框架类似于是一所大学(空壳子)

应用就是大学里面的二级学院(具备独立的功能模块)
# 一个应用就是一个独立的功能模块
比如:
user
order
address
cart
...
# 应用名一定要见名知意,但是我们教学为了方便,我都使用app01、02、03...

小白必会三板斧

return HttpResponse("OK") # 返回字符串的

 

return render(request, 'index.html') # 返回html文件的

return redirect('http://www.baidu.com') # 重定向(可以跳转别人的,也可以跳转自己的,自己的不需要加ip和端口,例如直接 /home/)

 

自己创建的templates文件夹,要在配置文件注册
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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',
],
},
},
]

 

配置文件介绍(settings.py)

SECRET_KEY

DEBUG(自己调试用true,上线改为false)

 注册应用

INSTALLED_APPS
上面的文件都是django自带的一些应用,不需要的时候可以删除

根路由文件(ROOT_URLCONF)如果文件名修改,这里也要修改,不然找到不到

 模板文件(TEMPLATES)

 数据库(DATABASES)

 语言(改成下面的就是中文)

 时区

数据库使用的时间(改为false)

 

静态文件配置

以登录界面为例

1、先在views文件中定义视图函数login

 2、在urls文件中写下路由

 3、在templates中建立一个html文件login

 4、查看提交方式:

 注意:当出现以下页面时:

 5、就在配置文件中将这个地方注释了(这块是验证块,为了安全会报错)

 6、静态文件

静态模板文件一般放在templates文件夹中,如果没有这个文件就自己创建

我们一般把静态文件放在static文件夹中,但是为我们需要自己手工创建出这个文件夹中

静态文件:
网站使用的CSS文件
网站使用的js文件
网站使用图片
网站使用的第三方库文件
jQuery、bootstrap等

"""

# 我们还可以针对不同的功能对static文件夹里面的问价进行拆分
css
js
img

在setting配置中(动态解析文件):

 导入bootstrap和jQuery

 

 

request对象请求方法

request.method      请求方式 有 GET POST

 

print(request.POST .get()) 只获取列表最后一个元素 print(request.POST.getlist()) 直接将列表取出

request.POST 和request.get 一模一样

get有大小限制,post没有

 

pycharm连接数据库

1、找到对应位置

 2、第一次使用要进行下载

 

Django连接MySQL

默认配置文件中的数据库是

 需要连接自己的数据库

    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'dj',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'root',
        'CHARSET': 'utf8'
    }

 当报错时的解决办法:

1. 如果解释器版本导致的问题,直接改源码
def get_new_connection(self, conn_params):
conn = Database.connect(**conn_params)
conn.encoders[SafeText] = conn.encoders[six.text_type]
# 先判断bytes是否存在于编码器中,如果在才执行操作
if bytes in conn.encoders: # 加上这句话
conn.encoders[SafeBytes] = conn.encoders[bytes]
return conn

2. 解释器版本改为3.6的时候也会报错

 

Django的底层默认使用的是mysqldb模块,这个模块兼容性很差
我们还使用pymysql连接mysql,你要提前安装pymysql模块
Did you install mysqlclient or MySQL-python?

# 怎么解决这个问题:
在项目的任意的__init__.py中加入下面两行代码
*****************************************************************************
import pymysql
pymysql.install_as_MySQLdb() # 猴子补丁
# 这两行代码的意思就是把底层的mysqldb模块换成pymysql
*****************************************************************************

3. 除了使用mysqldb、pymysql之外还可以使用mysqlclient这个模块
# 你用了mysqlclient这个模块,就不用加上面那两句话了
# mysqlclient安装的时候可能会报各种错误

 

Django中的ORM

ORM是对象映射模型

以后在django中写数据库相关代码时,就不用再写原生的SQL语句,直接通过python代码来操作数据库的增删改查。

orm的书写位置:

在models.py中书写

表 >>>>> 类名

记录 >>>>> 对象

字段 >>>>> 属性

创建一张表:

所有类必须继承models.Model

创建表

 在以下图的位置进行数据库迁徙:

# 类写完之后,一定要做数据库迁移,真正的在数据库中生成表
********************************************************************************
python36 manage.py makemigrations # 它的作用是把数据库的迁移记录保存下来
python36 manage.py migrate # 才是真正的把数据表创建出来
********************************************************************************

 

ORM增删改查字段

class Author(models.Model):
    '''如果你创建的表中有主键字段,并且,主键字段的名字也叫id,那么,以后你就可以直接省略id字段'''
    name = models.CharField(max_length=64)
    # password1 = models.CharField(max_length=128, null=True)
    # password1 = models.CharField(max_length=64, default='12')

字段增加:

1、可以在终端内直接给出默认值

2、该字段可以为空

3、直接给字段设置默认值

字段修改:

直接修改代码,执行数据库迁移命令

字段删除:

将对应字段注释后,再执行数据迁移命令

执行完毕后对应字段的数据也就没有了

执行命令前要检查,数据会丢失

 

 

通过结合前端页面实现orm对数据增删改查数据

 以用户数据展示页面举例

1、增加数据需要现在models.py里创建表。

 2、在路由中加入访问的连接。

 3、在视图中加入数据信息,这一步不需要再进行数据迁移,只需要跑一下代码,进入该界面即可,记住跑这个见面数据库就会增加数据,记得仔细查看

4、在userinfo.html中添加表格样式(以下是将数据写死了)

 

 5、动静态网页

 静态网页:在页面上写死了的数据,不会改变

动态网页:

  是从后端获取到的数据,在页面中显示出来

  数据是从数据库中查询出来的

__str__:1、当打印或者输出对象时,会自动触发__str__执行。

    2、返回值必须是字符串类型

    3、内部返回什么结果,打印就是返回结果

 6、视图里进行逻辑书写:

 7、模板变量分配

以下的locals()就是完成的模板变量分配

 以下是在html中写的模板变量分配

 8、修改数据(修改数据要确定主键id,通过id来删除,并且要把修改数据展示到修改页面)

 首先要先加入修改数据的视图和路由,在html数据中进行页面跳转

 寻找id(注意问号要是英文状态下的)

 视图中修改数据。

 9、添加用户数据

现在路由和视图中加入相应的数据,再建立相应的html文件。

在html文件中写对应的前端代码。

 视图中写入对应的代码。

 要在用户数据显示列表加入相应页面跳转数据

 10、删除用户数据

删除数据也要加入相应的视图和路由,但是不用建立相对html的界面

删除也要根据id来寻找对应的值才可以。

 

数据迁移显示“No changes detected”

在数据迁移时可能会出现“No changes detected”这个问题,以下是解决办法

1、删除migrations中的所有文件,删除后重新运行。

 2、一种原因是因为你在项目工程Demo的settings.py对新生成的子应用没有进行注册,注册后重新迁徙运行。

可以正常运行,会生成对应的0001_initial.py迁移文件。

 3、如果settings.py已经注册了该应用,那么在命令行(pycharm中的terminal)输入:python36 manage.py makemigrations --empty 你的应用名

 数据文件生成成功,然后进行数据迁移即可。

 

No migrations to apply. django同步数据库失败

在migrate时可能会出现以下问题:

建完表之后,再对一张表进行了一次修改,运行python manage.py migrate,

总是No migrations to apply,数据库中表结构也没有生成

后来只是删掉了对应的App,再次迁移生成表,依然没有成功

 解决办法:

删除该App下的 migrations 文件夹

1.从命令行进入mysql数据库

2.use 对应的库

3.输入命令 :delete from django_migrations where app='your-app-name'; #your-app-name是对应的你的APP的名字

 4.最后就可以执行对应的迁移表操作了: python manage.py makemigrations    python manage.py migrate

谈谈机制

 migrations机制有两个指令,第一个是makemigrations,第二个是migrate,生成migrations代码的makemigrations指令是用models里面的model和当前的migrations代码里面的model做对比,如果有新的修改,就生成新的migrations代码。

 

Django创建表关系

在models.py中创建

表关系有:一对一、一对多、多对多。

建立表前先理判断表关系(换位思考法):

首先以图书表、出版社表、作者表、作者详情表为例创建。

分析表关系:

  图书表和出版社表是一对多的关系    (一对多创建表关系:外键建在关系多的一方,也就是以少的一方主键为外键)

  图书表和作者表是多对多的关系    (对多对创建表关系:外键建立在第三方表)【这里的多对多只写了一种方式】

  作者表和作者详情表是一对一的关系    (外键建立在查询频率较高的一方)

创建表关系字段先创建表的基础字段,先创建没有外键的,最后再写外键字段。

 进行数据库迁移,就可以建立表了

 

 django1版本
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。

models.CASCADE
删除关联数据,与之关联也删除

models.DO_NOTHING
删除关联数据,引发错误IntegrityError

models.PROTECT
删除关联数据,引发错误ProtectedError

models.SET_NULL
删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)

models.SET_DEFAULT
删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

models.SET
删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

 

django2版本不一样,需要使用的时候查一下

class Book(models.Model):
    title = models.CharField(max_length=64)
    """
    max_digits=None,        总共多少位
    decimal_places=None     小数占几位
    """
    # price decimal(8,2)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    # publish_id = models.ForeignKey(to='Publish', to_field='id') # 创建外键的
    """如果你的字段是主键字段,那么,你就不用在字段的后面拼接_id了,它会自定的拼接_id"""
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 创建外键的 默认就是跟表的主键字段建立关系
    """
        authors:它是一个虚拟字段,意思是,在book表中不会实际创建出来这个字段,它能够创建出来第三张表(自动)
    """
    authors = models.ManyToManyField(to='Author', )


class Publish(models.Model):
    title = models.CharField(max_length=64)
    addr = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=64)
    author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    phone = models.CharField(max_length=64)
    qq = models.CharField(max_length=64)

要在以下位置加上以下代码:

 

Django框架的请求生命周期流程图

 

 

 url函数的使用(支持正则表达式)

django1中使用的是url:

  url('test',views.test)

  url函数第一个参数是支持正则表达式的,如果匹配到一个路由就不再往下匹配,直接执行路由对应的函数

正因为是支持正则,在匹配到textadd也会展示text的页面,因为在检测到text的时候就进入页面了。

 当在后面加一个“/”时,在浏览器中输入text时,django内部做重定向,一次匹配不行,url会自动加“/”来再次进行匹配。

 

取消斜杠(默认是True,也就是加/)

 在配置中有一个APPEND_SLASH = False

以下方式是严格限制路由匹配,但是$有时候加,有时候不加:

 

 django2中使用的是path

path('test/', admin.site.urls)

path是不支持正则的,是精准匹配,输入的内容和路由地址是完全匹配。

re_path('^test/$', admin.site.urls)

此时的re_path是支持正则表达式的。

 

无名分则和有名分组

分组:给某一段正则表达式用小括号括起来

无名分组:就是将括号内正则表达式匹配的内容当作位置参数传递给后面的视图函数。

以下代码上面是路由,下面是视图。

url('^test/(\d+)', views.test)
def test(request, xx):
    print(xx) # 123
    return HttpResponse("test")
url('^test/(\d+)/(\d+)$', views.test),
def test(request, xx, yy):
    print(xx, yy) # 123
    return HttpResponse("test")

有名分组:可以给正则表达式起一个别名

就是将括号内正则表达式匹配的内容当作关键字参数传递给后面的视图函数。

url(r'^test/(?P<year>\d+)$', views.test),
def test(request, year):
    print(year) # 123
    return HttpResponse("test")

 有名函数和无名函数是否可以一起使用

不要一起使用

但是有名无名单独可以使用多次

 无名函数使用多次,位置参数,args:

上面是视图,下面是路由

url(r'^test/(\d+)/(\d+)/(\d+)/(\d+)/', views.test),

def test(request,*args,**kwargs):
    print(args) 
    return HttpResponse("test")

 

 有名函数多次使用,关键字参数,kwargs:

url(r'^test/(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)/$', views.test),

def test(request,*args,**kwargs):
    print(kwargs)
    return HttpResponse("test")

 反向解析

反向解析:可以给路由起名,然后通过一个方法可以解析出这个名字对应的路由地址

先给路由和视图起一个别名:

url(r'^func_hhh/',views.func,name='123')
def func(request):
    return render(request,'func.html')

反向解析的两种方式:

后端反向解析(要在views中导入reverse)

print(reverse('123'))

前端反向解析

<a href="{% url '123' %}">123</a>

 

 无名分组反向解析

写代码时应该在这里放的数字一般是数据的主键值

路由和视图写别名

前端解析

<a href="{% url 'test' 111 %}">点我</a>

后端解析

print(reverse('test', args=(123, )))

 

有名分组的反向解析

前端解析:

中规中矩的写法:

<a href="{% url 'testadd' year=2023%}">点我</a>


print(reverse('testadd',kwargs={'year':2023, 'month':12}))

简便写法是和无名分组一样的书写方式。

 

django2中的path函数支持的5种转换器

path('test/', admin.site.urls)
Django默认支持以下5个转化器:

● str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
● int,匹配正整数,包含0。
● slug,匹配字母、数字以及横杠、下划线组成的字符串。
● uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
● path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)

urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<int:year>/', views.year_archive),  
    path('articles/<int:year>/<int:month>/', views.month_archive),  
    path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),  
  # path才支持,re_path不支持
  path('order/<int:year>',views.order),
]

 

路由分发

django的每一个应用都可以有自己的template文件夹urls.py

但是当路由多的时候,这个文件就会产生很多的路由地址,产生的问题就是理由比较臃肿,不太容易管理,也不容易排查错误。

我们针对每一个应用也可以有自己的路由文件,每一个应用下的路由我们称之为子路由。

因为每一个应用下没有urls.py这个文件,我们需要自己手动创建一个文件出来。

这个时候产生很多路由文件,匹配的时候先匹配总路由,然后由总路由分发到每个子路由这个时候总路由的作用就是分发了,总路就不再执行具体的视图函数,而是交给子路由。

创建一个新的应用:

注意:总路由的url千万不能加$符号

总路由方法一:

 总路由:记住要导入模块,并且要重新命名

 总路由方法2: 

 方法2:

子路由:

 

名称空间(别名冲突问题)

当多个应用出现了相同的别名,我们研究反向解析会不会自动识别应用前缀

正常情况下的反向解析是没有办法识别前缀的

总路由:

urlpatterns = [
   url(r'^app01/',include('app01.urls',namespace='app01')),
   url(r'^app02/',include('app02.urls',namespace='app02')),
]

子路由:

解析时:

print(reverse('app01:ref'))
print(reverse('app02:ref'))
{% url 'app01:ref' %}
{% url 'app02:ref' %}

只要保证名字不冲突,就没必要使用名称空间

一般情况下 有多个app时我们就在起别名时加上应用前缀。

这样确保多个app不冲突

 

伪静态概念

静态文件.html

http://127.0.0.1:8000/app01/index
https://www.cnblogs.com/fanshaoO/p/17592993.html # 其实就是伪静态之后的地址

 

伪静态的原因就是为了让搜索引擎增大seo的查询力度,言外之意就是让我们的页面能够更容易被搜索引擎搜索出来。

搜索引擎就是一个巨大的爬虫。

静态页面更加容易被搜索引擎抓到,称之为seo

seo就是优化产品使其更容易被找到

SEO---------------------->一般是通过技术手段等实现
SEM---------------------->它是需要收费的,其实就是广告

 

虚拟环境

一般我们开发项目是一个单独的项目,使用一个单独的解释器环境

举例:

开发一个CRM系统:3.6
开发一个OA系统:3.7
开发一个商城系统:3.6

 

不是每个项目都使用一个解释器,每个项目单独使用一个解释器版本,这个解释器只安装这个项目使用到的模块

每开发一个项目就下载一个解释器,可以解决问题,但是没必要,可以通过蓄奴环境来解决这个问题,虚拟环境其实就是一个纯净版本的解释器,你不用每次都下载和安装

# 它就是一个文件夹形式存在的解释器

# 虚拟环境尽量不要创建,创建出来够你的项目使用就行了

# 虚拟环境还可以通过命令创建

 

 视图层

三板斧问题

在视图中写函数和普通函数不太一样

djagno中使用局部的request

所有视图函数不能够没有返回值,并且返回值还必须是HttpResponse对象

 如果没有返回值就会报错:

 三板斧查看源码就可以发现,他们返回的都是HttpResponse对象

在flask中request使用的是全局变量request

JsonResponse序列化

序列化:实现跨语言传输

序列:字符串

序列化:把其他数据类型转为字符串的过程

反序列化:把字符串转为其他数据类型的过程

json格式的数据:主要是跨语言数据传输

现在实现跨语言数据的传输使用的都是json,在以前使用的是xml,

微信支付朝微信后端发送参数,使用的是xml

之前学的序列化是:

  import json

  json.dumps

  json.loads

在js中是:

JSON.stringify()
JSON.parse()    # 对象

方法1:(原始方法序列化)

 序列化(明显特征是单引号变双引号了):

import json
def ab_json(request):
    user_dict = {'username':'123','password':'123'}
    json_str = json.dumps(user_dict)
    return HttpResponse(json_str)

 当序列化加上中文时,编码也需要改变

未修改编码前:

编码改变之后:

 

 方法二:djongo提供的方式(改源码)

也可以实现

 

 字典可以序列化,列表也可以序列化:

这样写的话会报错,看报错信息进行修改

 加了safe修改后:

 

form表单上传文件

form表单上传文件类型数据:

  1、method必须指定成post

  2、enctype必须换成formdata

当出现这个界面就是未注释配置文件

 

前端写法:

 后端写法:

 

request对象的其他几个方法

request.GET
request.POST
request.FILES
request.methods

request.path_info     # /ab_request/
reqeust.path        # /ab_request/
request.get_full_path()   # /ab_request/ /ab_request/?username=kevin&age=11

上面两个只能拿到路由,没办法拿到路由的参数,下面的既能拿到路由,也能拿到参数。

 

C(class)BV的书写和F(function)BV的写法

 目前写的都是FBV:function based view 基于函数的视图

在视图文件中书写类 CBV:class based view 基于类的视图

postman的官网地址:https://www.postman.com/downloads/
apizza的挂网地址:http://www.apizza.net/

好处在于可以很方便的判断是post还是get,并跳转到相应位置

cbv:

视图写法:

 路由写法:

 

FBV和CBV各有千秋

  CBV 的特点是能够根据请求方式的不同直接匹配到对应的方法执行

 

CBV源码分析

 查看源码时,提醒自己面向对象的查找顺序

  先从对象找、再从产生对象的类里找、再去父类里找

 CBV的入口:

 

(类实例化后是对象,函数产生的是方法,与前端对象无关) 

类名可以调用哪些方法:

  1、方法被@classmethod装饰器修饰的方法:

      类名来调用类方法有什么好处:会把第一个类名自动当成第一个参数传递给方法的第一个形参cls

      对象调用方法把对象自己当成第一个参数传给方法的第一个形参

   2、被@staticmethod装饰器修饰的方法

 

 当请求来的时候,开始匹配路由login,就会调用View.view()

 
def dispatch(self, request, *args, **kwargs):

 

模板层

模板变量之分配

模板中取值一定使用的是句点符。

模板中的函数一定不能够加括号,他们会自动加括号调用。

模板语法调用不能加()

函数有参无法用{{}}

模板语法索引{{f,0}}

python语法可以传递后端基本所有的数据类型

 

 

 

 模板之过滤器

 

Django自带的过滤器有好几十、但是我们没必要全部记住,只需要记住几个就行了
语法:
{{ obj|过滤器名称:参数 }} 变量名字|过滤器名称:变量

案例:
default
length

{{ res|default:'你很好啊' }}   如果有值就显示前面的,没值就是后面默认值
{{ res|length }}        算长度
{{ res
|filesizeformat }}    计算文件大小和1024对比 {{ res|date:'Y-m-d' }}      日期格式化
{{l|slice:'2:4:2'}}        
切片操作(支持步长)
{{ res|truncatechars:9}}     切取字符包含点,九位
{{ info|truncatewords:9 }} #切取单词,不包含三个点

 前端

|safe

后端

from django.utils.safestring import mark_safe
# res = mark_safe('<h1>HELLO WORLD</h1>') # 直接就是安全的,
return render(request, 'ab_filter.html', context=locals())
 

模板语法之标签

for循环

使用forloop时:

前端:

 后端:

 取具体值时:

前端:

 就是将forloop改成foo

后端:

 

字典遍历:

前端:

后端:

 if判断

if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

前端:

 后端:

 

 with起别名

在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式

前端:

 后端:

 模板继承

网页的页面整体都大差不差,只是某一些局部再做变化

模板的继承就是自己先选好一个想继承的模板页面

 {% extends 'home.html' %} # {% extends '继承的html页面' %

 继承之后就是跟模板页面一模一样的,需要再页面上提前规划可以被修改的区域

{% block content %}(content是可以任意取名的)
模版内容
{% endblock %}

子页面就可以声明想要修改哪块划定了的区域
{% block content %}
子页面内容
{% endblock %}

 一般情况下模板页面至少要有三块可以被修改的区域

1.css区域
{% block css %}

{% endblock %}
 
2.html区域
{% block content %}

{% endblock %}

3.js区域 
{% block js %}

{% endblock %}

每个页码就可以有自己的独有的css代码、html代码、js代码

一般情况下,模板的页面上规划的区域越多,那么该模板的延展性就越高

 模板导入

将页面的某一个局部当成模块的形式

哪个地方需要就可以直接导入

{% include 'wasai.html' %}  # 在html页面上导入模块

 

 模型层(ORM)单表和多表操作

单表操作

当你只是想测试django中的某一个py文件内容 那么你可以不用书写前后端交互的形式
而是直接写一个测试脚本即可
脚本代码无论是写在应用下的tests.py还是自己单独开设py文件都可以

测试环境准备:去manage.py中拷贝前四行代码,然后写两行

########Django1.x版本
import os
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings")
    import django
    django.setup()
########Django2.x版本    
import os
def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day64.settings')
    import django
    django.setup()
    ...
if __name__ == '__main__':
    main()

在test.py里测试数据的增删改查

在这里测试数据库需要导入models

增加数据

第一种:

 第二种方法:

 删除数据

pk === primary key
pk会自动查找到当前表的主键字段 指代的就是当前表的主键字段
用了pk之后 你就不需要指代当前表的主键字段到底叫什么了
第一种方法:

 第二种方法:

修改数据

第一种方法:

 第二种方法(数据不存在会报错):

 

get方法返回的直接就是当前数据对象
但是该方法不推荐使用
一旦数据不存在该方法会直接报错
而filter则不会
所以我们还是用filter

查找数据

第一种(结果是列表套字典):

 第二种(结果是列表套元组):

 

 必知必会13条

# 还是在test.py文件
1. all() 查询所有数据
2. filter() 带有过滤条件的查询
3. get() 直接拿数据对象 但是条件不存在直接报错
4. first() 拿queryset里面第一个元素
# res = models.User.objects.all().first() # 可以不写all()
# print(res)
5. last() 拿queryset里面最后一个元素
# res = models.User.objects.all().last()
# print(res)
6. values() 可以指定获取的数据字段 select name,age from ... 列表套字典

# res = models.User.objects.values('name','age')
# <QuerySet [{'name': 'jason', 'age': 18}, {'name': 'egonPPP', 'age': 84}]>

 7.values_list()  列表套元祖

res = models.User.objects.values_list('name','age')
# <QuerySet [('jason', 18), ('egonPPP', 84)]>
# print(res)

查看内部封装的sql语句
上述查看sql语句的方式 只能用于queryset对象
只有queryset对象才能够点击query查看内部的sql语句

8.distinct()  去重

res = models.User.objects.values('name','age').distinct()
# print(res)
"""
去重一定要是一模一样的数据
如果带有主键那么肯定不一样 你在往后的查询中一定不要忽略主键
"""

9. order_by()  排序
# res = models.User.objects.order_by('age') # 默认升序
# res = models.User.objects.order_by('-age') # 降序
# print(res)

 10.reverse() 反转的前提是 数据已经排过序了 order_by()

# res = models.User.objects.all()
# res1 = models.User.objects.order_by('age').reverse()
# print(res,res1)

11. count() 统计当前数据的个数
# res = models.User.objects.count()
# print(res)

12. exclude() 排除在外
# res = models.User.objects.exclude(name='jason')
# print(res)

13.exists() 基本用不到因为数据本身就自带布尔值 返回的是布尔值
# res = models.User.objects.filter(pk=10).exists()
# print(res)

 查看内部sql语句的方式

方式1:queryset对象才能够点击query查看内部的sql语句

 方式2 :改配置文件(所有的sql语句都能查看)

去配置文件中配置一下即可 把下面的代码复制到settings.py中

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

 

 双下划线查询

 # 年龄大于35岁的数据
    res = models.User.objects.filter(age__gt=35)
    print(res)
    
    # 年龄小于35岁的数据
    res = models.User.objects.filter(age__lt=35)
    # print(res)
    
    # 大于等于 小于等于
    res = models.User.objects.filter(age__gte=32)
    print(res)
    res = models.User.objects.filter(age__lte=32)
    print(res)

    # 年龄是18 或者 32 或者40
    res = models.User.objects.filter(age__in=[18,32,40])
    print(res)

    # 年龄在18到40岁之间的  首尾都要
    res = models.User.objects.filter(age__range=[18,40])
    print(res)

    # 查询出名字里面含有s的数据  模糊查询
    res = models.User.objects.filter(name__contains='s')
    print(res)
    
    # 是否区分大小写  查询出名字里面含有p的数据  区分大小写
    res = models.User.objects.filter(name__contains='p')
    print(res)
    
    # 忽略大小写 ignore
    res = models.User.objects.filter(name__icontains='p')
    print(res)
    
    # 以什么开头 以什么结尾
    res = models.User.objects.filter(name__startswith='j')
    res1 = models.User.objects.filter(name__endswith='j')
    print(res,res1)

    # 查询出注册时间 按年 按月
    res = models.User.objects.filter(register_time__month='1')
    print(res)
    res = models.User.objects.filter(register_time__year='2020')
    print(res)

 

一对多的增删改查

增加:

第一种方法:

 第二种方法:

修改:

第一种:

models.Book.objects.filter(pk=9).update(publish_id=5)

第二种:

publish_obj = models.Publish.objects.filter(pk=4).first()
models.Book.objects.filter(pk=5).update(publish=publish_obj)

 

多对多的增删改查

多对多外键的增删改查  就是在操作第三张表

 增加add:

第一种方法:

 第二种方法  虚拟字段:

"""
add给第三张关系表添加数据
括号内既可以传数字也可以传对象 并且都支持多个
"""

 删除:

方法一:

 方法二(虚拟字段):

 修改:

第一种(括号里必须给一个可迭代对象):

 第二种(虚拟字段):

set
括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个

 清空

第三张表中清空某个书籍和作者的绑定关系

"""
clear
括号内不要加任何参数
"""

 

多表查询

子查询和连表查询

子查询:一个SQL语句的执行结果当成另一个SQL语句的执行条件,分步操作

连表查询:把多个表关联在一起拼接成一个大的虚拟表,然后按照单表查询

inner join
left join
right join
union

 举例:

select * from course inner join teacher on course.id=teacher_course_id where id=1;

select * from course as c inner join teacher as t on course.id=teacher_course_id left join class on class.id=c.class_id where c.id=1

正反向概念

先判断是正向还是反向查询

正向:外键字段在我手上,我查你就是正向查询

反向:外键字段在我手上,你查我就是反向查询

正向查询按照字段查询(外键字段)

反向查询按照表名小写或者表名小写__set

 一对一和多对多正反向的判断也是如此

子查询(基于对象的跨表查询)

在书写orm语句的时候跟写sql语句一样的
不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点
正向什么时候需要加.all()
当你的结果可能有多个的时候就需要加.all(),如果是一个则直接拿到数据对象

例题为例:

正向查询

 反向查询

"反向"
"""
基于对象
反向查询的时候
当你的查询结果可以有多个的时候 就必须加_set.all()
当你的结果只有一个的时候 不需要加_set.all()
自己总结出 自己方便记忆的即可 每个人都可以不一样
"""

 联表查询(基于双下划线的跨表查询)

举例说明:

聚合查询(aggregate)

sum max min avg count

聚合查询 不分组使用需要用 aggregate
"""
聚合查询通常情况下都是配合分组一起使用的
只要是跟数据库相关的模块
基本上都在django.db.models里面
如果上述没有那么应该在django.db里面
"""
# 先导入模块
from django.db.models import Max,Min,Sum,Count,Avg

例题:

分组查询annotate

# 分组查询:group by
# 分组之后只能取到分组的依据,按照什么字段分组就只能取到这个字段的值,前提是严格模式

# 非严格模式就可以取到所有字段的值
# 如何设置严格模式
1. 使用命令修改
查看sql_mode
show variables like '%mode%';
@@select sql_mode;

# 设置严格模式
set global sql_mode='ONLY_FULL_GROUP_BY'
2. 使用配置文件

例题:

 

F与Q查询

F查询

"""
能够帮助你直接获取到表中某个字段对应的数据
"""
# 先导入模块
from django.db.models import F

# F查询
"""
能够帮助你直接获取到表中某个字段对应的数据
"""

例题:

 在操作字符类型的数据的时候 F不能够直接做到字符串的拼接

 导入模块:

from django.db.models import F
from django.db.models.functions import Concat
from django.db.models import Value

Q查询

# 借助模块
from django.db.models import Q

 

res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600)) 
    # Q包裹逗号分割 还是and关系

 |   or关系

 ~  not关系

 

Q的高阶用法

能够将查询条件的左边也变成字符串的形式 q = Q()
# q.connector = 'or' # 默认是and 可以改成or
q.children.append(('maichu__gt',100))
q.children.append(('price__lt',600))
res = models.Book.objects.filter(q) # 默认还是and关系
print(res)

django中如何开启事务

(具体实物使用在数据库了解及部分掌握

"""
事务
  ACID
原子性:
  不可分割的最小单位
一致性:
  跟原子性是相辅相成
隔离性:
  事务之间互相不干扰
持久性:
  事务一旦确认永久生效
事务的回滚:
  rollback
事务的确认:
  commit
"""
# 目前你只需要掌握Django中如何简单的开启事务

# 事务
# 导入模块

from django.db import transaction
try:
with transaction.atomic():
# sql1
# sql2

# 在with代码快内书写的所有orm操作都是属于同一个事务
except Exception as e:
print(e)
print('执行其他操作')

 

 

ORM中模型层中其他的常用字段和参数

1、ORM字段

AutoField int

IntegerField

CharField

DateField
 日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例


DateTimeField
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例

TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]

BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
BooleanField(Field)
- 布尔值类型
TextField(Field) text
- 文本类型: 可以存储大文本,写一篇文章 text

EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm、Forms组件、中提供验证机制

# 如果你需要存储邮箱格式的数据,就是字符串格式存储CharField

FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)


FloatField(Field)
- 浮点型

DecimalField(Field)

max_digits,小数总长度
decimal_places,小数位长度

 2、ORM字段参数

#### null

用于表示某个字段可以为空。

#### **unique**

如果设置为unique=True 则该字段在此表中必须是唯一的 。

#### **db_index**

如果db_index=True 则代表着为此字段设置索引。

#### **default**

为该字段设置默认值。

### DateField和DateTimeField

#### auto_now_add

配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。

#### auto_now

配置上auto_now=True,每次更新数据记录的时候会更新该字段。

 

choices参数的使用(数据库字段设计常见)

choices是ORM中常营字段中的参数

例如在用户表中:性别、学历、工作经验、是否结婚、客户来源

针对某个可以列举完全的字段可能性

只要某个字段可以列举完全的可能性字段,一般情况下会选择choices参数

 存取的字段在上述元组列举范围之内就可以轻松获取到数字对应的真正内容

如果字段存的数字或者字母不在上述元组列举的范围,不会报错,存取的值是什么就输出什么。(例如上述性别,如果存入了4,则输出是也只会是4)

如果在,获取对应的中文信息:

      “固定写法:get_字段名_display()”

 #
    # user_obj = models.User.objects.filter(pk=1).first()
    # print(user_obj.gender)
    # 只要是choices参数的字段 如果你想要获取对应信息 固定写法 get_字段名_display()
    # print(user_obj.get_gender_display())

 

MTV与MVC模型

把Django框架的执行流程做分层:
    在Django中分的是MTV
    在其他语言中分的是MVC

这两个本质都是一样的:

    Web服务器开发领域著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层

    Web服务器开发领域里著名的MTV模式,所谓MTV就是把Web应用分为模型(M),控制器(V)和视图(T)三层

MTV:

M:models 模型:负责业务对象和数据库关系的映射(ORM)

T:templates 模板:负责如何把页面展示给用户(Html)

V:views 视图:负责业务逻辑,并在适当时候调用Model和Template

MVC:

M:models 模型   (对应MTV的M)

V:views 视图  (对应MTV的T)

C:controller 控制  (对应MTV的V)

 

还有一个S 代表视图(Services):只有在业务逻辑相当复杂时,才会分这一层,服务层,专门用来写业务逻辑的。

 

多对多三种创建方式

1、全自动

利用orm自动帮我们创建第三张关系表

优点:不需要写代码,非常方便,还支持orm提供操作第三张关系表的方法

不足之处:第三张关系表的扩展性极差(没有办法额外添加字段

2、纯手动

纯手动建立第三张表

优点:第三张表完全取决于自己进行额外扩展

不足之处:需要写的代码较多,不能够再使用orm提供的简单方法 (add,set,remove,clear)

3、半自动

可以使用orm的正反向查询,但是没法使用orm提供的简单方法(add,set,remove,clear这四个方法)

 through_fields字段先后顺序:

  判断本质:通过第三张表查询对应的表 需要哪个字段,就把哪个字段放前面

  简化判断:当表是谁,就把对应的关键字放前面

 

 

 

 

 

 

 

 

 

posted @ 2023-07-26 17:25  别管鱼油我了  阅读(241)  评论(0编辑  收藏  举报