Django:回顾

web应用

本质是基于socket实现的应用程序

浏览器-----------服务器

http协议

# 特点
1
基于TCP协议 2 基于请求响应 3 短连接 4 无状态保存(引入了cookie,session技术) 请求协议 浏览器--------------->服务器 <-------------- 响应协议

一、请求协议

    '''
    请求首行      GET   path?get数据   HTTP/1.1
    请求头         
    userAgent: win Chorome/IPhone 
    contentType:json   application/x-www-form-urlencoded
    空行
    请求体(post才有请求体)
    a=1&b=2
    {"a":1,"b":2}
    '''

 

1、给服务器发送请求几种方式?

  1 地址栏:     get请求
  2 form表单:   get   post请求  (无法发送json数据)
  3 a标签连接请求:    get请求
  4 Ajax请求:   get(查)  post(提交数据添加记录)  put(更新)  delete(删除) ......
        
        $.ajax({
             url:"/index/",
             type:"post",
             data:{
                a:1,
                b:2
             },  # 默认urlencoded编码
             success:function(res){
             
             
             }
        
        })

 

2、如何给服务器发送json数据?

  get请求发送的是urlencode数据类型。

  给服务器发送json数据,只有ajax才能发送,ajax发post请求时默认是urlencode数据,发送json数据需要指定contentType类型,示例如下:

<script>
    $.ajax({
     url:"/index/",
     type:"post",
     contentType:"json"
     data:JSON.stringfy({
        a:1,
        b:2
     }), 
     success:function(res){
         
     
     }

    })
</script>

 

注意:Django解析不了json数据,只能利用 request.body 解析,也就是发送的json数据在request.body中

urlencode 数据  =====>>  request.POST

json 数据       =====>>  request.body

二、响应协议

'''
响应首行    HTTP/1.1  200  OK
响应头
contentType:"json"  需要指定类型
...
空行
响应体
'''    

 

 响应状态码:

1开头: 请求中
200:    请求成功
3开头: 重定向
4:        文件路径找不到,前端错误
5:        服务器错误,后端错误

Django框架

 一、MVC 与 MTV

1、MVC

              

2、MTV

  python是基于 MTV+路由分发的

M: model.py
T: Template:存放模板文件
V: 视图 逻辑

二、URL路由分发

1、有名分组

2、无名分组

3、反向解析

  起别名

    url(r'^role/add/$', views.role, name='role_add'),
    url(r'^role/edit/(\d+)/$', views.role, name='role_edit'),

   视图:
        
        path=reverse("role_add")  # "role/add/"
        path=reverse("role_edit",args=(1,2))  # "role/edit/1/"
   
   
   模板:
       {% url 'role_add' %}
       {% url 'role_edit' 2 %} 

 

4、名称空间

命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

       上面反向解析中,由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回。我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。如下示例:

项目下urls.py文件:

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

app01下的urls.py: 

urlpatterns = [
        url(r'^index/', index, name="index"),
    ]

app02下的urls.py:

urlpatterns = [
        url(r'^index/', index, name="index"),
    ]

app01下的views.py:

    from django.core.urlresolvers import reverse
    def index(request):
        return  HttpResponse(reverse("app01:index"))

app02下的views.py: 

    from django.core.urlresolvers import reverse
    def index(request):
        return  HttpResponse(reverse("app02:index"))

三、视图函数

request对象:存储这次请求所有请求信息:
       属性:
         HttpRequest.GET
         HttpRequest.POST
                    ---- urlencoded编码
                    ---- 注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
                                request.POST.getlist("hobby")                    
         HttpRequest.body 一个字节串,代表请求报文的主体。
         HttpRequest.path   #存放当前的路径
         ttpRequest.method  #存放请求的方式
         HttpRequest.META   请求头
         HttpRequest.FILES  #上传文件的时候,存放在FILES
         HttpRequest.COOKIES
         HttpRequest.session    session中间件 源码
         HttpRequest.user       认证中间件 源码(用auth认证的时候存放) 如果有登陆的用户,那么表示的就是这个用户对象。如果没有登陆的用户,那么默认是AnonymousUser匿名用户
         
       方法:     
          HttpRequest.get_full_path()    
          HttpRequest.is_ajax()             
     
