首页 > 其他分享 >Django

Django

时间:2023-02-19 21:33:40浏览次数:55  
标签:__ obj name models res django Django

wsgiref

wsgiref模块是内置模块,将请求的数据进行封装,组成键值对格式
from wsgiref.simple_server import make_server


def run(env, response):
    '''

    :param env: 请求相关的所有数据,封装成键值对字典形式
    :param response: 响应相关的所有数据
    :return: 返回给浏览器的数据
    '''
    info = env.get('PATH_INFO')
    print(env)
    response('200 OK',[])
    return [info.encode()]


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    server.serve_forever()

模板语法-jinja2模块

# pip3 install jinja2
from jinja2 import Template

'''模板语法
{{user}}
{{user.get('age')}}
{{user['age']}}
{{user.age}}
'''
def index():
    user_dic = {
        'age': 18,
        'name': 'hyf'
    }
    with open(r'./templates/index.html','r',encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    res = tmp.render(user=user_dic)
    return res

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    {% for user_dict in user_list %} 
        <li>
            <div>ID: {{user_dict.id}}</div>
            <div>姓名:{{user_dict.name}}</div>
            <div>年龄:{{user_dict.age}}</div>
            <div>住址:{{user_dict.addr}}</div>
        </li>
    {% endfor%}

</ul>
你好{{user}}
</body>
</html>

Python三大主流web框架

"""
Django
	特点:大而全 自带的功能非常非常多
	不足:有时候过于笨重

flask
	特点: 小而精,自带的功能特别少,第三方的模块非常多
	不足:依赖于第三方

tornado
	特点:异步非阻塞 支持高并发,甚至可以开发游戏服务器
	不足:暂时不会(没有不足)
	
A:socket部分
B:路由与视图函数对应关系
C:模板语法

Django
	A使用别人的 wsgiref
	B自己写的
	C自己写的(没有jinja2好用,但也很方便)
	
flask
	A使用 别人的 werkzeug(内部是wsgiref)
	B自己写的
	C用别人的(jinja2)
	
tornado
	A使用自己的
	B使用自己的
	C使用自己的


"""

Django安装

Django的安装
pip3 install django==1.11.111
如果已经安装了其他版本,无需卸载直接重新安装

验证是否安装成功
终端输入django-admin查看

Django基本操作

命令行

1. 创建django项目
先切换到对应磁盘下,在此磁盘下创建
django-admin startproject 项目名
2. 启动
切换到项目目录下
python3 manage.py runserver [ip port]

3. 创建应用
python3 manage.py startapp 应用名(应该做到见名知意)


pycharm

1. 创建项目
新建项目-->选择Django

2. 运行项目
点击运行按钮

3. 创建应用
	3.1 在终端输入完整命令: python3 manage.py startapp app01
	3.2 菜单栏--工具(tool)---运行 manage.py---startapp app02
4. 修改端口号等操作
点击运行配置---修改

二者的区别

1. 命令行创建不会有templates文件夹,需要自己创建,pycharm会自动创建并且自动在配置文件中配置对应的路径
TEMPLATES = [
    {
        
        'DIRS': [BASE_DIR / 'templates']
        ,
        
    },
]

主要文件介绍

--mysite 项目文件夹
	--mysite 文件夹
		--setting.py 配置文件
		--urls.py    路由与视图函数对应关系(路由层)
		--wsgi.py    wsgiref模块(不考虑)
    --manage.py      django的入口文件
    --db.sqlite3     django自带的sqlite3数据库(小型,有bug)
    
    --app01文件夹
    	--admin.py   django的后台管理
    	--apps.py    注册使用
    	--migrations文件夹   所有的数据库迁移记录
    	--models.py  数据库相关的 模型类(orm)
    	--tests.py   测试文件
    	--views.py   视图函数

应用

django是一款专门用来开发app的web框架,一个app就是一个独立的功能模块

setting.py中

DEBUG = True  # 上线之后改为False

创建应用时一定要去配置文件中注册
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',  # 全写
    'app02'  # 简写
]

Django三板斧

HttpResponse
返回字符串
return HttpResponse('sdf四十多覅')

render: request,template_name,
返回一个页面
第一种传值方式:更加精确,节省资源
render(request,'index.html',{键名:值:})

第二种传值方式:数据较多时,会将当前所在的空间中所有名字传递给html页面
render(request,'index.html',locals())

redirect:to,
重定向

注意事项

# 如何让计算机能够正常的启动Django项目
1. 计算机的名称不能有中文
	右键计算机,名称
2. 一个pycharm窗口只开一个项目
3. 项目里所有的文件也尽量不要出现中文
4. python解释器尽量使用3.4-3.6之间的版本,
	如何项目报错,点击最后一个报错信息,去源码中把逗号删除
	
# 版本
1.x 2.x 3.x(直接忽略)
1.x 2.x差距不大


