python-django

目录:1.关于web框架  2.wsgiref模块  3.自己写一个web框架  4.http协议  5.django

关于web这一部分的内容还有待进一步整理补充

关于web框架:

         web应用程序是一种可以通过web访问的应用程序

                   有两种模式C/S和B/S,一般是B/S模式

                  

                   Google浏览器检查的时候network里面:

                            preview是显示浏览器渲染后的预览效果

                            response是浏览器得到的响应的具体内容,就是代码样式的

                  

         web框架是一种开发框架,用来支持动态网站、网络应用和网络服务的开发

wsgiref模块就是python基于wsgi协议开发的服务模块,本质上是一个web框架

         1.按照http请求协议解析数据

         2.这部分是我们自己写的,上面的跟下面的都用wsgiref模块来是实现

         3.按照http响应协议封装数据

        

         实例:

                   from wsgiref.simple_server import make_server

                   def application(environ, start_response):

                            # 按照http协议解析的数据就是environ

                            # 按照http协议组装的数据的格式就是start_response

                            path = environ.get('PATH_INFO')  # 这个environ是字典格式

                            print(path)

                            start_response('200 OK', [('Content-Type', 'text/html')])  # 这里第二个元素这个列表可以为空,但是必须要有这个列

                            data = b''

                            if path == '/login':

                                     with open('login.html', 'rb') as f:

                                               data = f.read()

                            elif path == '/index':

                                     with open('index.html', 'rb') as f:

                                               data = f.read()

                            return [data]  # 这里必须用列表的格式

                   # 封装socket

                   http = make_server('127.0.0.1', 8060, application)

                   # 等待用户连接 conn,addr = sock.accept()

                   http.serve_forever()

自己写一个web框架:

         在pycharm -----> day49-web -----> 03文件夹

        

         自己写的这个03就是一个web框架

         1.main.py是主函数入口,启动文件,封装了socket

         2.urls.py:路径与视图函数的映射关系------url控制器

         3.views.py是整个视图函数部分,固定有一个形参environ-----视图函数

         4.图片、html文件等放在templates里面-------模板

         5.models.py在项目启动前,在数据库中创建表结构,单独执行的-------与数据库相关

http协议

         hyper text transfer protocol 超文本传输协议

                   用于万维网(world wide web)服务器与本地浏览器之间传输超文本的传送协议

        

         是一个属于应用层的面向对象的协议

         特点:

                   基于TCP/IP协议

                   基于请求-响应模式

                            请求是从客户端发出的,服务端响应该请求并返回,也就是说先从客户端建立通信

                   无状态保存

                            http协议本身不对请求和响应之间的通信状态进行保存

                   无连接

                            限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后就断开连接

         http的请求协议与响应协议

                   http协议包含 由浏览器发送数据到服务器需要遵循的请求协议

                                                和 服务器发送数据到浏览器需要遵循的响应协议

                  

                   用于http协议交互的信被称为http报文,请求报文和响应报文

                           

                   请求协议:

                            请求格式

                                     请求首行:请求方法+URL+协议版本(HTTP/1.1),用\r\n与请求头分割

                                     请求头,有多个,用\r\n分割,一直到遇到\r\n\r\n,这后面的内容就是请求体了

                                     请求体,只有post请求才有请求体

                                    

                            请求方法

                                     get  提交的数据会被放在url之后,以?分割url和传输数据,参数之间用&连接

                                                提交的数据有大小限制

                                                有安全问题

                                                没有请求体

                                                常用于做查询操作的时候

                                                默认的,包括a标签也是get方法

                                                

                                     post 把提交的数据放在http包的body中

                                                提交数据没有大小限制

                                                常用于数据库更改的时候

                  

                   响应协议:

                            响应格式

                                     响应首行:协议版本(HTTP/1.1)+状态码+OK(状态码的原因短语)

                                     响应头

                                     响应体

                                    

                            响应状态码

                                     1XX  Informational(信息性状态码)     接收的请求正在处理

                                     2XX  Success(成功状态码)             请求正常处理完毕

                                     3XX  Redirection(重定向状态码)      需要进行附加操作以完成请求,服务器发出的,

                                                                                                                          举个例子就是访问的网站换域名了,访问原来的网址自动跳转到新的

                                     4XX  Client Error(客户端错误状态码)  服务器无法处理请求

                                     5XX  Server Error(服务器错误状态码)          服务器处理请求出错

django

         是一种web框架

         MTV模型的

                   M代表model模型

                   T代表Template模板

                   V代表view视图

        

         一个django project

        

                   django-admin startproject mysite

                 

                   下面包含

                            manage.py  与django进行交互的

                            mysite/

                                     __init__.py

                                     settings.py  配置文件

                                     urls.py  控制器/路由

                                     wsgi.py

                   在mysite目录下创建应用

                            python manage.py startapp blog

                            下面包含

                                     blog:

                                               __init__.py

                                               admin.py

                                               apps.py

                                               migrations

                                                        __init__.py

                                               models.py

                                               tests.py

                                               views.py

                  

                   启动django项目

                            python manage.py runserver 8080

第一个简单实例在新项目django_01里面,settings里面TEMPLATES的DIRS加一句os.path.join(BASE_DIR, 'templates')

