diango基础知识总结

下载

  1. 命令行

    pip install django==1.11.26 -i https://pypi.tuna.tsinghua.edu.cn/simple

  2. pycharm

创建项目

  1. 命令行

    django-admin startproject 项目名

  2. pycharm

    file _> new project _> django _> 输入路径 _> 选择解释器 _> create

启动项目

  1. 命令行

    python manage.py runserver # 127.0.0.1:8000

    python manage.py runserver 80 # 127.0.0.1:80

    python manage.py runserver 0.0.0.0:80 # 0.0.0.0:80

  2. pycharm

    点绿三角 django 前面是dj

    可以修改配置 可以改IP和端口

使用顺序

settings 静态文件配置

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  #文件夹根目录

DEBUG = True   #因为启动出错调试模式 上线后改为Flase,出错不报错,给用户更好的用户体验

ALLOWED_HOSTS = ['*'] #让所有的用户可以访问

INSTALLED_APPS = [       #app注册
	'app01', 
    'app01.apps.App01Config'   # 推荐写法
]

MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',   #提交POST请求注释一个中间件
]




"""
如果使用sqlite3数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', 
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
"""

"""
#如果使用mysql数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',   #diango的服务器引擎
        'NAME': 'bookmanager',
        'USER': 'root',
        'PASSWORD': '123',
        'HOST': '127.0.0.1',
        'PORT': 3306,
    }
}

#默认使用pymysql模块 替换
import pymysql
pymysql.install_as_MySQLdb()
"""




LANGUAGE_CODE = 'en-us'       #汉语 'zh-hans'  

TIME_ZONE = 'UTC'   #时区:英国的,改为亚洲上海 'Asia/Shanghai'  

STATIC_URL = '/static/'    #静态文件夹的别名,配置静态文件要以/static/为开头


STATICFILES_DIRS = [                  # 路由
    os.path.join(BASE_DIR,'static1'),   # 存放静态文件的路径
    os.path.join(BASE_DIR,'static1'),
]
				 # join(BASE_DIR必须是这个,静态文件夹static1)
					# 加上静态文件的存放路径

models.py 映射关系

写映射关系操作数据库

settings 配置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', #使用mysql数据库引擎
        'NAME': 'day43',		#默认操作的库
        'HOST': '127.0.0.1',	#库所在的服务器地址		
        'PORT': 3306,			#端口
        'USER': 'root',			#用户名
        'PASSWORD': '123',		#密登密码
    }
}


#默认使用pymysql模块 替换  也可以写在day43的__init__.py里
import pymysql
pymysql.install_as_MySQLdb()

创库

用可视化工具创建一个MySQL数据库

创表

class User(models.Model):
    username = models.CharField(max_length=32)  # varchar(32)
    password = models.CharField(max_length=32)  # varchar(32)
    
#类 对象   属性
#表 数据行 字段


python manage.py  makemigrations  # 制作迁移文件 出现在migrations
python manage.py migrate  # 执行SQL语句 同步 
		#terminal里执行命令

△id字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定 primary_key=True 即可。如果Django发现你已经明确地设置了Field.primary_key,它将不会添加自动ID列。

urls.py 路由

路径 函数转换

==settings配置:

STATICFILES_DIRS = [                  # 路由
    os.path.join(BASE_DIR,'static1'),   # 存放静态文件的路径
    os.path.join(BASE_DIR,'static2'),
]

url(r^'用户输入输入的路径 0.0.0.0:80/index/',不加括号的函数名)

urlpatterns = [ 	
    url(r'^admin/', admin.site.urls),
    url(r'^index/', index),   # 路径和函数的对应关系,
    url(r'^modal/', modal),  
]

views.py 函数

def index(request):  		    # 函数里写处理逻辑,request拿到网络路径,固定写法
    print(request.path_info)	# 打印网络路

import 导入:

导入返回字符串的包HttpResponse,返回html文件的包render,返回执行另一个逻辑的包

from django.shortcuts import HttpResponse,render, redirect 

导入dpp01文件中的创建数据表的类的models.py文件

from app01 import models

return 返回:

return HttpResponse('

index

')

返回字符串

return HttpResponse('<h1>index</h1>')         # 返回字符串

return render(,,)

返回接受到请求的网络路径要渲染的html文件和要传的值

return render(request, 'index.html',{'k1':v1}) 
#返回   (网络路径必添,要渲染的html文件,{别名:要传的值})

return redirecct('路径')

执行另一个逻辑

ORM的操作

写函数来实现增删该查

.all 获取所有的数据

all_publishers = models.Publisher.objects.all() 
#变量 = 文件名.类名.对象.取值方法
# objects.all() 查询出所有的出版社的信息,是一个对象列表

.filter(pk=pk) 获取所一个数据

第一个pk列名,第二个pk为从request中get到的

变量 = models.User.objects.filter(password='dsb')   # 对象列表	
# 用.first取第一个,若无,返回空列表,if 变量;判断时,不会报错,只是不会执行这个语句了
# 用[0]取值时,,若无,取不到值,if 判断时变量,会报错

get 获取所一个数据

变量 = models.User.objects.get(password='dsb')  # 对象 特点 获取不到或者获取到多个都报错

create(name=pub_name) 添加数据

利用类的对象

obj = models.Publisher.objects.create(name=pub_name)

update(name=pub_name) 跟新数据

templates HTML文件

模板

某.html的settings配置

MIDDLEWARE = [
  
    # 'django.middleware.csrf.CsrfViewMiddleware',   #提交POST请求注释一个中间件
  
]

hyml中的样式路径配置

<head>  
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.min.css">
    
    <script src="/static/js/jquery.js"></script>
    <script src="/static/plugins/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</head>

模板语法

△登录

<div class="container">

    <form class="form-signin" method="post" action="" novalidate>
        <h2 class="form-signin-heading">Please sign in</h2>
        <label for="inputEmail" class="sr-only">用户名</label>
        <input type="text" id="inputEmail" class="form-control" name="username" placeholder="输入用户名" required=""
               autofocus="">
        <label for="inputPassword" class="sr-only">密码</label>
        <input type="password" id="inputPassword" class="form-control" name="password" placeholder="输入密码" required="">
        <div>{{ error }}</div>
        <div class="checkbox">
            <label>
                <input type="checkbox" value="remember-me"> Remember me
            </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block">登录</button>

    </form>

△查询所有的作者信息

    all_authors = models.Author.objects.all()
    for author in all_authors:
        print(author)
        print(author.name)
        print(author.books,type(author.books))  # 关系管理对象
        print(author.books.all(),type(author.books.all()))  # 所关联的所有的对象

△for循环

views.py传过来的参数:
render(request,'pub.html',{'all_publishers':all_publishers}) 
{{ all_publishers }} 

html的for循环:
{% for i in all_publishers  %}

	{{ forloop.counter }}
	{{ i }}
	{{ i.id }}  {{ i.pk }}
	{{ i.name }}
	
{% endfor %}


△if

{% if 条件 %}
	xxx
{% else %}	
	xxxxx
{% endif %}

△form的注意点

  1. form标签的属性 action='提交的地址' method='post' novalidate 取消input标签自带的校验
  2. input标签必须要有name属性 有些标签有value值
  3. 需要有一个button按钮 或者 type='submit'的input

△get 和 post

get : 获取一个页面

1.直接在浏览器的地址栏中输入地址 回车

2.form表单 不指定method

3.a标签

参数: ?k1=v1&k2=v2

获取参数: request.GET.get('k1')

post : 提交数据

form表单  method = 'post'

获取数据: request.POST.get('k1')

static1 渲染

一个项目的结构

day43项目

.idea 配置

pycharm自动帮配的配置,打开别人的diango项目时要先删了此项

app01

方便在一个大的Django项目中,管理实现不同的业务功能

migrations 放表

放和数据库同步的表

admin.py 后台

后台管理:

1、应用注册

2、admin界面汉化

apps.py 元数据

应用程序设置

元数据

models.py

写映射关系操作数据库

它包含了你存储的数据的重要字段和行为

  • 每个模型都是一个Python类,它是django.db.models.Model的子类。
  • 模型的每个属性都代表一个数据库字段。
#类 对象   属性
#表 数据行 字段
class User(models.Model):
    username = models.CharField(max_length=32) #varchar
    password = models.CharField(max_length=32) #varchar

image-20191212191131843

tests.py 测试

views.py

写函数逻辑

day43项目包

init.py 自动执行

#默认使用pymysql模块 替换  也可以写在settings.py里
import pymysql
pymysql.install_as_MySQLdb()

settings

静态文件配置

urls.py

路径 函数转换

wsgi.py 网关接口

WSGI(Python Web Server Gateway Intergace)

中文名:python服务器网关接口,python应用于web服务器之间的接口,很少用到,但是最好不要修改其内容

static1

templates

manage.py 命令行接口

应用的命令行接口

将Django project放到sys.path目录中,同时设置DJANGO_SETTINGS_MODULE环境变量为当前project的setting.py文件。

diango运行流程

Django处理一个请求的流程:

  1. 在浏览器的地址栏中输入地址,回车,发了一个GET请求
  2. wsgi模块接收了请求,将请求的相关信息封装成request对象
  3. 根据地址找到对应函数
  4. 执行函数获取到返回结果,wsgi模块将结果返回给浏览器

发请求的途径:

  1. 在浏览器的地址栏中输入地址 get请求
  2. a标签 get请求
  3. form表单 get/post

reqeust

​ reqeust.GET url上携带的参数 ?k1=v1&k2=v2

​ reqeust.POST form表单提交POST请求的参数

​ request.method 请求方式 GET、POST

response

​ HttpResponse('字符串') ——》 返回字符串

​ render(request,'模板的名字',{}) ——》 返回一个页面

​ redirect('地址') ——》 重定向

创建一个app

terminal里执行命令

python manage.py startapp app名称

注册

settings配置
INSTALLED_APPS = [
	'app01', 
    'app01.apps.App01Config'   # 推荐写法
]

Django使用MySQL数据库的流程

手动创建一个MySQL数据库

配置数据库

ENGINE   MySQL
NAME	数据库的名字
HOST    ip 
PORT    3306
USER    用户名
PASSWORD  密码

在与settings同级目录下的__init__.py中写代码:

import pymysql
pymysql.install_as_MySQLdb()

写models:

form django.db import models 
class Publisher(models.Model):
	name = models.CharField(max_length=32)

执行迁移的命令

python  manage.py  makemigrations  # 检查已经注册的APP下面的models.py的变更情况
python manage.py migrate   # 执行迁移 

ORM 对象关系映射

对应关系:

​ 类 _> 表

​ 对象 _> 数据行(记录)

​ 属性 _> 字段

ORM能做的事情:对数据做修改、对表做修改

常用的字段

AutoField  自增字段
IntegerField  整数
CharField 字符串
DatetimeField  DateField 日期时间
	auto_now:每次修改时修改为当前日期时间。
	auto_now_add:新创建对象时自动添加当前日期时间。
BooleanField  布尔值
TextField   大文本
ImageField  图片
DecimalField   10进制小数

字段参数

null=True   # 数据库中该字段可以为空
blank=True  # 用户输入可以为空
db_column   # 数据库字段的名
default     # 默认值
primary_key  # 主键
db_index    # True 索引
unique      # 唯一约束
verbose_name   # 中文提示
choices        # 让用户选择的数据

建表的参数

    class Meta:
        # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
        db_table = "person"

        # # admin中显示的表名称
        verbose_name = '个人信息'

        # verbose_name加s
        verbose_name_plural = '所有用户信息'

        # 联合索引
        # index_together = [
        #     ("name", "age"),  # 应为两个存在的字段
        # ]
        #
        # # 联合唯一索引
        unique_together = (("name", "age"),)  # 应为两个存在的字段

ORM的操作

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=32)
    