Django 版本 Python 版本
2.2 3.5,3.6,3.7,3.8(2.2.8 添加),3.9(2.2.17 添加)
3.1 3.6,3.7,3.8,3.9(3.1.3 添加)
3.2 3.6, 3.7, 3.8, 3.9, 3.10 (在 3.2.9 中就已经加入了)
4.0 3.8,3.9,3.10
4.1 3.8, 3.9, 3.10, 3.11 (added in 4.1.3)

2023-02-09_191705

登录功能

html文件都放到templates文件夹中
其他静态文件放到static:js css 图片等文件  Django不会创建static,需要手动创建

静态文件配置

#  settings.py
STATIC_URL = '/static/'  # 令牌,如果要访问静态文件,必须以'/static/'开头

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')  # 一旦令牌正确,依次从上到下,查找
    # BASE_DIR / 'static'  
    os.path.join(BASE_DIR,'static1')
    os.path.join(BASE_DIR,'static2')
]

# 静态文件的动态解析,此时STATIC_URL令牌如何改变都不会影响运行
# html中
{% load static %}
<link rel="stylesheet" href="{% static '/static/bootstrap-3.4.1-dist/css/bootstrap.css' %}">

request对象方法

  • request.method:请求方式,大写
  • request.GET:get请求参数
    • request.GET.get()
    • request.GET.getlist()
  • request.POST:post请求参数
    • request.POST.get()
    • request.POST.getlist()
  • request.FILES: 文件信息
  • request.path
  • request.path_info
  • request.get_full_path:可以拿到?后的内容
  • request.body:原生的浏览器发来的二进制数据
"""
form表单
1. method默认get请求
2. action参数:
	2.1 不写,默认朝当前所在url提交数据
	2.2 全写,指明道姓
	2.3 只写后缀 /login_fn/
	
在前期使用django提交post请求时候,需要去配置文件中间件中注释一行代码'django.middleware.csrf.CsrfViewMiddleware',
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',
]


request.method    获取请求方式,全大写字符串
request.POST      获取post请求的普通参数,不含文件
	request.POST.get('username')      get只会获取列表的最后一个值
	request.POST.getlist('username')  getlist获得列表
request.GET
	request.GET.get('username')       get只会获取列表的最后一个值
	request.GET.getlist('username')   getlist获得列表

"""

pycharm链接数据库(mysql)

查找:
右上方database
左下方database
在配置中的plugins插件搜索安装

在没有,重装pycharm


一定先安装驱动,点击下载即可
链接数据库
修改完需要提交

Django链接数据库

Django默认数据库sqkite3
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

Django链接mysql
1. 配置文件中的配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'dbPycharm',
        'USER': 'root',
        'PASSWORD': '123',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'CHARSET': 'utf8',
    }
}
2. 代码声明
django默认用的是mysqldb模块链接Mysql(直接启动django会报错),但是该模块的兼容性不好,需要手动改为pymysql链接,
需要告诉django不要用默认的mysqldb,而是使用pymysql
在项目下或者任意app下的__init__.py文件中写上:
import pymysql
pymysql.install_as_MySQLdb()

Django ORM介绍

ORM, 对象关系映射
作用:能够让一个不用sql语句的小白也能通过python,面向对象的代码简单快捷的操作数据库
不足:封装程度高,有时候sql语句效率低下,需要自己写sql语句

类          表
对象        记录
对象属性     记录某个字段对应的值

models.py  数据库相关

利用ORM实现字段的增删改查操作

"""
1. 先去models.py中书写一个类
	class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True)
    # username varchar(32)
    username = models.CharField(max_length=32)
    # password int
    password = models.IntegerField()

*************************# 2 数据库迁移命令*************************
python3 manage.py makemigrations 将操作记录记录到小本本上(migrations文件夹)

python3 manage.py migrate  将操作真正的同步到数据库中
# 只要你修改了models.py中跟数据库相关的代码 就必须重新执行上述的两条命令
******************************************************************

class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True,verbose_name='主键')
    # username varchar(32)
    username = models.CharField(max_length=32,verbose_name='用户名')
    """
    CharField必须要指定max_length参数 不指定会直接报错
    verbose_name该参数是所有字段都有的 就是用来对字段的解释
    """
    # password int
    password = models.IntegerField(verbose_name='密码')


class Author(models.Model):
    # 由于一张表中必须要有一个主键字段 并且一般情况下都叫id字段
    # 所以orm当你不定义主键字段的时候 orm会自动帮你创建一个名为id主键字段
    # 也就意味着 后续我们在创建模型表的时候如果主键字段名没有额外的叫法 那么主键字段可以省略不写
    # username varchar(32)
    username = models.CharField(max_length=32)
    # password int
    password = models.IntegerField()

2. 字段的增加
    1. 在交互中输入默认值
    2. 在写语句时直接写上null=True
    3. 在写语句时直接写上default=默认值
3. 字段的修改
	1. 直接在语句中修改,makemigrations + migrate 提交
	
4. 删除很简单,直接注释掉(已有数据会丢失)
"""