静态文件配置在新项目django_02里面,重点在于

        先加一个static包,盛放jquery文件,这里static就固定用这个名字,虽然可以改,但是不要改了

        再在settings里面加了一个

            STATICFILES_DIRS = [

                os.path.join(BASE_DIR, 'static')

            ]

        这样在客户端访问static/这个地址的时候才能访问的到

        这样配置完了以后写html的时候就可以用jquery文件了,<script src="/static/jquery-3.3.1.js"></script>

        然后,控制html的css文件跟js文件也可以单独拿出来放到static里面,同一个功能的可以放到同一个包里

        html里面<link rel="stylesheet" href="/static/app01/timer.css">

                <script src="/static/app01/timer.js"></script>引入

                要注意引入时候的先后顺序

                                    

路由层(URLconf) django_03

         from django.urls import path,re_path

         path是django2版本的语法,re_path是django1版本的语法,2版本两种都支持

        

         URL配置就像django所支撑网站的目录,本质是url与要被该url调用的视图函数之间的映射表

         就是通过这个来告诉django,对于客户端发来的某个url调用哪一段逻辑代码对应执行

         说白了就是哪一个路径由哪一个视图函数来处理

        

         注意:

                   若要从URL 中捕获一个值,只需要在它周围放置一对圆括号,括号是分组的意思,会默认传值,写视图函数的时候要多写一个形参,一个括号多写一个

                   不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。

                   每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的”,字符串中任何字符都不应该转义

                  

         有名分组:

                   使用命名的正则表达式组来捕获URL中的值并以关键字参数传递给视图

                   (?P<name>pattern) name是组的名称,也就是关键字参数时候关键字key  pattern是正则匹配规则

                  

         分发:

                   把app01的功能单独出来,放到app01-->urls里面,就是在app01里面再写一个urls.py

                   然后在主urls里面先引入include,再像下面这样写

                   re_path(r"app01/", include("app01.urls")),

                  

         登录验证的实例在django_03

                   def login(request):

                            if request.method == 'GET':

                                     return render(request, 'login.html')

                            else:

                                     user = request.POST.get('user')  # request.POST request.GET拿到的都是字典格式,必须大写

                                     pwd = request.POST.get('pwd')

                                     if user == 'yuan' and pwd == '123':

                                               return HttpResponse('登录成功')  # 必须要有返回

                                     else:

                                              return HttpResponse('用户名或密码错误')

        

         反向解析

                   在使用django项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中或用于处理服务器端的导航

                   硬编码或者设计专门的url生成机制会容易产生过期的url

                  

                   所以在需要url的地方,对于不同层级,django提供不同的工具用于url反查:

                            在模板中,使用url模板标签

                                     path('login/', views.login, name="Log")  # 使用name=给url起别名

                                     <form action="{% url 'Log' %}" method="post">  # 使用反向解析的固定格式,与render有关

                            在python代码中,使用from django.urls import reverse()函数

                                     也是先在url里面起别名

                                               re_path(r'^articles/2003/$', views.special_case_2003, name="s_c_2003"),

                                     再在views.py里面引入reverse

                                               url = reverse("s_c_2003")

                  

                   命名url模式时,需要确保使用的名称不会与其他应用中的名称冲突

                  

         名称空间namespace

                   名称空间是表示标识符的可见范围

                   一个标识符可在多个名称空间中定义,它在不同名称空间中的含义互不相干

                  

                   由于别名name没有作用域,django在反解url时,会在项目全局顺序搜索,当查到第一个name指定url时就返回

                  

                   可以在分发的时候设定namespace是“app01”,放在include里面,限定名称空间,格式是include(("app01.urls","app01"))

                            在使用反解的时候reverse(app01:index)

                  

         django2.0版本的path

                   特有的功能,规则如下:

                            使用尖括号<>从url中捕获值,捕获到的值字符串格式

                            捕获值中可以包含一个转化器类型,比如使用<int:name>捕获一个整数变量

                                     如果没有转化器,将匹配任何字符串,当然也包含了/字符

                            无需添加前导斜杠

                           

                           

                            django默认支持以下5个path转化器(Path Converters)

                                     str   匹配除了路径分隔符/之外的非空字符串,默认值

                                     int   匹配正整数,包含0

                                     slug  匹配字母、数字、横杠和下划线组成的字符串

                                     uuid  匹配格式化的uuid

                                     path  匹配任何非空字符串,包含路径分隔符,?不行,因为?是路径分隔符

                  

                            注册自定义转化器

                                     三点要求:

                                               regex 类属性,字符串类型

                                               to_python(self, value)方法,value是由雷属性regex所匹配到的字符串,返回具体的python变量值

                                                        以供django传递到对应的视图函数中

                                               to_url(self, value)方法,和to_python相反,value是一个具体的python变量值,返回其字符串,通常用于url反向引用

                                    

                                     实例:

                                               class FourDigitYearConverter: 

                                                        regex = '[0-9]{4}' 

                                                        def to_python(self, value): 

                                                                 return int(value) 

                                                        def to_url(self, value): 

                                                                 return '%04d' % value 

                                               使用register_converter 将其注册到URL配置中:

                                               from django.urls import register_converter, path 

                                               from . import converters, views 

                                               register_converter(converters.FourDigitYearConverter, 'yyyy') 

                                               urlpatterns = [ 

                                                        path('articles/2003/', views.special_case_2003), 

                                                        path('articles/<yyyy:year>/', views.year_archive), 

                                                        ... 

                                               ]

                                    