# 一对多的关系
class Book(models.Model):
    name = models.CharField(max_length=32)
    pub = models.ForeignKey(to='Publisher',on_delete=None) 
    
    def __str__(self):
        return self.name

查询

from app01 import models 

models.Publisher.objects.all()  #查询所有的数据  QuerySet  对象列表 
models.Publisher.objects.get(name='xxx') 
					#查询一条数据  只能查有且唯一的数据
models.Publisher.objects.filter(name='xxx') 
					#查询所有满足条件的数据 对象列表 
    
for book in all_books:
    print(book)
    print(book.id)
    print(book.pk)
    print(book.name)
    print(book.pub)  # 所关联的出版社对象    	对象.外键
    print(book.pub_id)  # 所关联的出版社对象的id   对象.外键_id

新增

obj = models.Publisher.objects.create(name='xxxx')

models.Book.objects.create(name=book_name,
                           pub=models.Publisher.objects.get(pk=pub_id))
obj = models.Book.objects.create(name=book_name, pub_id=pub_id)

obj = models.Publisher(name='xxxx')
obj.save()  # 保存到数据库

obj = models.Book(name='xxx',pub_id=出版社的对象id)
obj.save()


多对多的新增:
书对作者
book_id = request.POST.getlist('book_id')
# 插入数据
obj = models.Author.objects.create(name=author_name)
obj.books.set(book_id) # 设置多对多的关系

删除

models.Publisher.objects.filter(pk=pk).delete()   # 批量删除
models.Publisher.objects.get(pk=pk).delete()	# 单条数据的删除

更新

models.Book.objects.filter(pk=pk).update(name=book_name,pub_id=pub_id)  # 批量更新

obj = models.Book.objects.filter(pk=1).first()
obj.name = 'xxxx'
obj.pub_id = 2
# book_obj.pub  =  出版社的对象
obj.save()  #保存更新

外键

一对多的关系

class Book(models.Model):
    name = models.CharField(max_length=32)
    pub = models.ForeignKey('Publisher', on_delete=models.CASCADE)
  
 
    """
    on_delete 在2.0版本之后是必填的
    on_delete= 
        models.CASCADE  级联删除
        PROTECT   保护
        SET(1)    
        SET_DEFAULT  设置为默认值设置为某一个值
        SET_NULL   设置为空
        DO_NOTHING 什么都不变
    """
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

# 基于对象的查询
# 正向查询
book_obj = models.Book.objects.get(pk=3)
# print(book_obj)
# print(book_obj.pub)

# 反向查询
# 没有指定related_name  表名小写_set
pub_obj = models.Publisher.objects.get(pk=2)
# print(pub_obj.book_set,type(pub_obj.book_set))  # 关系管理对象
print(pub_obj.book_set.all())

# related_name='books'
# print(pub_obj.books.all())


# 基于字段的查询
ret = models.Book.objects.filter(pub__name='老男孩出版社')
# print(ret)

# 没有指定related_name  类名小写__字段
ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# 指定related_name  related_name__字段
ret = models.Publisher.objects.filter(books__name='没有页码的python书')

# 指定related_query_name='book'  related_query_name_name__字段
# ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# print(ret)

多对多

class Pulisher(models.Model):
	name = models.CharField(max_length=32)

class Book(models.Model):
	name = models.CharField(max_length=32)
    pub = models.ForeignKey('Pulisher',on_delete=models.DO_NOTHING)

class Author(models.Model):
	name = models.CharField(max_length=32)
	books= models.ManyToManyField(to='Book') 
# 查询
book_obj.pub   # 所关联的对象   book_obj.pub_id  所关联的对象的id

author_obj.books  # 关系管理对象
author_obj.books.all()   # 所关联的所有的书籍对象
# 新增
Book.objects.create(name='xxx',pub=对象)
Book.objects.create(name='xxx',pub_id=对象的ID)

obj= Book(name='xxx',pub_id=对象的ID)
obj.save()

obj = Author.objects.create(name='xxx')
obj.books.set([书籍id,书籍id])
# 删除
Book.objects.filter(pk=pk).delete()  # QuerySet 删除
Author.objects.get(pk=pk).delete()   # 对象 删除
# 编辑
Book.objects.filter(pk=pk).update(name='xxx')

book_obj.name ='xxxx'
book_obj.save()

Author.objects.filter(pk=pk).update(name='xxx')
author_obj.books.set([id,id])
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