利用ORM实现数据的增删改查操作

# 去数据库中查找
from app01 import models
name = 'aaa'
res = models.User.objects.filter(name=username).first()
if res:
    if password == res.password:
        return HttpResponse('收到了')
    return HttpResponse('密码错误')
return HttpResponse('用户名错误')


# 注册1(添加数据)
res1 = models.User.objects.create(name=username)

# 注册2(添加数据)
user_obj = models.User(name=username)
user_obj.save()


# 更新
# 1. update 批量更新,效率低,从头到尾将数据的所有字段全部更新
# 2. save() 局部更新
user_obj2 = models.User.objects.filter().update(name='ddd',...)

user_obj3 = models.User.object.filter()
user_obj3.name='aaa'
user_obj3.save()

"""
批量删除
models.User.object.filter().delete()
删除应该二次确认,删除数据不是真的删除,而是给一个标志位修改状态
"""

Django ORM 表与表之间的关系

"""
图书管理系统

作者

出版社

书籍

三者关系
书籍(多) --- 出版社(一) foregin key() references xxx(id)
作者(多)---- 书籍(多) 建立新表 foregin key(auth_id) references xxx(id);foregin key(book_id) references bbb(id)
作者(一)----作者详情(一) 一般外键建在查询较多的一方

models.OneToOneField          						OneToOneField会自动加_id后缀
models.ManyToManyFiled 
models.ForeginKey(on_delete=models.CASCADE)         OneToOneField会自动加_id后缀  

on_delete:
	1、models.CASCADE
    	级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
    2、models.SET_NULL
        当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
    3、models.PROTECT
        当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
    4、models.SET_DEFAULT
        当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
    5、models.SET()
        当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
    6、models.DO_NOTHING
        什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
    外键详细配置

django1.x版本中外键都是默认级联更新删除的

django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常:
TypeError: init() missing 1 required positional argument: ‘on_delete’


"""

django请求生命周期流程图

路由层

路由匹配

'''
路由匹配规则:
正则匹配,找到匹配的项就不再向下寻找

text与text/
寻找text路由,如果都没有,则自动加/ 再重头寻找
取消方式:
APPEND_SLASH = False  默认是True

"^text/$": 严格模式

首页匹配:"^$"
尾页匹配:""  放到最后

无名有名分组:不能混用
"^text/[0-9]{4}"
'''

无名分组

"""
使用括号:(\d+)
无名分组就是将括号中的匹配内容当做位置参数,传递给视图
"""
path('^text/(\d+)$')


def user(request,xx):
    print(xx) # 111
    return HttpResponse('aaa')

有名分组

path('^text/(?P<year>\d+)$')

def user(request,year):
    print(year) # 111
    return HttpResponse('aaa')

反向解析

# 无论url如何变化,都能找到对应的函数
# 通过一些方法得到一个结果,该结果可以直接访问对应的url触发视图函数
# 起别名
path('^text/$', views.func, name="ooo")

# 前端反向解析
{% url 'ooo'  %}
# 后端反向解析
from django.shortcuts import render, reverse
url = reverse('ooo')  # text/

无名分组反向解析

"""
无名分组反向解析
path('^text/(\d+)$', views.func, name="xxx")
index\数值
reverse(xxx)  报错

后端
reverse(xxx, args=(1,))   text/1


前端
{% url 'ooo' 12 %}         text/12

数据一般放的是主键值,进行编辑和删除
"""

有名分组反向解析

"""
无名分组反向解析
path('^text/(?P<year>\d+)$', views.func, name="xxx")
index\数值
reverse(xxx)  报错

后端两种写法
reverse(xxx, kwargs={'year':111})   text/111
reverse(xxx, args=(111,))   text/111

前端两种写法
{% url 'ooo' year=111 %}         text/111
{% url 'ooo' 111 %}         text/111

数据一般放的是主键值,进行编辑和删除
"""

路由分发

"""
django的每个应用都有自己的templates文件夹 urls.py static文件夹
django能够非常好的做到分组开发(每个人只写自己的app)
作为组长,可以将所有的app全部拷贝在一个项目里,然后再配置文件中注册,然后结合路由分发的特点将所有的app整合

当一个django项目中的url特别多的时候,总路由urls.py代码非常冗余,不好维护,此时也可以使用路由分发减轻总路由的压力

利用路由分发之后,
"""
# 总路由
from django.urls import path,include

path('^app01/', include('app01.urls'))


# 子路由 app01-->urls.py
from django.urls import path
from app01 import views

path('^reg/',views.reg)

名称空间

"""
多个应用之间,url有相同的别名时,无法反向解析
需要在总路由中加上名称空间

"""
#总路由
path('^app01/', include('app01.urls', namespace="app01"), )

#子路由
path('^reg/',views.reg,name='aaa')
reverse('app01:aaa')   # app01/reg/

# 前端
{% url 'app01:aaa' %} 