视图层

         在django_04

         一个视图函数,简称视图,是一个简单的python函数,它接受web请求并返回web响应

         响应可以是任何东西,但是必须有

         我们约定俗成的将视图放在项目或应用程序目录中名为views.py的文件中

         也约定俗成的将request作为第一个参数传进去

        

         url:协议://IP:port/路径path?请求数据

                  

         请求对象HttpRequest

                   通常称之为request

                   属性:

                            request.method  拿到的就是get或post

                            request.GET     拿到的是字典,可以用get拿数据

                            request.POST  拿到的是字典,可以用get拿数据

                            request.path   拿到的是/index/这一部分,只拿路径,不拿数据部分

                           

                   常用方法:

                            HttpRequest.get_full_path()    返回path,这个会连同数据一起拿到,而上面的path只拿路径

                            HttpRequest.is_ajax()   

        

         响应对象HttpResponse

                   主要由三种形式

                            1.HttpResponse()    括号内直接跟一个具体的字符串作为相应体,可以渲染标签

                           

                            2.render()        

                                     render(request, template_name,[context])

                                     request用于生成响应的请求对象

                                     template_name是要使用的模板的完整名称,就是那个页面html文件

                                    

                                     可选参数context是提交到模板上下文中的一个字典,默认是一个空字典,如果字典中的某个值是可调用的,

                                               视图将会在渲染模板之前调用它,模板语法{'ctime':ctime},在html里面{{ ctime }}

                                              

                            3.redirect()

                                     传递要重定向的一个硬编码的url

                                               return redirect('/some/url')

                                     也可以传递一个完成的url

                                               return redirect('http://example.com')

                                              

模板层

         在django_05

         模板语法只有两个:{{}}  0.渲染变量

                                                                 1.深度查询,使用句点符,就是用.,一层层都是用点来查

                                                                 2.过滤器

                                                 {%%}  0.渲染标签

         在django模板中遍历复杂数据结构的关键是句点字符,语法:{{var_name}}

        

                   return render(request, 'index.html', locals())  # locals()用于局部变量比较多的时候,也是按照键值对字典的方式

                  

                   对于复杂数据结构,用.来查询

                   <p>{{ l.1 }}</p>

                   <p>{{ info.name }}</p>

                   <p>{{ alex.name }}</p>

                   <p>{{ alex.age }}</p>

                   <p>{{ person_list.1.age }}</p>

        

         过滤器

                   语法:{{obj|filter_name:param}}

                  

                   default

                            {{value|default:"nothing"}}

                            如果一个变量是false或者为空,显示给定的nothing,否则,显示变量的值

                  

                   length

                            {{value|length}}

                            返回值的长度,它对字符串和列表都起作用

                            如果value是['a','b','c','d'],那么输出4

                  

                   filesizeformat

                            {{value|filesizeformat}}

                            将值格式化为一个人类可读的文件尺寸

                            如果value是123456789,输入将会是117.7MB

                  

                   date

                            {{value|data:"Y-m-d"}}

                            如果value=datetime.datetime.now()

                  

                   slice切片,顾头不顾尾

                            {{value|slice:"2:-1"}}

                            如果value="hello world"

                  

                   truncatechars

                   truncatewords

                            {{value|truncatechars:9}}

                            如果字符串字符多于指定的字符数量,那么将会被截断,截断的字符串将会以可翻译的省略号序列("...")结尾

                            参数是要截断的字符数,注意后面的三个...会占空

                  

                   safe

                            告诉django这段代码不必转义

                            value="<a href="">点击</a>"

                            {{value|safe}}

                  

                   add

                            {{ l.1|add:100 }}加法

                  

         标签

                   看起来是这样的{% tag %}

                  

                   for标签

                            遍历每一个元素

                            {% for i in l  %}

                                     <p>{{ i }}</p>

                            {% endfor %}

                            遍历每一个字典

                            {% for i, v in info.items %}

                                     <p>{{ forloop.counter }} {{ i }}:{{ v }}</p>  # 使用forloop加序号,作用类似于enumerate,但是从1开始,counter0就从0开始

                            {% endfor %}

                  

                   for...empty

                            for标签带有一个可选的{% empty %}从句,以便在给出的组是空或者没找到时可以有所操作

                            {% for person in person_list %}

                                     <p>{{ person.name }}</p>

                            {% empty %}

                                     <p>sorry,no person here</p>

                            {% endfor %}

                  

                   if标签

                            {% if %}会对一个变量求值,如果它的值是True(存在、不为空且不是boolean类型的false值),输出对应的内容

                            {% if user %}

                                     <p><a href="#">hi{{ user }}</a></p>

                            {% else %}

                                     <p><a href="#">登录</a></p>

                            {% endif %}

                           

                   with标签

                            使用一个简单的名字缓存一个复杂的变量,当你需要使用一个昂贵的方法(比如访问数据库)很多次时非常有用

                            {% with person_list2.1.name as n %}

                                     {{ n }}

                                     {{ n }}

                                     {{ n }}

                                     {{ n }}

                            {% endwith %}

                           

                   csrf_token

                            用于跨站请求伪造保护,加在html的form表单里面

                            <form action="" method="post">

                                     {% csrf_token %}

                                     <input type="text" name="user">

                                     <input type="submit">

                            </form>

                           

         自定义标签和过滤器

                   1.在settings中INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag

                   2.在app中创建templatetags模块,模块名只能是templatetags,是一个包

                   3.创建任意.py文件,如my_tags.py

                            from django import template

                            from django.utils.safestring import mark_safe

                             

                            register = template.Library()   #register的名字是固定的,不可改变

                             

                             

                            @register.filter  自定义的过滤器最多只能传两个值进去

                            def filter_multi(v1,v2):

                                     return  v1 * v2

                            <br>

                            @register.simple_tag  自定义标签 没有传参的限制

                            def simple_tag_multi(v1,v2):

                                     return  v1 * v2

                            <br>

                            @register.simple_tag

                            def my_input(id,arg):

                                     result = "<input type='text' id='%s' class='%s' />" %(id,arg,)

                                     return mark_safe(result)

                   4.在使用自定义simple_tag和filter的html文件中导入之前创建的my_tags.py

                            {% load my_tags %}

                   5.使用simple_tag和filter,filter可以用在if等语句之后,simple_tag不可以

                            {% if i|multi_filter:20 > 300 %}

                                     <p> >300 </p>

                            {% else %}

                                     <p> {{ i|multi_filter:20 }} </p>

                            {% endif %}

                           

         继承

                   django_05的base.html,include也在里面,include是把部分内容单独拿出来,用include引入

                            {% include 'advertise.html' %}

                   base是一个html模板,在其他html中用{% extends 'base.html' %}继承,这一句必须写在首行

                            这样新的html就拥有相同的样式,

                            然后再base中放空盒子用来给新html添加内容,空盒子如下:

                                {% block con %}

                                     {% endblock %} 

                                     盒子可以放多个,con可以随便写,title也可以这样写,block盒子越多越好

                                     endblock也可以起名字,这样更可读

                            在新html中,把要添加的内容放到盒子中间