author_obj = models.Author.objects.get(pk=1)

# print(author_obj.books.all())

book_obj = models.Book.objects.get(pk=1)
# print(book_obj.author_set.all())

ret = models.Author.objects.filter(books__name='没有页码的python书')
ret = models.Book.objects.filter(author__name='bigbao')

# print(ret)
# set 设置多对多的关系  [id]   [对象]
# author_obj.books.set([3,])
# author_obj.books.set( models.Book.objects.all()) # [对象,对象]

# add 添加多对多的关系  id   对象
# author_obj.books.add(1,2,3)
# author_obj.books.add(*models.Book.objects.all())  # *[对象,对象]

# remove 删除多对多的关系  id   对象
# author_obj.books.remove(1,2)
# author_obj.books.remove(*models.Book.objects.filter(pk__in=[1,2])) # [对象,对象]


# clear 清除多对多的关系
# author_obj.books.clear()

# create 新增一个所关联的对象 并且和当前的对象设置关系
author_obj.books.create(name='跟和尚学合气道', pub_id=1)

# book_obj.author_set

# 多对一  反向查询 一 ——》 多  关系管理对象
# 关系管理对象.set([对象,对象])
# 关系管理对象.add(对象,对象)

#  外键字段 null=True, 才有remove,clear
# 关系管理对象.remove(对象,对象)
# 关系管理对象.clear()

# 关系管理对象.create()

必知必会13条

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

# all()  查询所有的数据  QuerySet 对象列表
ret = models.Person.objects.all()

# filter  获取满足条件的所有的对象  QuerySet 对象列表
ret = models.Person.objects.filter(name='alex')

# exclude  获取不满足条件的所有的对象  QuerySet 对象列表
ret = models.Person.objects.exclude(name='alex')

# values()
#  不指定字段 获取所有字段名和值  QuerySet 对象列表  [ {},{} ]
#  指定字段  values('pid','name')  获取指定字段名和值  QuerySet 对象列表  [ {},{} ]
ret = models.Person.objects.all().values()
ret = models.Person.objects.filter(name='alex').values('pid', 'name')

# values_list()
#  不指定字段 获取所有的值  QuerySet 对象列表  [ (),() ]
#  指定字段  values_list('pid','name')  获取指定的值  QuerySet 对象列表  [ (),() ]
ret = models.Person.objects.all().values_list()
ret = models.Person.objects.filter(name='alex').values_list('name', 'pid', )

# order_by  排序 默认升序  -降序  可以多个字段排序
ret = models.Person.objects.all().order_by('age', '-pid')

# reverse  对已经排序的QuerySet做的反转
ret = models.Person.objects.all().order_by('pid').reverse()

# get    获取满足条件的一个的对象  对象
ret = models.Person.objects.get(name='alex')

# first  获取第一个元素   对象  获取不到的时候是none
ret = models.Person.objects.filter(name='xxx').first()

# last  获取最后一个元素   对象  获取不到的时候是none
ret = models.Person.objects.filter(name='xxx').last()

#  count 计数
ret = models.Person.objects.all().filter(age=84).count()

# exists 数据是否存在
ret = models.Person.objects.filter(age=84).exists()

# distinct  去重  数据时完全一样才去重
ret = models.Person.objects.filter(age=84).values('age').distinct()



"""
返回对象列表
all
filter 
exclude 
order_by 
reverse
values   [{}] 
values_list   [()] 
distinct  

返回对象
get
first  
last 

返回数字
count

返回布尔值
exists

"""

单表的双下划线

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

ret = models.Person.objects.filter(pk__gt=3)  # greater than   where pk > 3
ret = models.Person.objects.filter(pk__gte=3)  # greater than equal   where pk >= 3

ret = models.Person.objects.filter(pk__lt=3)  # less than   where pk < 3
ret = models.Person.objects.filter(pk__lte=3)  # less than equal   where pk <= 3

ret = models.Person.objects.filter(pk__range=[1,3])  # 1 <= pk <= 3
ret = models.Person.objects.filter(pk__in=[1,3,7,10,100])  # 成员判断

ret = models.Person.objects.filter(name__contains='bigbao')  # like   不忽略大小写
ret = models.Person.objects.filter(name__icontains='bigbao')  # like  ignore  忽略大小写

ret = models.Person.objects.filter(name__startswith='b')  # 以什么开头 不忽略大小写
ret = models.Person.objects.filter(name__istartswith='b')  # 以什么开头 忽略大小写

ret = models.Person.objects.filter(name__endswith='o')  # 以什么结尾 不忽略大小写
ret = models.Person.objects.filter(name__iendswith='o')  # 以什么结尾 忽略大小写

ret = models.Person.objects.filter(age__isnull=False)   # 字段是否为空


ret = models.Person.objects.filter(birth__year='2019')   # 按照年份
ret = models.Person.objects.filter(birth__contains='2019-12-19')  # 时间包含


print(ret)

外间的操作

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

# 基于对象的查询
# 正向查询
book_obj = models.Book.objects.get(pk=3)
# print(book_obj)
# print(book_obj.pub)

# 反向查询
# 没有指定related_name  表名小写_set
pub_obj = models.Publisher.objects.get(pk=2)
# print(pub_obj.book_set,type(pub_obj.book_set))  # 关系管理对象
print(pub_obj.book_set.all())

# related_name='books'
# print(pub_obj.books.all())