HttpResponse对象:
        obj=HttpResponse("hello")
        obj=render(request,"index.html")
        obj=redircet("/index/")
        
                    
FBV与CBV : ******源码流程

    views:
          from django.views import View
          class BookView(View):
                
                def get(self,request):
                        pass

                def post(self,request):
                        pass                                
    urls.py:
           url("books",BookView.as_view())        

四、模板层

含有模板语法的html文件成为模板文件
render方法渲染引擎
模板语法:
     
    {{}}:渲染变量
          ---- 深度查询 句点符. 注意:  .无参方法
          ---- 过滤器 date,safe,add,slice,
    {% %}:渲染标签            
         {%for i in [111,222,333]%}
               {%if i!= 222%}
                   <p>i</p>
               {%endif%}
         {%endfor%}    

    自定义标签和过滤器 
          1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.            
          2、 在app中创建templatetags模块(模块名只能是templatetags)
          3、 创建任意 .py 文件,如:my_tags.py
                    from django import template             
                    register = template.Library()   #register的名字是固定的,不可改变
                                                 
                    @register.filter
                    def filter_multi(v1,v2):
                        return  v1 * v2
                        
                    @register.simple_tag
                    def simple_tag_multi(v1,v2):
                        return  v1 * v2


           4、模板中使用:
                    {% load my_tags %}  

                    # num=12
                    {{ num|filter_multi:2 }} #24
                     
                    {{ num|filter_multi:"[22,333,4444]" }}



    继承 extend:
            创建base.html:
                构建钩子
                {%block css%}
                    
                {%endblock css%}
                
                {%block content%}
                    <p>123</p>
                {%endblock%}
                
                {%block js%}
                    
                {%endblock js%}
            子模板继承:
                 {%extends 'base.html' %}
                 
                 {%block content%}
                    <p>111</p>
                 {%endblock%}

ORM - 单表操作

 模型类与表之间的对应关系 

class  Book(model.Model):
     title=models.CharFiled(max_length=32)
     

    '''
    类-----------------表    #  Book------- app01_book
    属性变量-----------字段  #  title------ title
    属性对象-----------约束     #  models.CharFiled(max_length=32)
    类实例对象---------表记录 
    '''

一、model的元类信息(Meta)

class Book(models.Model):
         id=models.AutoField(primary_key=True)
         title=models.CharField(max_length=32)
         state=models.BooleanField()
         pub_date=models.DateField()
         price=models.DecimalField(max_digits=8,decimal_places=2)
         publish=models.CharField(max_length=32)
         
 
class Book(models.Model):
    title=models.CharField(max_length=32,verbose_name="书籍名称")


     def __str__(self):
        return self.title
     class Meta:
            app_label="APP01"
            db_table="app01book"
            unique_together=["title","price"]
            verbose_name="书籍"
            ordering=["price"]   

 

使用:

print(Book._meta.verbose_name)    # 取表的名称 书籍
                               #'书籍'

print(Book)                     #模型类
                             #<class 'app01.models.Book'>


print(Book._meta.model_name) # 取类名小写的字符串 #'book' print(Book._meta.app_label) # 取表的app项目名称, #'app01'

详细元类信息查看: https://www.cnblogs.com/flash55/p/6265405.html

二、更多参数

(1)null

如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
 
    blank
 
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
 
(2)default
 
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
 
(3)primary_key
 
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。
 
(4)unique
 
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
 
(5)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。

 三、数据库配置

 # settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'bms',           # 要连接的数据库,连接前需要创建好
        'USER':'root',        # 连接数据库的用户名
        'PASSWORD':'',        # 连接数据库的密码
        'HOST':'127.0.0.1',       # 连接主机,默认本级
        'PORT':3306            #  端口 默认3306
    },
    
    'app01': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'bms',           # 要连接的数据库,连接前需要创建好
        'USER':'root',        # 连接数据库的用户名
        'PASSWORD':'',        # 连接数据库的密码
        'HOST':'127.0.0.1',       # 连接主机,默认本级
        'PORT':3306            #  端口 默认3306
    },
    
}

