第六章Django

web应用程序

server端建立socket,不断地accept,当收到客户端连接信号之后,服务端向客户端发送数据,将html网页打开,read出来,并发送至客户端,这样客户端就可以浏览到网页的内容

http协议:

包头里面的数据用 一个“ ”来区分,最后使用两个“ ”来区分数据

GET协议把数据放在了包头里面,POST协议把数据放在包头的最后面

GET提交的数据以“?”区分,参数之间以“&”进行连接

相应格式:

协议版本 状态码 状态码的原因短语 相应首部字段 主体

web框架 yuan功能总结

main.py: 启动文件,封装了socket

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

2 views.py 视图函数,固定有一个形式参数:environ -----视图函数,

3 templates文件夹: html文件 -----模板

4 models: 在项目启动前,在数据库中创建表结构 ----- 与数据库相关



Django的安装与启动
创建应用:python manage.py startapp blog

urlpatterns = [
re_path(r'^articles/2003/$', views.special_case_2003),
re_path(r'^articles/([0-9]{4})/$', views.year_archive),
re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

有名分组:在组前面加上?P<组名> 即可,在传参时的形参必须是“组名”,否则会出错
 


命名空间:namespace
app01.urls:
需要加上
app_name = "app01"
urlpatterns=[
re_path(r'^index/',views.index,name="index"),
]

同理在ap02.urls加上相同的配置

views.py:
def index(request):
return HttpResponse(reverse("app01:index"))
需要加上反向解析


注册自定义转换器
先建一个类
class FourDigitYearConverter:
regex = '[0-9]{2}' #正则表达式的公式

def to_python(self,value):
return int(value)

def to_url(self,value):
return '%04d' % value

在项目中注册转换器
# 注册定义的url转换器
register_converter(FourDigitYearConverter,'mm') #FourDigitYearConverter : 为以上类名

之后在urls里可以直接path使用
path('articles/<mm:month>/',views.month_archive)


模板语法 只有两个
1.{{}}
可以在
return render(request,'index.html',locals()) 这样就把该函数里的全部全局变量都传过去了
同时在index.html可以通过 . 来过去数据 如一个数组l=【‘123’,‘456’,‘789’】 ,在html可以通过l.2 获取到数据456

2{%%}
{%if%}

{%endif%}

自定义标签与过滤器
1.在settings的INSTALLED_APPS加上当前app的名称,不然django无法找到自定义的simple_tag.
2.在app文件夹里面添加templatetags模块(模块名只能是templatetags)
3.在templatetags里面创建任意py文件
4.在该py文件里面引入
from django import template
register = template.Library()  # 固定名字
@register.filter          #加上装饰器,这个为模板过滤器
def filter_multi(x,y):
return x*y

@register.simple_tag #标签过滤器
def filter_tag(x,y):
return x*y
5.在html文件里面读取该过滤器
{%load py的文件名%}
6.使用
{{ 2 | filter_multi:5 }}

{% filter_tag 5 6 %}

继承:extends
在一个base.html 里面把模板写好
在另一个html里面引入base.html
{% extends "base.html" %}
这时候可以在下面继续添加block里面的内容
{{% block title %}
<title>第一个</title>
{% endblock title%}

模型层ORM
ORM 对象-关系-映射
通过编写ORM层,控制pysql转换成db语句,再去控制db数据库。py文件里面通过创建一个类


生成表模型
1.创建模型
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)
     state=models.BooleanField()
     pub_date=models.DateField()
     price=models.DecimalField(max_digits=8,decimal_places=2)
     publish=models.CharField(max_length=32)

创建一个app,然后在app项目文件下的models下创建类

2.配置链接数据库settings

在项目文件下的settings文件设置下,设置数据库信息

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.mysql',
        'NAME':'bms',                #创建数据库名字
        'USER':'root',         #链接数据库用户名
        'PASSWORD':'',         #链接数据库密码
        "HOST":'127.0.0.1',      #目标数据库地址
        'PORT':3306           #目标数据库端口
    }
}

  