# 基于字段的查询
ret = models.Book.objects.filter(pub__name='老男孩出版社')
# print(ret)

# 没有指定related_name  类名小写__字段
ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# 指定related_name  related_name__字段
ret = models.Publisher.objects.filter(books__name='没有页码的python书')

# 指定related_query_name='book'  related_query_name_name__字段
# ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# print(ret)


聚会和分组

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

from django.db.models import Max, Min, Avg, Sum, Count

ret = models.Book.objects.filter(id__gt=3).aggregate(max=Max('price'), min=Min('price'))

# 统计每一本书的作者个数
ret = models.Book.objects.annotate(Count('author'))  # 按照book进行分组  统计作者的个数

# 统计出每个出版社的最便宜的书的价格
ret = models.Publisher.objects.annotate(Min('book__price')).values()

ret = models.Book.objects.values('pub', 'pub__name').annotate(Min('price'))

# 统计作者的图书的个数

ret = models.Author.objects.annotate(Count('books')).values()

ret = models.Book.objects.values('author').annotate(Count('id'))

# 统计不止一个作者的图书
ret = models.Book.objects.annotate(count=Count('author')).filter(count__gt=1)

# 根据一本图书作者数量的多少对查询集 QuerySet进行排序
ret = models.Book.objects.annotate(count=Count('author')).order_by('-count')

# 查询各个作者出的书的总价格
ret = models.Author.objects.annotate(Sum('books__price')).values()

ret = models.Book.objects.values('author').annotate(Sum('price'))

print(ret)

F

可以拿字段出来对比

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models
from django.db.models import F, Q


# ret = models.Book.objects.filter(sale__gt=F('kucun'))
# ret = models.Book.objects.update(sale=F('sale')*2)


print(ret)

Q

| 或

& 与
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models
from django.db.models import F, Q

ret = models.Book.objects.exclude(pk__lte=3, pk__gte=2)
ret = models.Book.objects.filter(Q(~Q(Q(pk__gt=3) & Q(pk__lt=2))) & Q(name__contains='跟'))

print(ret)

事务

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django

django.setup()  # 初始化

from app01 import models

from django.db import transaction

try:
    with transaction.atomic():
        # 一系列的ORM操作
        models.Publisher.objects.create(name='xxx')
        models.Publisher.objects.create(name='xxx')
except Exception as e:
    print(e)

print('xxx')

cookie

定义

​ 保存在浏览器本地上一组组键值对

特点

1.cookie是由服务器进行设置的
2.浏览器保存在本地的
3.下次访问时自动携带对应的cookie

设置

response.set_cookie(key,value)   # Set-Cookie: is_login=1; Path=/
response.set_signed_cookie('is_login','1',salt='xxxx')
#两种操作方式相同,第二种推荐,salt='xxxx',以xxxx来进行加盐
response.set_signed_cookie(key,value,salt='xxxx',max_age=5,path='/')
	#max_age=5,让浏览器记住登录状态的时间最大为五秒,超过五秒清楚is_login

获取

request.COOKIES #  {} 
request.COOKIES[key]# 没有会报错
request.COOKIES.get(key)
request.get_signed_cookie(key,salt='xxxx',default='')
#default='' 默认值设置为空,不然取不到会报错

删除

response.delete_cookie(key)  # 设置键值对的值为空 超时时间为0

装饰器

让装了装饰器的函数的名字不是inner,而是原来的名字

from functools import wraps

def wrapper(func):
    @wraps(func)  # 复制了原来函数的名字和注释
	def inner(request,*arg,**kwargs):
        # 之前
        ret = func(request,*arg,**kwargs)
        # 之后
        return ret 
    return inner

@wrapper  # f1 = wrapper(f1)
def f1(request):
    pass

f1.__name__  #  inner _> f1   #让装了装饰器的函数的名字不是inner,而是原来的名字

response

diango中有三种response

from django.shortcuts import render, redirect, HttpResponse
HttpResponse()
render()
redirect()

session

定义

保存在服务器上的一组组键值对,必须依赖cookie

为什么要有session?

  1. cookie保存在浏览器上,不太安全
  2. cookie的大小和个数有限制

设置

request.session[key] = value 
request.session[is.login]=1

获取

request.session[key] #这样取值没有取值会报错
request.session.get(key)

删除

request.session.pop('is_login')
request.session.delete()  #  删除所有的session数据
request.session.flush()   #  删除所有的session数据和cookie

其他

request.session.clear_expired()		#清除过期的session  ?
request.session.set_expiry(value)   #设置session过期的时间

配置

from django.conf import global_settings
#在global_settings中查看全局配置
#在settings中覆盖修改

SESSION_COOKIE_NAME = 'session'   # cookie的名字
SESSION_SAVE_EVERY_REQUEST = True  # 每次请求都更新session
SESSION_EXPIRE_AT_BROWSER_CLOSE = True  # 浏览器关闭session就失效

SESSION_ENGINE = 'django.contrib.sessions.backends.db'
from django.contrib.sessions.backends import db #session在哪储存
# 数据库  缓存  缓存+数据库  文件 加密cookie

正则表达式

^ 开头

$ 结尾

[0-9] 数字

[a-zA-Z] 英文字母

[asd]{4,6}

+(一个或多个)
*(0个或多个)

? (0个或1个)

\d 阿拉伯数字

\w 匹配字母或数字或下划线或汉字 等价于'[^A-Za-z0-9_]

.(除了换行符之外的任意字符)

url的命名和反向解析

静态路由