针对每一个注册app下的models.py创建对应的表结构

python manage.py makemigrations
python manage.py migrate

四、添加记录

book_obj=Book.objects.create(title="python葵花宝典",state=True,price=100,publish="苹果出版社",pub_date="2012-12-12")

book_obj=Book(title="python葵花宝典",state=True,price=100,publish="苹果出版社",pub_date="2012-12-12")
book_obj.save()

五、查询表记录

简单查询

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

<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
  
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
							如果符合筛选条件的对象超过一个或者没有都会抛出错误。
  
<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
 
<5> order_by(*field):       对查询结果排序
  
<6> reverse():              对查询结果反向排序
  
<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。
  
<9> first():                返回第一条记录
  
<10> last():                返回最后一条记录
  
<11> exists():              如果QuerySet包含数据,就返回True,否则返回False
 
<12> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
							model的实例化对象,而是一个可迭代的字典序列
							
							
							Book.objects.filter(price__gt=100).values("title","price")
							'''
							queryset=[]
							for obj in Book.objects.filter(price__gt=100):
								queryset.append({
									"title":obj.title,
									"price":obj.price
								
								})
							
							'''
							
<13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
							
								Book.objects.filter(price__gt=100).values("title","price")
							'''
							queryset=[]
							for obj in Book.objects.filter(price__gt=100):
								queryset.append((
									obj.title,
									obj.price
								
								))
							
							'''
							
							
							
<14> distinct():            从返回结果中剔除重复纪录		   

基于双下划线的模糊查询

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")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)
Book.objects.filter(pub_date__year__gt=2012)

六、删除表记录

Book.objects.filter(price__in=[100,200,300]).delete()
Book.objects.get(pk=1).delete()

七、修改表记录

# 方式1
Book.objects.filter(title__startswith="py").update(price=120)
# 方式2
book=Book.objects.filter(title__startswith="py").first()
book.price=1000
book.save()

ORM - 多表操作

模型类

from django.db import models

# Create your models here.


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()
    '''
        create table app01_publish(
           nid   INT auto_increment primary key
           name  varchar(32)
           city  varchar(32)
           email varchar(32)
        
        )
    
    '''


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',)
    '''
        create table app01_book(
               nid   INT auto_increment primary key
               title  varchar(32)
               publishDate  date
               price decimal(5,2)
               publish_id  INT
               ForeignKey publish_id references Publish(nid)
        )
        
        
        create book_authors(
             id   INT auto_increment primary key
             book_id INT
             ForeignKey book_id references app01_book(nid)

             author_id INT
             ForeignKey author_id references app01_author(nid)                             
        )
    
    '''
View Code

 

1、添加记录

针对一对多:
       
   book_obj=Book.objects.create(title="python葵花宝典",price=100,publishDate="2012-12-12",publish_id=1)
   
   pub_obj=Publish.objects.get(pk=1)
   book_obj=Book.objects.create(title="python葵花宝典",price=100,publishDate="2012-12-12",publish=pub_obj)


针对多对多:
    
          book_authors
          
              id  book_id    author_id
              
               4    2           3
               5    1           4

         book=Book.objects.get(pk=1)
         book.authors.add(1,2,3)
         
         book=Book.objects.get(pk=2)
         book.authors.add(3)
         
         book=Book.objects.get(pk=1)
         book.authors.remove(2,3)
        
         book=Book.objects.get(pk=1)
         book.authors.clear()
        
         book=Book.objects.get(pk=1)
         book.authors.set([4,5]) # 列表不打散

2、补充中介模型

                    

# 中介模型方式:
        
        
        class Student(models.Model):
            name = models.CharField( max_length=32)
            courses=models.ManyToManyField("Courses",through="Score")
            
        class Course(models.Model):
            name = models.CharField( max_length=32)    
                                            
        class Score(models.Model):
             student=models.ForeignKey("Student")
             course=models.ForeignKey("Course")
             score=models.IntegerField()

 