'''
一般情况下,在起别名的时候加上app前缀
'''

伪静态

"""
将一个动态网页,伪装成一个静态网页
伪装的目的在于增大网站的SEO查询力度,并且征集搜索引擎收藏本网站的概率

总结:无论怎么优化,始终干不过RMB玩家
path('^reg.html',views.reg,name='aaa')
"""

虚拟环境

"""
在正常开发中,会给每个项目配置一个该项目独有的解释器环境,该环境内只有该项目用到的模块,其他一概不装

"""

Django版本区别

'''
1. path 与 url
    django1.x中路由层使用的是url方法
    2.x 以上使用的 path

    url()第一个参数支持正则
    path()第一个参数不支持正则,写什么匹配什么


    如果习惯使用正则可以使用以下方式
    from django.urls import path, re_path
    re_path 等同 url方法

2. 转换器
path('index/<int:id>/')  将第二个路由内容转为int类型,然后以id关键字的形式传递给函数

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


path('articles/<int:year>/<int:month>/<slug:other>/', views.article_detail) 
# 针对路径http://127.0.0.1:8000/articles/2009/123/hello/,path会匹配出参数year=2009,month=123,other='hello'传递给函数article_detail


3. django1.x版本中外键都是默认级联更新删除的

django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常:
TypeError: init() missing 1 required positional argument: ‘on_delete’

'''

# 自定义转换器
class MonthConverter:
    regex='\d{2}' # 属性名必须为regex
	
    # value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
    def to_python(self, value):
        return int(value)
	
    # 和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用
    def to_url(self, value):
        return value # 匹配的regex是两个数字,返回的结果也必须是两个数字

视图层

三板斧

"""
HttpResponse

render

redirect

必须返回一个HttpResponse对象, render和redirect内部也是返回一个HttpResponse

"""
# render实现原理
from django.template import Template, Context

res = Template('<h1>{{ user }}</h1>')
data = Context({'user':{'name':'hyf','age':11}})
ret = res.render(data)

return HttpResponse(ret)

JsonResponse对象

"""
json格式;前后端数据交互时实现跨语言传输数据
JSON.stringify()
JSON.parse()

JSON.dumps()
JSON.loads()
"""
import json
def send_json(request):
    user = {'name':'hfy','age':11,'addr':'中文呢'}
    res = json.dumps(user, ensure_ascii=False)   #ensure_ascii默认是True ,转为ascii码
    
    # 使用JsonResponse
    res2 = JsonResponse(user, json_dumps_params={'ensure_ascii':False})
    
    # 列表
    res3 = JsonResponse([1,2,3,4],safe=False)
    return HttpResponse(res)

文件上传

"""
form表单上传文件
method='post'
enctype='multipart/form-data'
"""
def upload_file(request):
    if request.method == "POST":
        # 获取普通数据
        res1 = request.POST
        
        # 获取文件信息
        files_data = request.FILES.get('file')  # 文件对象
        with open(files_data.name,'wb') as f:
            for line in file_obj.chunks():   # 推荐加上chunks方法,不加是一样的,都是一行行读取
                f.write(line)

FBV与CBV

# 视图函数既可以是函数也可以是类
from django.views import View
class MyLogin(View):
    # 自动走get请求
    def get(self, request):
        return render(request, 'form.html')
    
    def post(self, request):
        return HttpResponse('post')
    
# 路由中
path('text/', views.MyLogin.as_views())
"""
FBV和CBV各有千秋
CBV特点
	能够根据请求方式的不同直接匹配对应的方法执行
"""
    

CBV源码

    """
    突破口在:as_views
    path('text/', views.MyLogin.as_views()) 
    判断as_views(),是静态方法@staticmethod还是类方法@classmethod
    通过源码可以得知是类方法
    返回的是view函数名即path('text/', views.view) 
    
    CBV和FBV在路由匹配上本质是一样的,都是路由对应的函数内存地址
    
    """
    
    def dispatch(self, request, *args, **kwargs):
        
        if request.method.lower() in self.http_method_names:
            '''
            getattr 反射机制,属性或方法查找顺序
            1. 在实例方法中找
            2. 产生实例的类
            3. 父类
            
            此时在MyLogin类中找'get'属性,
            '''
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
            
        return handler(request, *args, **kwargs)
    
    @classonlymethod
    def as_view(cls, **initkwargs):
       
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)      #  cls是我们自己写的类 MyLogin
            self.setup(request, *args, **kwargs)   # 设置对象属性
            
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
    
    # 设置对象属性
    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

模板语法传值

"""
{{}}   变量相关
{% %}  逻辑相关


模板语法可以传递的数值类型:
int
float
str
list
dict
set 集合{}
tuple 元组()
bool

函数名在前端会自动加括号调用,但是无法给函数传递参数
类名也会自动加括号调用

内部会自动判断是否加括号调用,一般情况下针对的是函数名和类名

django模板的取值方式,是固定的“句点符”--“.”
即可以点键名也可以点索引
"""