url(r'^login/', views.login,name='login'),

反向解析ht

模板

{% url 'login' %}   ——》  '/app01/login/'

py文件

from django.urls import reverse
reverse('login')   ——》  '/app01/login/'

分组路由

位置传参

url(r'^del_publisher/(\d+)/', views.del_publisher,name='del_pub'),
#分组后从url中捕获参数,捕获的参数会按照 位置传参 传递给函数

关键字传参

url(r'^del_publisher/(?P<pk>\d+)/', views.del_publisher),
#分组后从url中捕获参数,捕获的参数会按照 关键字传参 传递给函数

反向解析

模板

{% url 'del_pub' '1' %}   ——》  '/app01/del_publisher/1/'

py文件

from django.urls import reverse
reverse('del_pub',args=('1',))   ——》  '/app01/del_publisher/1/'

命令分组 路由

url(r'^del_publisher/(?P<pk>\d+)/', views.del_publisher,name='del_pub'),

反向解析

模板

{% url 'del_pub' '1' %}   ——》  '/app01/del_publisher/1/'     位置传参
{% url 'del_pub' pk='1' %}   ——》  '/app01/del_publisher/1/'  关键字传参

py文件

from django.urls import reverse
reverse('del_pub',args=('1',))   ——》  '/app01/del_publisher/1/'    位置传参
reverse('del_pub',kwargs={'pk':'1'})   ——》  '/app01/del_publisher/1/'  关键字传参

namespace

多人合作开发解决路径重复问题

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/',include('app01.urls',namespace='app01' )),   
    url(r'^app02/',include('app02.urls',namespace='app02')),    
]
{% url 'app01:del_pub' '1' %}
reverse('app01:del_pub',args=('1',)) 

MVC

M: model 模型 与数据库交互

V: view 视图 HTML

C:controller 控制器 流程 和 业务逻辑

MTV

M:model ORM

T:template 模板 HTML

V:view 视图 业务逻辑

Django中的视图

FBV

def add_publisher(request,*args,**kwargs):
	# 逻辑
	return  response

urls.py

  url(r'^add_publisher',add_publisher )

CBV

from django.views import View
class Addpublisher(View):
	def get(self,reuqest,*args,**kwargs)
        # 处理GET请求的逻辑
        self.request
        return  response
    
    def post(self,reuqest,*args,**kwargs)
        # 处理POST请求的逻辑
        return  response

urls.py

  url(r'^add_publisher',Addpublisher.as_view() )

CBV中不同的请求能找到相应函数执行的原因:
继承了View,程序加载的时候,执行View中的Addpublisher.as_view(),
Addpublisher.as_view()定义了一个view函数,返回view,通过反射获取请求方式对应的方法(get/post)。

as_view的流程:

1. 程序加载的时候,执行Addpublisher.as_view():

   定义了一个view函数,返回view

   url(r'^add_publisher',view )

2. 请求到来时,执行view函数:

   1. 实例化对象  ——》 self
   2. self.request = request
   3. 执行self.dispatch(request, *args, **kwargs)
      1. 判断请求方式是否被允许:
         1. 允许: 通过反射获取请求方式对应的方法(get/post)  ——》 handler
         2. 不允许:self.http_method_not_allowed  ——》 handler
      2. 执行handler,将它的结果返回

加装饰器

FBV

FBV 直接加

@login_required
def publisher(request):

CBV

解决装饰器加同时加在类和函数上时的参数导致的复用性问题:
不加method_decorator,加在类方法上,需要第一个参数需要是self,如果在login_required的inner括号里加上了self,函数便无法用这个装饰器了,所以装饰器加在类上时要借助method_decorator

from django.utils.decorators import method_decorator

登录验证的装饰器
def login_required(func):
    def inner(request, *args, **kwargs):
        # print(request.COOKIES)
        # is_login = request.COOKIES.get('is_login')
        # is_login = request.get_signed_cookie('is_login', salt='xxxx', default='')
        is_login = request.session.get('is_login')
        # print(request.path_info)
        # print(request.get_full_path())
        print(request.META.get('HTTP_ACCEPT'))

        print(is_login)
        if is_login != 1:
            # 没有登录 跳转到登录页面
            url = request.path_info
            return redirect('/login/?url={}'.format(url))
        ret = func(request, *args, **kwargs)

        return ret

        # if is_login == '1':
        #     # 登录
        #     ret = func(request, *args, **kwargs)
        #     return ret
        # else:
        #     url = request.path_info
        #     return redirect('/login/?url={}'.format(url))

    return inner



# 加在方法上
@method_decorator(login_required)
def get(self, request, *args, **kwargs):

# 重写dispatch方法,加在dispatch方法上
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
    ret = super().dispatch(request, *args, **kwargs)
    return ret

#直接找到父类的dispatch方法加上去 ——最简单!推荐!
@method_decorator(login_required,name='dispatch')
class Addpublisher(View)

# 加在类上
@method_decorator(login_required,name='post')
@method_decorator(login_required,name='get')
class Addpublisher(View)

request对象的方法

request.method  # 请求方法 GET POST 
request.GET     # url上携带的参数  {}  
request.POST   # form提交POST请求的参数  {}   编码类型是urlencode 
request.body   # 请求体  b''
request.path_info  # 路径  不包含ip和端口  也不包含参数
request.COOKIES  # cookie的字典 
request.session  # session的数据
request.FILES  # 上传的文件  编码的类型是  enctype="multipart/form-data"
request.META     # 请求头   小写 ——》 大写  HTTP_    - _> _