模型层

         ORM是对象-关系-映射的简称,实现了数据模型与数据库的解耦

                   即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库

                  

                   只能对表进行操作,不能对数据库进行操作

                  

         单表操作django_06

                   创建表

                            1.在app01的models.py里面,固定格式如下:

                           

                                     from django.db import models

                                     # Create your models here.

                                     class Book(models.Model):

                                               id = models.AutoField(primary_key=True)

                                               title = models.CharField(max_length=32)

                                               pub_date = models.DateField()

                                               price = models.DecimalField(max_digits=8, decimal_places=2)  # 这个是最大是八个数,有两位是小数

                                               publish = models.CharField(max_length=32)

                  

                            2.配置settings

                                     DATABASES = {

                                               'default': {

                                                        'ENGINE': 'django.db.backends.mysql',

                                                        'NAME':'bms',           # 要连接的数据库,连接前需要创建好

                                                        'USER':'root',        # 连接数据库的用户名

                                                        'PASSWORD':'',        # 连接数据库的密码

                                                        'HOST':'127.0.0.1',       # 连接主机,默认本级

                                                        'PORT':3306            #  端口 默认3306

                                               }

                                     }

                           

                            3.在项目名称下的__init__.py里面加上,而不是app的__init__.py里面

                                     import pymysql

                                     pymysql.install_as_MySQLdb()

                            上面这两步2 3是为了在本机生成一个表,如果不进行上面这两步,那么就在项目中生成mysql表

                           

                            4.还要确保配置文件settings中的INSTALLED_APPS中写入了app的名称

                           

                            5.最后通过两条数据库迁移命令即可在指定的数据库中创建表 :

                                     python manage.py makemigrations

                                     python manage.py migrate

                           

                            1 4 5必写,2 3是为了在本地生成表

                           

                   添加表记录

                            # 添加表记录

                            # 方式一

                            book_obj = Book(id=1, title='python红宝书', price=100, pub_date='2012-12-12', publish='人民出版社')

                            book_obj.save()

                            # 方式二,返回值是当前生成的记录的对象,可以操作对象取值,推荐

                            book_obj2 = Book.objects.create(title='php', price=100, pub_date='2013-12-12', publish='人民出版社')

                  

                   查询表记录

                            <1> all():                  查询所有结果

                                                        book_list = Book.objects.all()

                                                        print(book_list)  # 返回QuerySet数据类型,django独有的,有点像列表,可以进行for循环、索引、切片等

                                                        for i in book_list:

                                                                 print(i.title, i.price)

          

                            <2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象,条件可以加多个,用,分割

                                             # filter() 调用者是objects管理器,返回值是queryset对象,该对象可以使用first last方法

                                                        book_list = Book.objects.filter(price=100)

                                                       

                             

                            <3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,

                                                                                             如果符合筛选条件的对象超过一个或者没有都会抛出错误。

                                                        book_obj = Book.objects.get(title='php')

                             

                            <4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象,排除

                                                        调用者是objects管理器,返回值是queryset对象,该对象可以使用first last方法

                                                        book_obj = Book.objects.exclude(title='go')

                             

                            <5> order_by(*field):       对查询结果排序

                                                        调用者是queryset对象,返回值是queryset对象

                                                        ret = Book.objects.all().order_by('id')

                                                        按照id升序排列,加一个-就是'-id'就是降序排列

                             

                            <6> reverse():              对查询结果反向排序

                             

                            <8> count():                返回数据库中匹配查询(QuerySet)的对象数量。

                                                        ret = Book.objects.all().count()

                                                        调用者是queryset对象,返回值是int类型

                             

                            <9> first():                返回第一条记录              

                            <10> last():                返回最后一条记录

                                                        # first() last() 调用者是queryset对象,返回值是model对象

                                                        theFirst = Book.objects.all().first()

                                                        theLast = Book.objects.all().last()

                                      

                            <11> exists():              如果QuerySet包含数据,就返回True,否则返回False

                                                        ret = Book.objects.all().exists()  只要有就行

                                                        调用者是queryset对象,返回值是布尔值

                             

                            <12> values(*field):        返回一个ValueQuerySet  一个特殊的QuerySet,运行后得到的并不是一系列

                                                                                             model的实例化对象,而是一个可迭代的字典序列

                                                                                             调用者是queryset对象

                                                        ret = Book.objects.all().values('price')

                                                        取值是ret[0].get('price')

                                                       

                                                                

                            <13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

                                                                                             调用者是queryset对象

                                                        ret = Book.objects.all().values_list('price')

                             

                            <14> distinct():            从返回结果中剔除重复纪录,配合value或value_list使用

                                                        ret = Book.objects.all().values('price').distinct()

                                                                                             调用者是queryset对象,返回值看是value还是value_list

                  

                   基于双下划线的模糊查询

                            Book.objects.filter(price__in=[100,200,300])

                            Book.objects.filter(price__gt=100)  # 大于

                            Book.objects.filter(price__lt=100)  # 小于

                            Book.objects.filter(price__range=[100,200])

                            Book.objects.filter(title__contains="python")  # 有python就行,在哪不重要,区分大小写

                            Book.objects.filter(title__icontains="python")  # 有python就行,在哪不重要,不区分大小写

                            Book.objects.filter(title__startswith="py")  以py开头的

                            Book.objects.filter(pub_date__year=2012)

                  

                   删除表记录,通用于单表和多表

                            删除方法就是 delete()。它运行时立即删除对象,返回任何值是删除的记录数。可以一次删除多个对象

                            调用者是queryset对象,model对象也可以调用delete

                           

                   修改表记录,通用于单表和多表

                            Book.objects.filter(title__startswith="py").update(price=120),返回值是修改的记录数

                            调用者只能是queryset对象

                  

                   练习:

                            1 查询老男孩出版社出版过的价格大于200的书籍

                                     Book.objects.filter(publish='老男孩出版社', price__gt=200)

                            2 查询2017年8月出版的所有以py开头的书籍名称

                                     Book.objects.filter(title__startswith='py', pub_date__year=2017, pub_date__month=8).values('title')

                             

                            3 查询价格为50,100或者150的所有书籍名称及其出版社名称

                                     Book.objects.filter(price__in=[50,100,150]).values('title', 'publish')

                             

                            4 查询价格在100到200之间的所有书籍名称及其价格

                                     Book.objects.filter(price__range=[100,200]).values('title', 'price')

                             

                            5 查询所有人民出版社出版的书籍的价格(从高到低排序,去重)

                                     Book.objects.filter(publish='人民出版社').values('price').distinct().order_by('-price')

        