过滤器

"""
一些模版内置方法:60多个
{{数据 | 过滤器:参数}}

常用的:
length: 统计长度
{{b | default:'b为False显示此文本,否则显示b的值'}}
文件大小 :{{file_size | filesizeformat}}   1.2MB
日期格式: {{curren_time | date:'Y-m-d H:i:s'}}  
切片操作:{{list_data | slice:"0:10:2"}}
切取字符:{{info | truncatechars:9}}  包含三个点
截取单词:{{info_2 | truncatewords:9}} 按空格切
移除特定的字符:{{msg | cut:' '}}
拼接:{{list_data | join:'$'}},{{list_data | add:'后缀'}},{{list_data | add:10}}


转义: {{msg | safe}} <h1>sddsdf</h1> 默认取消转义
后端转义:  make_safe('<h1>asdfasf</h1>')

for 循环
    {% for foo in l %}
        <p>{{ forloop }}</p>   {'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 4, 'revcounter0': 3, 'first': True, 'last': False}


        <p>{{ foo }}</p>
    {% endfor %}
    
    {% empty %}
    	<p>循环为空时</p>

if 判断
    {% if b %}
        <p>1</p>>
    {% elif c%}
        <p>2</p>
    {% else %}
        <p>3</p>
    {% endif %}
    
起别名
{% with a.b.3.info as nn %}
    <p>{{ nn }}</p>
{% endwith %}
"""

自定义过滤器、标签、inclusion_tag

"""
三步走
1. 应用下必须创建templatetags文件夹
2. 在该文件内创建任意名称的py文件
3. 在该py文件内必须书写:
	from django import template
	register = template.Libarary()
	
最多两个参数
"""


# templatetags/mytags.py
from django import template

register = template.Library()


# 自定义过滤器,最多两个参数
@register.filter(name='boay')
def my_filter(v1, v2):
    print(v1, v2)
    return v1 + v2

# 自定义标签, 参数可以多个
@register.simple_tag(name='myTag')
def my_tag(v1, v2):
   return '%s-%s-%s'%(v1,v2,v3)

# 使用
{% load mytags %}<p>{{ n | boay:333 }}</p>
{% myTag 参数1 参数2 参数3 %} # 空格隔开

"""
自定义inclusion_tag
内部原理
	先定义一个函数
	在页面中调用,可以传值
	运行函数,将结果返回给一个页面
	将渲染好的结果放到调用的位置
	
总结:当页面的某一个地方的页面需要传递参数才能动态渲染,并且在多个页面都有使用到的话,就可以采用inclusion_tag的方式
"""
@register.inclusion_tag('left.html') # left.html页面是一个缺失的页面
def left(n):
    print(n)
    list_data = ['第{}列'.format(i) for i in range(n)]

    return locals()

模板的继承

"""
子页面中
{% extends 'home.html' %}  继承父页面

替换其中的内容
{% block context %}
....
{% endblock %}


父页面
{% block context %}
将被替换的内容区域
{% endblock %}


一般有三块区域
1. css区域
2. html区域
3. js区域
"""

模板的导入

"""
将页面中局部作为模块

在需要的位置 
{% include 模块1.html %}
"""

模型层

单表操作

# django中的sqlite3对日期不敏感,会出错

# 删除
# res = models.User.objects.filter(pk=2).delete()
# print(res)

'''
    pk会自动寻找主键
'''

# res = models.User.objects.filter(pk=2).first()
# res.delete()
# print(res)


# 修改
# models.User.objects.filter(pk=1).update(name='hyf01')
# user_obj = models.User.objects.get(pk=4)

"""
    不推荐,一旦get参数不存在,直接报错,而filter不会
    user_obj.name = 'xxx'
    user_obj.save()
"""

必知必会13条

"""
all()           查询所有数据   

filter()        带有条件查询

get()           直接拿到数据对象, 但是条件不存在直接报错

first()			拿到queryset中第一个元素

last()          拿到queryset中最后一个元素

values()        获取指定获取的字段  select name from ...
models.User.objects.values('name') <Queryset [{'name':'xxx'},{'name':'vvv'}]>

values_list()   获取指定获取的字段 [()]
res = models.User.objects.values('name','age') <Queryset [('xxx',11),('bbb',12)]>
res.query       查看内部的sql语句,只有Queryset对象,才能.query

distinct()      去重, 一定要是一模一样的数据,如果带有主键可定不一样
models.User.objects.values('name').distinct()


order_by()      排序默认升序,order_by('-name') 加上减号是降序
reverse()       反转,数据之前一定是排序好的,
count()         统计当前数据的个数
exclude()       排除在外
exists()		判断是否存在
"""

下划线查询