3、跨表查询 

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)

    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",relate_name="xxx",on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author',)
    
####################   基于对象(子查询)

正向查询按字段,反向查询relate_name,如果没有设置,按表名小写_set

    book=Book.objects.get(pk=1)
    book.publish
    book.authors.all()
    
    
    pub=Publish.objects.get(pk=1)
    pub.xxx.all()
    
    
    author=Author.objects.get(pk=1)
    author.book_set.all()
    
    author.authordetail
    authordetail.author


####################   基于双下划线(join查询)

    id  title  pub_id
     1     A      1
     2     B      1
     
     
     Publish
     id   name
      1   人民
      2   北京

     innerjoin

        1     A      1   1   人民
        2     B      1   1   人民

     rightjoin
        1   人民      1     A      1
        1   人民      2     B      1
        2   北京      null  null   null
     
     
     
        book_authors
      
          id  book_id    author_id
          
           1    1           1
           2    2           1 
           2    3           1 
           3    3           2
  
正向查询安字段,反向查询按表名小写  

# 查询python出版社的名字
Book.objects.filter(title="python").values("publish__name")    
Publish.objects.filter(book__title="python").values("name")                    

# 查询alex出版过的书籍的名称

Author.objects.filter(name__startswith="a").values("book__title")
Book.objects.filter(authors__name__startswith="a")

 

 4、分组查询(基于双下划线join)

聚合
# 计算所有图书的平均价格
    Book.objects.all().aggregate(AVG("price"))
    Book.objects.all().aggregate(MAX("price"))


分组: id name age salary dep
1 alex 12 2000 销售部 2 egon 22 3000 人事部 3 wen 22 5000 人事部 sql:select dep,AVG(salary) from emp group by dep orm:Emp.objects.values("dep").annotate(avg=AVG("salary")) # [{"dep":"销售","avg":5000},{}]
跨表分组查询 book id title pub_id 1 python 1 2 linux 1 3 go 2 publish id name 1 沙河 2 北京 查询每一个出版社的名称以及出版书籍的个数 id title pub_id id name 1 python 1 1 沙河 2 linux 1 1 沙河 3 go 2 2 北京 Publish.objects.values(pk).annotate(c=Count("book")) # [{pk:1,c:2},{pk:2,c:1}] Publish.objects.all.annotate(c=Count("book")).values("c","name") # [publish_obj,publish_obj] # 查询每一个作者的名字以及出版书籍的最高价格 Author.objects.annotate(max_price=Max("book__price")).values("name","max_price") # 查询96年以后出生的每一个作者的名字以及出版书籍的最高价格 Author.objects.filter(birthday__year__gt=1996).annotate(max_price=Max("book__price")).values("name","max_price") # 查询不止一个作者的书籍名称以及关联的作者个数 Book.objects.all().annotate(c=Count("authors"))# [book1,book2,.....] Book.objects.all().annotate(c=Count("authors")).filter(c__gt=1).values("title","c") # 查询每一个销售的名字以及今天对应的成单量 userinfo id name 1 sanjiang 2 jinjin 3 bingbing customer id name deal_date consultant 1 A 2018-11-23 1 1 B 2018-11-22 1 1 C 2018-11-23 2 1 D 2018-11-18 1 1 E 2018-11-23 1 1 F 2018-11-23 1 1 Q 2018-11-23 1 customer id name deal_date consultant id name 1 A 2018-11-23 1 1 sanjiang 1 C 2018-11-23 2 2 jinjin 1 E 2018-11-23 3 3 bingbing 1 F 2018-11-23 3 3 bingbing 1 Q 2018-11-23 1 1 sanjiang Userinfo.objects.filter(depart_id=1).filter(customer__deal_date=now).annotate(c=Count("customers")).values("name","c")

 