图书管理系统的作业    

         实现功能:book单表的增删改查,写在django_07

        

         多表操作django_08

                   一对多

                            一旦确定表关系是一对多,创建关联字段,关联字段必须在多的表中

                   多对多

                            一旦确定表关系是多对多,创建第三张关系表,三个字段,id和另外两张表的关联字段

                   一对一

                            其实就是把本来的一张表,其中几个字段拿出来单独写一张表,就变成一对一的关系了

                            在两张表的任意一张表中建立关联字段加上unique

                  

                   建关联字段是为了进行查询,加外键约束条件是为了保护数据安全,避免有关联的内容被删除导致其他数据查不到

                  

                   创建表

                   实例:用ORM生成关联的表模型

                            from django.db import models

                            class Author(models.Model):

                                     nid = models.AutoField(primary_key=True)

                                     name=models.CharField( max_length=32)

                                     age=models.IntegerField()

                                     # 与AuthorDetail建立一对一的关系

                                     authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)

                            class AuthorDetail(models.Model):

                                     nid = models.AutoField(primary_key=True)

                                     birthday=models.DateField()

                                     telephone=models.BigIntegerField()

                                     addr=models.CharField( max_length=64)

                            class Publish(models.Model):

                                     nid = models.AutoField(primary_key=True)

                                     name=models.CharField( max_length=32)

                                     city=models.CharField( max_length=32)

                                     email=models.EmailField()

                            class Book(models.Model):

                                     nid = models.AutoField(primary_key=True)

                                     title = models.CharField( max_length=32)

                                     publishDate=models.DateField()

                                     price=models.DecimalField(max_digits=5,decimal_places=2)

                                     # 与Publish建立一对多的关系,外键字段建立在多的一方,生成字段

                                     publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)

                                     # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表

                                     authors=models.ManyToManyField(to='Author',)          

                                              

                            注意:

                                     表的名字是自动生成的

                                     id字段是自动添加的

                                     对于外键字段,django会在字段名上添加_id来创建数据库表中的列名

                                     一对一和一对多一定要加上on_delete=models.CASCADE,只要是django2.0版本

                                     外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None

        

                   添加表记录

                            一对多:

                                     方式1:

                                        publish_obj=Publish.objects.get(nid=1)

                                        book_obj=Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=100,publish=publish_obj)

                                      

                                     方式2:

                                        book_obj=Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=100,publish_id=1)  

                                    

                                     book_obj.publish是与这本书关联的出版社对象

                                     book_obj.publish_id是与这本书关联的出版社的id

                           

                            多对多:

                                     # 当前生成的书籍对象

                                     book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)

                                     # 为书籍绑定的做作者对象

                                     yuan=Author.objects.filter(name="yuan").first() # 在Author表中主键为2的纪录

                                     egon=Author.objects.filter(name="alex").first() # 在Author表中主键为1的纪录

                                     # 绑定多对多关系,即向关系表book_authors中添加纪录

                                     book_obj.authors.add(yuan,egon)    #将某些特定的 model 对象添加到被关联对象集合中  book_obj.authors.add(*[])

                                                                                    可以直接放1,2

                                                                                    可以放*[1,2]

                                    

                                     多对多关系其它常用API:

                                               book_obj.authors.remove()      #将某个特定的对象从被关联对象集合中去除。book_obj.authors.remove(*[])

                                               book_obj.authors.clear()       #清空被关联对象集合

                                               book_obj.authors.set()         #先清空再设置 

                                    

                                     book.authors.all() 是于这本书关联的所有作者对象的集合 

                  

                   跨表查询:

                            1.基于对象的查询

                            2.基于双下划线的查询

                            3.聚合与分组查询

                            4.F查询与Q查询

        

                   基于对象的跨表查询,就是mysql里的子查询

                            关联属性在A表中,通过A找B就是正向查询,通过B找A就是反向查询

                           

                           

                            实例:

                                     一对多:正向查询按字段查,反向查询按表名查,表名小写_set

                                               # 查询麦田这本书出版社的名字,一对多的正向查询,按字段

                                               book_obj = Book.objects.filter(title='麦田').first()

                                               print(book_obj.publish.name)

                                               # 查询人民出版社出版的书籍名称,一对多的反向查询,按表名,小写表名_set

                                               publish = Publish.objects.filter(name='人民出版社').first()

                                               book_list = publish.book_set.all()

                                               print(book_list)

                                    

                                     多对多:正向查询按字段查,反向查询按表名查,表名小写_set

                                               # 查询麦田的所有作者名称,多对多的正向查询

                                               book_obj = Book.objects.filter(title='麦田').first()

                                               author_list = book_obj.authors.all()

                                               for author in author_list:

                                                        print(author.name)

                                               # 查询alex出版过的所有书籍名称,多对多的反向查询

                                               alex = Author.objects.filter(name='alex').first()

                                               book_list = alex.book_set.all()

                                               for book in book_list:

                                                        print(book.title)

                                    

                                     一对一:正向查询按字段,反向查询按表名

                                               # 查询alex的手机号,一对一的正向查询

                                               alex = Author.objects.filter(name='alex').first()

                                               print(alex.authorDetail.telephone)

                                               # 查询手机号为110的作者的名字跟年龄,一对一的反向查询

                                               ad = AuthorDetail.objects.filter(telephone=110).first()

                                               print(ad.author.name)

                                               print(ad.author.age)

                           

                           

                           

                           

                   基于双下划线的跨表查询,就是mysql里的join,相对用的较多

                            正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表

                           

                            实例:

                                     # 一对多

                                     # 一对多查询的正向查询:查询麦田这本书出版社的名字

                                     # ret = Book.objects.filter(title='麦田').values('publish__name')

                                     # print(ret)

                                     # 一对多的反向查询:查询麦田这本书出版社的名字

                                     # ret = Publish.objects.filter(book__title='麦田').values('name')

                                     # print(ret)

                                     # 多对多

                                     # 多对多的正向查询:查询麦田的所有作者名称

                                     # ret = Book.objects.filter(title='麦田').values('authors__name')

                                     # print(ret)

                                     # 多对多的反向查询:查询麦田的所有作者名称

                                     # ret = Author.objects.filter(book__title='麦田').values('name')

                                     # print(ret)

                                     # 一对一

                                     # 一对一的正向查询:查询alex的手机号

                                     # ret = Author.objects.filter(name='alex').values('authorDetail__telephone')

                                     # print(ret)

                                     # 一对一的反向查询:查询alex的手机号

                                     ret = AuthorDetail.objects.filter(author__name='alex').values('telephone')

                                     print(ret)

                                    

                                     # 进阶练习 连续跨表查询

                                     # 查询手机号以110开头的作者出版过的所有书籍名称以及书籍出版社的名称

                                     # 方式一:

                                     # ret = Book.objects.filter(authors__authordetail__telephone__startswith=110).values('title', 'publish__name')

                                     # print(ret)

                                     # 方式二:

                                     ret = Author.objects.filter(authorDetail__telephone__startswith=110).values('book__title', 'book__publish__name')

                                     print(ret)

        

                   聚合查询

                            # 聚合查询 aggregate返回值是一个字典,而不是queryset格式的数据,键的名称可以自定义

                            #                   可以放多个参数                                                               ,默认是price__avg

                            # 查询所有书籍的平均价格

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

                            ret = Book.objects.all().aggregate(Avg('price'))

                            print(ret)

                  

                   分组查询

                            单表分组查询

                                     单表模型.objects.values('group by的字段').annotate(聚合函数(‘统计字段))

                                     annotate函数的返回值是queryset数据类型

                                    

                                     # 查询每一个部门的名称以及员工的平均薪水

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

                                     ret = Emp.objects.values('dep').annotate(Avg('salary'))

                                     print(ret)

                                    

                                     Emp.objects.all()翻译成sql语句就是select * from Emp

                                    

                            多表/跨表分组查询

                                     每一个后的表模型.objects.values('主键').annotate(聚合函数(关联表__统计字段))

                                     每一个后的表模型.objects.annotate(聚合函数(关联表__统计字段)),不加values的话会默认有一个all()

                                     最好用主键分组,下面的例子有的不是用主键分组的,不太好

                                    

                                     # 查询每一个出版社名称及出版的书籍的个数

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

                                     ret = Publish.objects.values('name').annotate(c=Count('book__title'))

                                     print(ret)

                                     # 查询每一个作者的名字以及出版过的书籍的最高价格

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

                                     ret = Author.objects.values('name').annotate(m=Max('book__price'))

                                     print(ret)

                                     # 查询每一个书籍的名称以及对应的作者个数

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

                                     ret = Book.objects.values('title').annotate(Count('authors__name'))

                                     print(ret)

                                     # 统计每一本以‘红’开头的书籍的作者个数

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

                                     # ret = Book.objects.filter(title__startswith='红').values('pk').annotate(Count('authors__name'))

                                     # print(ret)

                                     # 统计不止一个作者的书籍

                                     ret = Book.objects.values('pk').annotate(c=Count('authors__name')).filter(c__gt=1).values('title', 'c')

                                     print(ret)

                  

                   F查询与Q查询

                            F查询:

                                # 查询评论数大于收藏数的书籍

                                from django.db.models import F

                                Book.objects.filter(commnetNum__lt=F('keepNum'))

                                     #将每一本书的价格提高30元:

                                     Book.objects.all().update(price=F("price")+30) 

                                     # Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

                                     # 查询评论数大于收藏数2倍的书籍

                                     Book.objects.filter(commnetNum__lt=F('keepNum')*2)

                           

                            Q查询:

                                     from django.db.models import Q

                                     Q对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象

                                     bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

                                     Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询

                                     bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

                                     查询函数可以混合使用Q 对象和关键字参数,但是,Q对象,它必须位于所有关键字参数的前面

                                     bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),

                              title__icontains="python")

                           