"""
格式: 属性__gt=33 
__gt   : 大于
__gte  : 大于等于
__lt   : 小于
__lte  : 小于等于
__in   : age__in=[1,2,3] 1或2或3
__range: 之间,首位都要age__range=[1,3]  1<=x<=3
__contains: 包含  name__contains='x'  name中包含’x' 默认区分大小写,忽略大小写(加i) name__icontains='x'
__startwith : 以什么开头
__endwith:  以什么结尾
__month : 按照月份 __month='1'
__year : 按照年份 __year='1'

"""

查看内部sql语句的方式

# 方式一:query
res = models.User.objects.values('name','age')   #  <Queryset [('xxx',11),('bbb',12)]>
print(res.query)       # 查看内部的sql语句,只有Queryset对象,才能.query


# 方式二:在配置文件中拷贝如下代码
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

测试脚本

"""
当只是想要测试django中某一个py文件内容时,可以不用书写前后端交互的形式,而是直接写一个测试脚本

测试环境的准备:
manage.py 中拷贝以下代码

import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject4.settings')
    
if __name__ == '__main__':
    main()
    
然后在tests.py中粘贴

import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject4.settings')
    
    # 自己写几行
    import django
    django.setup()

	# 所有代码一定要写在测试环境准备完成以后,否则会报错
    from app01 import models

    models.User.objects.all()
    
    
if __name__ == '__main__':
    main()

"""

一对多外键增删改查

"""
书籍Book        多
出版社Publish    一

在书籍表中建立外键
publish = models.Book.objects.ForeignKey(to='Publish', on_delete=models.CASCADE)

"""
# 增
# 1 直接写实际字段 publish_id
models.Book.objects.create(xxxx,xxxx,publish_id=1)  

# 2 虚拟字段 对象  publish_obj, 外键 = publish_obj
publish_obj = models.Publish.objects.filter(pk=1).first()  
models.Book.objects.create(xxxx,xxxx,publish=publish_obj)


# 删
models.Publish.objects.filter(pk=1).delete() 

# 修改
# 1 直接写实际字段 publish_id
models.Book.objects.filter(pk=1).update(publish_id=2)
# 2 虚拟字段 对象  publish_obj, 外键 = publish_obj
publish_obj = models.Publish.objects.filter(pk=1).first()  
models.Book.objects.filter(pk=1).update(publish=publish_obj)

多对多外键增删改查

"""
书籍Book
作者Authors

"""
# 增
book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors 类似于找到第三张关系表了
book_obj.authors.add(1)  # pk=1 书籍id为1 的书籍绑定一个主键为1的作者
book_obj.authors.add(2,3) # pk=1 书籍id为1 的书籍绑定一个主键为2,的作者以及绑定一个主键为2,的作者
# 放对象
authors_obj1 = models.Authors.objects.filter(pk=1).first()
authors_obj2 = models.Authors.objects.filter(pk=1).first()
book_obj.authors.add(authors_obj1,authors_obj2)


# 删
book_obj.authors.remove(2)   # 删除 pk=1 书籍id为1 的书籍并且作者为2的数据
book_obj.authors.remove(authors_obj1)


# 修改
book_obj.authors.set([1,3])   # set括号内必须给一个可迭代对象(可以是数字或对象) 先删除再增(已有的不动)


# 清空
book_obj.authors.clear()   # 在第三张表中清空某个书籍与作者的绑定关系

正反向的概念

'''
开外键字段在哪里,外键在的一方去查是正向,没有外键的一方查有外键的一方是方向
正向:多 查 一, 书籍查出版社
反向:一 查 多, 出版社查书籍

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

正向查询按字段
反向查询按表名小写
	表名_set
	
_set:当查询结果可以有多个时,要加上_set.all(), 如果结果是一个,则不需要加_set.all()
'''

多表查询

子查询(基于对象)


# 1. 查询书籍主键为1的出版社
# book_obj = models.Book.objects.filter(pk=1).first()
# res = book_obj.publish
# print('出版社名称:%s' % res.publish_name)

# 2. 查询书籍主键为1的作者,
# book_obj = models.Book.objects.filter(pk=1).first()
# res = book_obj.author.all()
# print(res)

'''
    当结果可能是多个时就需要使用到all()
    数据就一个时,不需要
'''

# 3. 查询作者主键为1的作者电话
# author_obj = models.Authors.objects.filter(pk=1).first()
# res = author_obj.detail
# print('电话号码:%s'%res.phone)

# 4. 由出版社去查书, 反向
# publish_obj = models.Publish.objects.filter(pk=1).first()
# res = publish_obj.book_set.all()
# for obj in res:
#     print(obj.book_name)

# 5. 查询作者’阿里‘写过的书
# author_obj = models.Authors.objects.filter(name='阿里').first()
# res = author_obj.book_set.all()  # author_obj.book_set  app01.Book.None
# for obj in res:
#     print(obj.book_name)

# 6. 手机号以9995结尾的作者
# author_detail_obj = models.AuthorsDetail.objects.filter(phone__endswith='9995').first()
# print(author_detail_obj)
# res = author_detail_obj.authors
# print(res.name)