request.get_full_path()   # 路径  不包含ip和端口  包含参数
request.get_signed_cookie(key)  # 获取加密cookie
request.is_ajax()   # 是否是ajax

response对象的方法

HttpResponse('xxxx')  # 返回字符串   Content-Type: text/html; charset=utf-8
render(request,'模板的路径',{})   # 返回一个页面
redirect('路径')   # 重定向  状态码301 302  响应头 Location:路径

from django.http.response import JsonResponse

模板中

变量 {{ 变量名 }}

通过(.)取相应的内容

.key > .属性 .方法 > .索引

过滤器

{{ 变量|过滤器 }} {{ 变量|过滤器:参数 }}

{{ kong | default:'没有传参' }}

filter

{{ 变量|filter:参数 }}

default add length slice join first last lower upper title truncatechars truncatewords

date:"Y-m-d H:i:s" safe

USE_L10N = False
DATETIME_FORMAT = 'Y-m-d H:i:s'

标签

{% %}

for

{%  for i in list %}

	{{ i }}

{% endfor %}

forloop.counter 循环的序号 从1开始

forloop.counter0 循环的序号 从0开始

forloop.revcounter 循环的序号 到1结束

forloop.revcounter0 循环的序号 到0结束

forloop.first 是否是第一次循环

forloop.last 是否是最后一次循环

forloop.parentloop 当前循环的外层循环 {}

{% for i in list  %}
	{{ forloop }}
	{{ i }}
	
{% empty %}
	空空如也
{% endfor %}

if 不支持算数运算

{% if  条件  %}
	x
{% elif  条件1  %}
	xx
{% else %}
	xxx
{% endif %}

注意点:

  1. 不支持算数运算
  2. 不支持连续判断 10 > 5 > 1 false

csrf

{% csrf_token %}  #  form表单中有一个隐藏的input标签  name=‘csrfmiddlewaretoken’

母版和继承

母版:

​ 模板,提取出多个页面公共部分放在一个母版中,定义上多个block块,让子页面重新复写。

继承:

  1. {% extends ‘母版的名字’ %}
    2. 重写block块。

注意点:

1. {% extends ‘母版的名字’  %}  母版名字 的引号好带上   不带会当做变量
  1. {% extends ‘母版的名字’ %} 上不要写内容

    1. 要替换母版的内容都写在block块中

    2. 定义多个block块, css,js

组件:

把一小段的HTML代码段 ——》 nav.html

{% include 'nav.html ' %}

静态文件的使用:

{% load static %}
"{% static '静态文件的相对路径' %}"

母版和组件的继承和引用怎么用?

使用admin的步骤

  1. 创建超级用户

    python manage.py createsuperuser

  2. 注册model

    在app下的admin.py中注册

    from django.contrib import admin
    from app01 import models
    # Register your models here.
    admin.site.register(models.Person)
    
  3. 访问网站登录操作

中间件

process_request(self,request)

参数:

​ request 请求的对象,和视图中的request是同一个

执行时间:视图函数之前

执行顺序:

​ 按照注册的顺序 顺序执行

返回值

​ None : 正常流程

​ HttpReponse: 当前中间件之后的中间件的process_request方法、路由匹配、视图也不执行,直接执行当前中间件的process_response方法

process_response(self, request, response)

参数:

​ request 请求的对象,和视图中的request是同一个

​ response 返回的响应对象

执行时间:视图函数之后

执行顺序:

​ 按照注册的顺序 倒叙执行

返回值

​ HttpReponse: 必须返回响应对象

process_view(self, request, view_func, view_args, view_kwargs)

参数:

​ request 请求的对象,和视图中的request是同一个

​ view_func 视图函数

​ view_args 视图函数的位置参数

​ view_kwargs 视图函数的关键字参数

执行时间:路由匹配之后,视图函数之前

执行顺序:

​ 按照注册的顺序 顺序执行

返回值

​ None 正常流程

​ HttpReponse: 当前中间件之后的process_view、视图不执行,执行最后一个中间的process_response

process_exception(self, request, exception)

参数:

​ request 请求的对象,和视图中的request是同一个

​ exception 错误对象

执行时间(触发条件):视图层面有错误才执行

执行顺序:

​ 按照注册的顺序 倒叙执行

返回值

​ None 当前中间没有处理异常,交由下一个中间件处理异常,所有的中间件都没有处理,Django处理错误

​ HttpReponse: 当前中间处理好异常,之后执行最后一个中间件的process_response方法

pocess_template_response(self,request,response)

参数:

​ request 请求的对象,和视图中的request是同一个

​ response 返回的响应对象

执行时间:视图必须返回一个template_response对象

执行顺序:

​ 按照注册的顺序 倒叙执行

返回值

​ HttpReponse: 必须返回响应对象

response.template_name = 'index1.html'  # 改模板
response.context_data # 改变量

Django的请求的生命周期

\1. 简介目录
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/p/9029086.html

\2. 路由系统
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9282718.html

\3. 视图
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9285269.html

\4. 模板
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9333821.html