3.确认信息

①在项目app文件下的__init__插入代码:
import pymysql

pymysql.install_as_MySQLdb()


②确保配置文件中的INSTALLED_APPS中写入我们创建的app名称

如在installed_apps 下添加app文件名


最后,可以进行数据迁移
python manage.py makemigrations
python manage.py migrate

  


数据库的建立create:
方式一:
book_obj = Book.objects.create(title='第一个数据库',state=True,price=500,pub_date="2012-12-12",publish='人民出版社')    #里面的数据格式需要与建立时的数据格式一致

方式二:
book_obj = Book(title='方式二',publish='机械出版社',state=True,pub_date="2010-12-11",price=10.12)
book_obj.save()                    #需要多一个save
 
查询表:
Django 自己生成的一个数据对象:QuerySet: [obj1,obj2,obj3....]
可以通过语句Book.object ---> 生成QuerySet数据
Book.object.all() 可以读取所有的数据

values方法: 返回和调用都是QuerySet
book_obj = Book.objects.values('price')
相当于
list = []
for obj in QuerySet:
  list.append{'price':obj['price']}
  .... #如果在values后面加值,就继续append

values_list方法:  
返回和调用都是QuerySet
book_obj = Book.objects.values_list('price')


distinct:去重 从返回结果中剔除重复纪录


表的查询

一对多的查询:
A---B
如果关联表在A表中:
A----->B :正向查询
反过来通过B去查A 则是反向查询,主要看关联表在哪张表里面
正向查询:看字段
反向查询:看表名:表名小写__set.all()
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建立一对一的关系, on_delete must add after Django 2.0 when use foreign Key
    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',)

  



聚合与分组查询
关键字:
annotate

总结 跨表的分组查询的模型:
# 每一个后表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段))
 

AJAX
特点:
1.使用JavaScript向服务器发送异步请求
2.局部刷新

$(".Ajax").click(function () {
$.ajax({
url:"/test_ajax/", //请求地址
type:"get", //请求的类型poet或者是get
success:function (data) {
$(".haha").html(data)
console.log(data)
}
})
})


数据之间的传输 通过使用json序列化
在py里面使用json.dump序列化
在Ajax里面使用JSON.parse 反序列化进行解析


利用Form表单进行文件上传

def file_put(request):
    if request.method=="POST":
        print('123')
        print(request.POST)
        print(request.FILES)

        file_obj = request.FILES.get("tou")

        with open(file_obj.name,'wb') as f:
            for i in file_obj:
                f.write(i)

        return HttpResponse('OK')

    return render(request, "file_put.html")
批量导入数据库的数据:
'''
    批量导入数据:

    Booklist=[]
    for i in range(100):
        book = Book(user="book_%s"%i,pwd=i*i)
        Booklist.append(book)
    Book.objects.bulk_create(Booklist)
    '''

分页器:

book_list = Book.objects.all()

    paginator = Paginator(book_list,10)

    print("count:", paginator.count)  # 数据总数
    print("num_pages", paginator.num_pages)  # 总页数
    print("page_range", paginator.page_range)  # 页码的列表

    page1=paginator.page(4)     #第4页的page对象数据
    for i in page1:             #遍历
        print(i)

    print(page1.object_list)    #直接拿出该page的所有对象

  
  #捕捉EmptyPage错误信息时做的处理
  try:
  current_page = int(request.GET.get("page",1))
  page1 = paginator.page(current_page)
  except EmptyPage as e:
  page1 = paginator.page(1)
 
 print(page2.has_next())            #是否有下一页
    print(page2.next_page_number())    #下一页的页码
    print(page2.has_previous())        #是否有上一页
    print(page2.previous_page_number()) #上一页的页码

form组件

form.is_valid()   #:返回布尔值
form.cleaned_data #:{"name":"yuan","email":"123@qq.com"} 返回匹配成功的字典
form.errors      #返回对应类字段的错误信息 :{"name":[".........."]}