基于多表的图书管理在django_09

像服务器发送请求的途径:

         1.浏览器的地址栏,默认是get请求

         2.form表单:

                            get请求

                            post请求

         3.a标签,默认get请求

         1.2.3都是同步请求

         4.ajax:

                   特点:

                            1.异步请求

                            2.局部刷新

                   请求方式:

                            get请求

                            post请求

Ajax django_10

         AJAX(Asynchronous Javascript And XML)即异步Javascript和XML

         使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)

         特点:

                   1.异步请求

                   2.局部刷新

        

         同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;

         异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

        

         登录验证的时候用到了json

                   在html中

        var ret =JSON.parse(data);  // js的反序列化json字符串方法

                if (ret.user){

                    location.href = 'http://www.baidu.com'  // 跳转页面

                }else{

                    $('.error').html(ret.msg).css({'color':'red', 'margin-left':'10px'})

                }

        

         ContentType请求头

                   指定请求体的编码类型

                   1.application/x-www-form-urlencoded,只要是post类型,无论是原生form还是ajax的form都默认是这种类型

                   2.multipart/form-data,使用表单上传文件时,必须设置enctype=multipart/form-data

                   3.application/json 用来告诉服务端消息主体是序列化后的 JSON 字符串

        

         基于form表单上传文件

         基于ajax上传文件

         都在file_put里面

        