5.ORM
字段和参数:![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9323320.html
查询操作:![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9403501.html
练习题:![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9414626.html

\6. cookie和session
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9502602.html

7.中间件
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9333824.html

\8. ajax
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9524153.html

\9. form组件
![img](file:///C:\Users\acer\AppData\Roaming\Tencent\QQ\Temp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9537309.html

AJAX

js技术,发送请求的一种方式.

特点:

  1. 异步
  2. 传输的数据量小
  3. 局部刷新

发请求的途径:

  1. form表单发请求 指定method GET/POST
    1. action 地址 method enctype
    2. input select option 标签要有name属性,有的还需要有value
    3. 有button按钮或者type='submit'的input框
  2. 直接在地址栏中输入地址 回车 get
  3. a标签 get
  4. ajax

发ajax请求的写法:

jQuery:

$.ajax({
    url: '/test/',   //  url路径
    type: 'post',    // 请求方式
    data: {          // 请求数据
        name: 'alex',
        age: 84,
        hobby: JSON.stringify(['吐口水', 'TESA', '篮球', '毒鸡汤']),
    },
    success: function (res) {   // 响应成功的回调函数
        console.log(res);
        console.log(res.status);
        console.log(typeof(res))
    },
    error:function (res) {		// 响应失败的回调函数
        console.log(res)

    }
})

上传文件

$('#b1').click(function () {

        var form_obj = new FormData();  // enctype="multipart/form-data"
        form_obj.append('name', 'alex')
        form_obj.append('f1', $('#f1')[0].files[0])

        $.ajax({
            url: '/upload/',
            type: 'post',
            data: form_obj,
            processData: false, // 不需要处理编码方式
            contentType: false, // 不需要处理contentType请求头
            success:function (res) {  //  响应成功的回调函数  res _> 返回的响应体
                alert(res)
            }

        })
    })

CSRF中间件

  1. process_request方法:

    从cookie中获取csrftoken的值,放到request.META中

  2. process_view方法:

    1. 判断视图是否使用csrf_exempt装饰器,使用了就不校验
    2. 判断请求方式是否是'GET', 'HEAD', 'OPTIONS', 'TRACE',如果是,也不校验
    3. 进行校验:
      1. csrf_token = request.META.get('CSRF_COOKIE') # cookie中获取csrftoken的值
    4. 请求方式是POST
      1. request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
      2. 获取不到,从头中获取x-csrftoken的值 = >request_csrf_token
      3. 进行比较csrf_token request_csrf_token的值:
        1. 对比成功 接收请求
        2. 对比不成功 拒绝请求

ajax通过Django的csrf校验

前提:

有csrftoken的cookie:

  1. from django.views.decorators.csrf ensure_csrf_cookie
    

方式一:

给data中添加csrfmiddlewaretoken的键值对

方式二:

给headers添加x-csrftoken的键值对

headers: { 
'x-csrftoken': $('[name="csrfmiddlewaretoken"]').val()},

方式三:

导入文件

csrf相关的装饰器

from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie

csrf_exempt   豁免csrf的校验   CBV需要加在dispatch方法上才生效
csrf_protect  强制校验
ensure_csrf_cookie  添加csrftoken的cookie

form组件

定义:

from django import forms

class RegForm(forms.Form):
    user = forms.CharField(label='用户名')
    pwd = forms.CharField(label='密码',widget=forms.PasswordInput)

使用:

视图函数:

def reg2(request):
    form_obj = RegForm()
    if request.method == 'POST':
        form_obj = RegForm(request.POST)
        if form_obj.is_valid():
            # 校验成功
            # form_obj.cleaned_data # 清洗后的数据
            return HttpResponse('注册成功')


    return render(request, 'reg2.html', {'form_obj': form_obj})

模板:

{{ form_obj.as_p }}   _>       生成所有字段的input框

{{ form_obj.user }}         _> 某个字段的input框
{{ form_obj.user.label }}   _> 某个字段的中文提示
{{ form_obj.user.id_for_label }}   _> 某个字段的input框的ID


{{ form_obj.errors }}   _>  所有的错误
{{ form_obj.user.errors }}  _>  某个字段的所有错误
{{ form_obj.user.errors.0 }}  _>  某个字段的第一个错误

常用的字段

CharField  
ChoiceField
MultipleChoiceField  

字段的参数

initial  初始值
required  是否必填
disabled  是否禁用
label 	  中文提示
initial   默认值
min_length  最小长度
error_messages   错误信息
choices   可选择的数据

校验

  1. 自带的校验

  2. 自定义校验规则

    1. 写函数

      from django.core.exceptions import ValidationError
      
      
      def check_name(value):
          # 自定义校验规则
          # 如果校验合格 什么都不做
          # 校验不合格   抛出异常
          if 'alex' in value:
              raise ValidationError('不能包含alex,非法字符')
              
      
  3. 使用内置的校验器

    from django.core.validators import RegexValidator
    
    validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式不正确')]
    

局部钩子和全局钩子

def clean_user(self):
    # 局部钩子
    # 校验成功  返回当前字段的值
    # 校验不成功  抛出异常
    if 'alex' in self.cleaned_data.get('user'):
        raise ValidationError('不能包含alex,非法字符')
    return self.cleaned_data.get('user')

def clean(self):
    # 全局钩子
    # 校验成功  返回所有字段的值 self.cleaned_data
    # 校验不成功  抛出异常
    pwd = self.cleaned_data.get('pwd')
    re_pwd = self.cleaned_data.get('re_pwd')
    if pwd == re_pwd:
        return self.cleaned_data
    else:
        self.add_error('re_pwd','两次密码不一致!!!')
        raise ValidationError('两次密码不一致')

posted @ 2019-12-11 22:17  谢国宏  阅读(622)  评论(0编辑  收藏  举报