'''
    
'''
"""
总结:
正向查询:.外键名  如果结果为多个时需要加上.all()
反向查询:.表名(小写) 如果结果为多个时需要加上_set.all() 如:author_obj.book_set.all()

反向查询时当查询结果可以有多个时,要加上_set.all(), 如果结果是一个,则不需要加_set.all()

"""

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

# 基于双下划线的跨表查询 跨表 外键字段__普通字段

# 1. 查询书籍主键为1的出版社名和书籍名称
# res = models.Book.objects.filter(pk=1).values('publish__publish_name','book_name')
# print(res)

# 反向查询 filter中使用__
# res = models.Publish.objects.filter(book__book_name='红楼梦').values('publish_name','book__book_name')
# print(res)

# 2. 查询pick的手机号和作者姓名
# res = models.Authors.objects.filter(name='pick').values('name', 'detail__phone')
# for dict_obj in res:
#     name = dict_obj.get('name')
#     phone = dict_obj.get('detail__phone')
#     print(name,phone)

# 3. 查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('author__name', 'book_name')
print(res)
"""
总结:在联表查询中,双下划线
filter中可以使用 表名__字段名的方式进行反向查询
反向查询时 双下划线的方式:表名__字段名

正向查询时:外键名__字段名 , 外键名表示进入关联表中
"""

聚合查询

"""
aggregate()

需要先导入
只要是跟数据库相关的都在django.db.models里,如果没有则在django.db
通常情况下都是配合分组使用的
单独使用时:aggregate   
"""
from django.db.models import Max, Min, Sum, Count, Avg
# 1 查询所有书的平均价格 
res = models.Book.objects.aggregate(Avg('price'))
print(res)

分组查询

"""
annotate()

Mysql中分组之后,默认只能获取分组的依据,组内的其他字段都无法直接获取
	严格模式:QNLY_FULL_GROUP_BY
	
models 后面点什么,就按什么分组
"""
# 1 查询所有书的平均价格
# res = models.Book.objects.aggregate(Avg('price'))
# print(res)

# 2. 统计一本书的作者个数 author__id == author
res = models.Book.objects.annotate(author_num=Count('author')).values('author_num', 'book_name',)
print(res)

# 3. 统计每个出版社最便宜书的价格
res = models.Publish.objects.annotate(price_min=Min("book__price")).values('publish_name', 'price_min',
                                                                          )
print(res)

"""
    select * from app01_book inner join app01_publish on app01_book.publish_id=app01_publish.id;
"""

# 4. 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('author')).filter(author_num__gt=1).values('book_name', 'author_num')

"""
    只要orm返回的结果是一个queryset对象,那么就可以继续使用queryset对象封装的方法
"""

# 5. 查询每个作者出的书的总价格
res = models.Authors.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')

"""
如果按照指定字段分组该如何做  values
以price为例
models.Book.object.values('price').annotate()

如果数据库分组出现错误
	修改数据库严格模式
"""

F与Q查询

"""
F查询: 可以将列表中的字段的值提取出来
F(字段名):
	如果是数值类型可以直接加减
	如果是字符串类型需要拼接
		from django.db.models.function import Concat
		from django.db.models import Value
		Concat(F(字段名),Value('拼接的字符串'))
		
"""
# 查询书籍卖出的数量大于库存的书籍
res = models.Book.objects.filter(maichu__gt=F('kuchun')).values('book_name')
"""
Q查询:
	and: filter(Q(maichu__set=100),Q(price__set=200))
	or:  filter(Q()|Q())
	not: filter(~Q())
filter括号内多个参数是and关系

Q的高阶用法:能将查询左边也变为字符串的形式
q = Q()

q.connector="or"   修改连接符 默认是and

q.children.append('maichu__set',100)
q.children.append('price__set',200) 
filter(q)
"""
# 查询卖出数量大于100或者价格小于200的书籍
res = models.Book.objects.filter(Q(maichu__get=100) | Q(price__lt=200))

django中开启事务

"""
事务的特性
ACID
原子性:不可分割的最小单位
一致性:
隔离性:事务之间互相不影响
持久性:事务一旦确认,永久生效
	事务的回滚
		rollback
	事务的确认
		commit
"""
from django.db import transaction

try:

	with transaction.atomic():
    	# sql语句,在此代码块中都属于一个事务
except Exception ase:
    # 捕获 

    

orm中常用字段及参数

AutoField

int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。

CharField

字符类型,必须提供max_length参数, max_length表示字符长度。

IntegerField

一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)

BigIntegetField

长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

DecimalField

- 10进制小数
- 参数:
    max_digits,小数总长度
    decimal_places,小数位长度

EmailField

字符串类型,Django Admin以及ModelForm中提供验证机制

DateField和DateTimeField

auto_now_add:配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
auto_now:配置上auto_now=True,每次更新数据记录的时候会更新该字段。

BooleanField