分页器 在django_11

         from django.core.paginator import Paginator

        

forms组件 在django_12

         如果所有的字段都校验成功的话,那么form.cleaned_data里面有所有的校验成功的键值对,是一个字典

         如果传进来的值有检验函数未定义的部分,那么没有影响,只要规定的部分正确就行

         如果传进来的值缺少校验函数定义的部分,那么就当做空值,那就是false,即可多不可少

         form.errors也是一个字典,里面是匹配错误的,键是匹配的键,值是错误信息

        

         form表单的name属性值一定要与forms组件字段名称保持一致才能进行校验

        

         forms组件的渲染标签功能

                  

         forms组件渲染错误信息<form action="" method="post" novalidate>

        

         forms组件参数设置

                   class UserForm(forms.Form):

                            name = forms.CharField(min_length=4, label='用户名', error_messages={'required': '该字段不能为空'},

                                                                              widget=widgets.TextInput(attrs={'class': 'form-control'}))

                            pwd = forms.CharField(min_length=4, label='密码',

                                                                             widget=widgets.PasswordInput(attrs={'class': 'form-control'}),  # 设置成密文

                                                                             error_messages={'required': '该字段不能为空'})

                            r_pwd = forms.CharField(min_length=4, label='确认密码', error_messages={'required': '该字段不能为空'},

                                                                                    widget=widgets.TextInput(attrs={'class': 'form-control'}))

                            email = forms.EmailField(label='邮箱', error_messages={'required': '该字段不能为空','invalid': '格式错误'},

                                                                                     widget=widgets.TextInput(attrs={'class': 'form-control'}))

                            tel = forms.CharField(label='手机号', error_messages={'required': '该字段不能为空'},

                                                                             widget=widgets.TextInput(attrs={'class': 'form-control'}))

                           