from django.forms import widgets
class UserForm(forms.Form):                              #用于认证用
    name = forms.CharField(max_length=32,label="用户名", widget=widgets.TextInput(attrs={"class":"form-control"}),error_messages={“required”:“该字段不能为空”})   #attr即为修改样式,error_message修改默认的错误信息,必须为required这个键名
    pwd = forms.CharField(min_length=4)
    r_pwd = forms.CharField(min_length=4)
    email = forms.CharField()
    tel = forms.CharField(min_length=4,max_length=32)


def form_test(request):
    if request.method == 'POST':
        form = UserForm(request.POST)
        if form.is_valid():             #校验是否验证通过,同时会把错误、正确的信息放在两个字典里面
            print(form.cleaned_data)
        else:
            print(form.cleaned_data)
            print(form.errors)  # ErrorDict : {"校验错误的字段":["错误信息",]}
            print(form.errors.get("name"))  # ErrorList ["错误信息",]
        return HttpResponse("OK")
        form = UserForm()
        return render(request, "form_test.html", locals())

    form = UserForm()

    return render(request,"form_test.html")

在html里面想打印错误信息,可以{{form.name.errors}}  这样可以获取name里的错误信息

利用form表单组件 进行文件上传,使用FormData

$(".login_btn").click(function () {
        var form_data = new FormData();         //首先实例化一个FormData
        form_data.append("user",$("#id_user").val())    //再往里面添加数据
        form_data.append("pwd",$("#id_pwd").val())
        form_data.append("r_pwd",$("#id_r_pwd").val())
        form_data.append("email",$("#id_email").val())
        form_data.append("img",($("#avater")[0].files[0]))     //该为文件,主要是传它才使用FormData,不然不用这么麻烦
        form_data.append("csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val())

        $.ajax({
            url:"",
            type:"post",
            contentType:false,     //必须设置这两个值
            processData:false,
            data:form_data,         //最后把这个对象传给data
            success:function (data) {
                console.log(data)
            }
        })
    })

局部钩子

在规则里面class 添加一个方法"clean_%s"name

 def clean_tel(self):
        val = self.cleaned_data.get('tel')

        if len(val) == 11:
            return val
        else:
            raise ValidationError("手机号格式错误")

form.is_valid--》self.errors-->self.full_clean--》self._clean_fields()
依次校验每个字段,之后再走钩子去判断里面有没有clean_%s 用户自定义的方法

if hasattr(self, 'clean_%s' % name):
    value = getattr(self, 'clean_%s' % name)()
    self.cleaned_data[name] = value

全局钩子

    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        r_pwd = self.cleaned_data.get('r_pwd')

        if pwd and r_pwd:
            if pwd == r_pwd:
                return self.cleaned_data
            else:
                raise ValidationError('两次密码不一致!')
        else:
            return self.cleaned_data

视图函数 form_test.html

<div class="container">
    <form action="" method="post">
        {% csrf_token %}
        <div class="row">
            <div>
                <p>
                {{ form.name.label }}{{ form.name }}<span>{{ form.name.errors }}</span><span class="has-error pull-right">{{ errors.0 }}</span>  #errors类 自己写
                </p>
            </div>
            <div>
                <p>
                {{ form.pwd.label }}{{ form.pwd }}<span>{{ form.pwd.errors }}</span>
                </p>
            </div>
            <div>
                <p>
                {{ form.r_pwd.label }}{{ form.r_pwd }}<span>{{ form.r_pwd.errors }}</span><span class="pull-right error">{{ errors.0 }}</span>
                </p>
            </div>
            <div>
               <p>
                {{ form.email.label }}{{ form.email }}<span>{{ form.email.errors }}</span>
                </p>
            </div>
            <div>
                <p>
                {{ form.tel.label }}{{ form.tel }}<span>{{ form.tel.errors }}</span>
                </p>
            </div>
            <input type="submit" value="提交">

cookie:具体一个浏览器针对一个服务器存储key-value({})

获取cookie:

cookie 信息储存在request.COOKIE

原文地址:https://www.cnblogs.com/tyh-tesla/p/9411086.html