布尔值类型,
该字段传入 布尔值(True/False) 数据库中存0/1

TextField

文本类型,没有字数限制,

FileField(FileField)

 - 字符串,路径保存在数据库,文件上传到指定目录
 - 参数:
 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   上传图片的宽度保存的数据库字段名(字符串)

其他字段

	AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

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

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    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   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

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

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型
 字段合集

字段对应关系

对应关系:
    'AutoField': 'integer AUTO_INCREMENT',
    'BigAutoField': 'bigint AUTO_INCREMENT',
    'BinaryField': 'longblob',
    'BooleanField': 'bool',
    'CharField': 'varchar(%(max_length)s)',
    'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
    'DateField': 'date',
    'DateTimeField': 'datetime',
    'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
    'DurationField': 'bigint',
    'FileField': 'varchar(%(max_length)s)',
    'FilePathField': 'varchar(%(max_length)s)',
    'FloatField': 'double precision',
    'IntegerField': 'integer',
    'BigIntegerField': 'bigint',
    'IPAddressField': 'char(15)',
    'GenericIPAddressField': 'char(39)',
    'NullBooleanField': 'bool',
    'OneToOneField': 'integer',
    'PositiveIntegerField': 'integer UNSIGNED',
    'PositiveSmallIntegerField': 'smallint UNSIGNED',
    'SlugField': 'varchar(%(max_length)s)',
    'SmallIntegerField': 'smallint',
    'TextField': 'longtext',
    'TimeField': 'time',
    'UUIDField': 'char(32)',

自定义字段

# 自定义字段
rom django.db import models

# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
    '''
    自定义的char类型的字段类
    '''
    def __init__(self,max_length,*args,**kwargs):
        self.max_length=max_length
        super().__init__(max_length=max_length,*args,**kwargs)

    def db_type(self, connection):
        '''
        限定生成的数据库表字段类型char,长度为max_length指定的值
        :param connection:
        :return:
        '''
        return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
    id=models.AutoField(primary_key=True)
    title=models.CharField(max_length=32)
    class_name=FixCharField(max_length=16)
    gender_choice=((1,'男'),(2,'女'),(3,'保密'))
    gender=models.SmallIntegerField(choices=gender_choice,default=3)

字段参数

"""
null: 字段是否可以为空
unique: 如果设置为unique=True 则该字段在此表中必须是唯一的
	ForeignKey(unique=True) === OneToOneKey()
db_index: 如果db_index=True 则代表着为此字段设置索引。
default: 设置默认值
"""

数据库查询优化

图书管理系统

标签:__,obj,name,models,res,django,Django
From: https://www.cnblogs.com/hyf120/p/17135653.html

相关文章

  • [django]drf入门004 过滤排序分页(转载)
    原文:https://pythondjango.cn/1.分页目录为什么要分页?DRF提供的分页类PageNumberPagination类LimitOffsetPagination类CursorPagination类函数类视图中使用分......
  • django中使用celery,模拟商品秒杀。
    Celery是Python开发的简单、灵活可靠的、处理大量消息的分布式任务调度模块 安装:pipinstallcelery#安装celery库pipinstallredis#celery依赖于......
  • django修改认证模型类
    1.我在一个子应用下面创建了一个apps目录,且在apps下又创建了一个子应用users,结构如下图:2.在users的models.py中fromdjango.dbimportmodelsfromdjango.contrib.auth......
  • django日志集成输出器
    在配置文件中importos#⽇志LOGGING={'version':1,#自定义一个简单版本'disable_existing_loggers':False,#是否禁⽤已经存在的⽇志器'form......
  • Django Rest Frame work 如何使用serializers序列化函数新手教程
    DjangoRestFramework如何使用serializers序列化   DjangoRestFramework提供了serializers模块,用于序列化和反序列化模型实例以及原生数据类型......
  • Django Rest Frame work 如何使用serializers序列化
    DjangoRestFramework如何使用serializers序列化   DjangoRestFramework提供了serializers模块,用于序列化和反序列化模型实例以及Python原生数......
  • 【InterView】Django部分(一)
    目录ORM是什么?优势?get请求和post请求的区别简述django请求的生命周期?ORM是什么?优势?ORM:中文翻译为对象关系映射。模型类名对应数据库表名类属性对象数据库表字段类属......
  • django连接ubuntu22下的mysql8
    1.安装mysql(这里就不过多赘述了)sudoapt-getinstallmysql-server  2.登录mysql  (1)在根目录/etc/mysql/debian.cnf,使用默认账户密码登录   (2)空密码......
  • python Django基础
    django官网https://www.djangoproject.com/download/文档https://docs.djangoproject.com/安装Django安装官网LTS版本pipinstalldjango==3.2.15Django命令>django......
  • 1.初识 Django
    设计模式定义#mysite/news/models.pyfromdjango.dbimportmodelsclassReporter(models.Model):full_name=models.CharField(max_length=70)def_......