会话跟踪技术         django_13                 

         cookie

                   具体一个浏览器针对一个服务器存储键值对

                   一般默认有效时间是两周

                   Cookie大小上限为4KB;

                    一个服务器最多在客户端浏览器上保存20个Cookie;

                    一个浏览器最多保存300个Cookie;

                   response.set_cookie(key,value)  设置

                   request.COOKIE.get(key)                           读取

                    

                   path='/', 设置Cookie生效的路径,不设置的话任何路径都能拿到cookie,设置后只有这个路径可以

                  

                   删除cookie:

                            response.delete_cookie("cookie_key",path="/",domain=name)

                           

                            在浏览器内ctrl+shift+delete就能清除cookie

         session

                   流程:

                            1.浏览器向服务器发送第一次请求

                            2.服务器设置session,生成随机字符串,并将随机字符串与设置的session对应,并将随机字符串作为cookie返回给浏览器

                            3.浏览器携带cookie向服务器发送第二次请求,服务器根据cookie中的随机字符串去找到对应的session值

                            1.生成随机字符串作为session-key

                            2.设置cookie

                            3.在django_session表中创建一条记录,以session-key随机字符串为键,以数据的字典格式为值

                           

                           

                   语法:

                            1、设置Sessions值

                                                 request.session['session_name'] ="admin"

                            2、获取Sessions值

                                                 session_name = request.session["session_name"]

                            3、删除Sessions值

                                                 del request.session["session_name"]

                            4、flush()

                                     request.session.flush()

                                      删除当前的会话数据并删除会话的Cookie。

                                      这用于确保前面的会话数据不可以再次被用户的浏览器访问

                  

                   session的数据,然后之前有该浏览器的数据,那就是会更新,如果没有那就创建

                           

                   session的配置

                            Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。

                                    

                            配置 settings.py

           

                            SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

                              

                            SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)

                            SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)

                            SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)

                            SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)

                            SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)

                            SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)

                            SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)

                            SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

用户认证组件 django_14

         逻辑更严谨

         用户认证推荐用这套组件,功能是用session记录登录验证状态

         使用前提:要有一张用户表,是django自带的auth-user表

         创建超级用户:

         auth模块

                   from django.contrib import auth

                   auth模块三个常用方法:

                            authenticate()

                                     用户认证,一般需要username password两个关键字参数

                                     如果认证消息有效,会返回一个user对象

                            login()

                                     接收request 和 一个认证了的user对象两个参数

                                     返回一个request.user对象,给已通过认证的用户附上session id等信息

                            logout()

                                     注销用户

                                     接收一个request参数,无返回值

                                     调用该函数,当前请求的全部session信息会全部被清除

         user对象

                   属性:username password,password是用哈希算法保存到auth-user表中的

                   方法:

                            is_authenticated

                                     用于检查用户是否通过了认证,如果是真正的user对象,返回值为True

                                     request.user.is_authenticated

                                    

                                     from django.contrib.auth.decorators import login_required

                                     这是django设计好的一个装饰器,用于处理一种情况:

                                               用户登录后才能访问某些页面

                                               如果没有登录就访问该页面的话会跳转到登陆页面

                                               在登录页面中登录后再在动跳转到之前要访问的地址

                                     若用户没有登录,则会跳转到django默认的登录URL '/accounts/login/ '

                                     (这个值可以在settings文件中通过LOGIN_URL进行修改)。

                                     并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。

        

                            创建用户

                                      使用create_user这个辅助函数来创建用户

                                               from django.contrib.auth.models import User

                                               user = User.objects.create_user(username='',password='',email='')

                                    

                            check_password()

                                     用户要修改密码的时候,让用户先输入原来的密码,通过检查后返回True

                           

                            修改密码set_password()

                                     user = User.objects.get(username='')

                                     user.set_password(password='')

                                     user.save

        

         匿名用户对象

                   id永远为None

                   username永远为空字符串

                   get_username() 永远返回空字符串

                   is_staff 和 is_superuser永远为false

                   is_active 永远为false

                   groups和user_permissions永远为空

                   is_anonymous()返回True而不是False

                   is_authenticated() 返回False而不是True

                   set_password() check_password() save() 和delete() 引发NotImplementedError

                  

         总结

                   如果未登陆 request.user就是AnonymousUser

                   如果登陆了就是登陆对象

                   request.user是一个全局变量

中间件

         浏览器发请求给服务器,先到wsgiref,wsgiref处理成request发送到中间件,七个中间件依次处理process_request

         然后交给路由控制,分发到对应的视图函数处理,可能就要去与数据库和模板进行交互了,拿到处理结果交给中间件,交给process_response处理

         处理完了交给wsgiref进行数据封装,最后把封装好的数据交给浏览器,浏览器渲染显示在页面上

         介于request与response之间的一道处理过程,可以在全局上改变django的输入输出

        

         中间件的四个方法:

                   process_request,不能有返回值

                   process_view可以用来调用视图函数,process_request--->路由控制--->process_view--->视图函数

                            如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。

                   process_exception 如果视图函数出错,这个方法才会执行,也是像response一样倒着执行

                   process_response,必须有返回值

        

         应用案例

                   做IP访问频率限制

                   URL访问过滤

猜你喜欢

转载自www.cnblogs.com/Interstellar-cooper/p/9254181.html