5、F与Q

 Book.objects.filter(commnetNum__lt=F('keepNum'))
 Book.objects.filter(commnetNum__lt=F('keepNum')*2)               
 Book.objects.all().update(price=F("price")+30)             
 
 Book.objects.filter(Q(title__startswith="py")|Q(price__gt=100))
 
 q=Q()
 q.conector="or"
 q.children.append(("title__startswith","py"))
 q.children.append(("price__gt",100))

 

Django组件

一、文件上传

  文件上传中无论是form表单或ajax发送请求,后台的视图函数的处理都是一样的

form表单
<form action="/file_put/" method="post" enctype="multipart/form-data">
            姓名<input type="text" name="user">
            文件<input type="file" name="file_obj">
            <input type="submit">
        </form>

ajax形式

<div>
            姓名<input type="text" id="user">
            文件<input type="file" name="file_obj" id="file">
            <input type="button" class="filebtn" value="提交">
            <p class="msg"></p>
        </div>
        
        
        // 发送文件
          $(".filebtn").click(function () {


              var formdata=new FormData();
 formdata.append("file_obj",$("#file")[0].files[0]);
 formdata.append("user",$("#user").val());

              $.ajax({
                  url:"/file_put/",
                  type:"post",

// Ajax上传文件必备参数
                  processData: false ,    // 不处理数据
                  contentType: false,    // 不设置内容类型

                  data:formdata,
                  success:function (response) {
                      console.log(response);
                      if (response=="OK"){
                          $(".msg").html("提交成功!")
                      }
                  }
              })
              
          })
                        


视图: 
     def file_put(request):

            print(request.POST)
            print(request.FILES)
            file_obj=request.FILES.get("file_obj")
            # 文件对象有一个name属性,获取文件名称字符串
            print(file_obj.name)
            path=file_obj.name

            path=os.path.join(settings.BASE_DIR,"media","img",path)
            with open(path,"wb") as f:
                for line in file_obj:
                    f.write(line)


            return HttpResponse("OK")

二、cookie、 session、 auth

1、cookie

cookie概念:
       针对每一个服务器,保存在客户端(浏览器)的一个key-value结构数据,可以理解成一个字典结构
       
cookie语法:
       obj=HttpResponse()
       obj=render()
       obj=redirect()
       # 设置cookie
       obj.set_cookie("key","value",3600*24)
       # 获取cookie
       request.COOKIES
       # 删除cookie
       obj.delete_cookie("key","value")


应用:
    登录认证
    验证码
    保存上次访问时间
    浏览过的商品

2、session

  中间过程很重要

# 设置session

request.session["key"]="value"
   '''
    if request.cookie("session_id"):
        1 获取随机字符串session_id:21342saidf92349
        2 去django-seeson表中过滤session-key=21342saidf92349的记录
            session-key         session-data
            21342saidf92349    {"key":"value"}
        3 更新:
    else:                            
   
   
        1 生成一个随机字符串:21342saidf92349
        2 去django-seeson表中创建一条记录
            session-key         session-data
            21342saidf92349    {"key":"value"}
        3 响应setcookie("session_id",21342saidf92349)
   '''
# 获取session
   request.seesion["key"]
   '''
     1 获取cookie中key为session_id的对应值:21342saidf92349
     2 去django-session表中过滤session-key=21342saidf92349的记录对象obj
     3 obj.session-data.get("key"")
   
   '''

Django表的介绍:

                   

session_key:存放的是随机字符串,这个是要给浏览器的钥匙,不是给用户的

session_data:要存放的是键值对数据,可以理解为字典,但是是加密的

该表中

  一条记录代表的是一个浏览器的,两条记录表示两个浏览器访问,(不同电脑的同种浏览器访问算是两条记录)

  同一个浏览器访问,如果产生好几个 session,会现在 session_data 中键值对中找 key,如果 key 存在那么就替换 values,如果不存在 key 就会添加键值对,{username:yuan,keep_str:123456}

 

 

 

 

 

 

 

 

 

 

 
posted @ 2018-11-23 08:54  葡萄想柠檬  Views(112)  Comments(0)    收藏  举报
目录代码