django

  • 2020 年 11 月 25 日
  • 笔记

1 AJAX

1 ajax基本语法

test.html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
  {#一定要记得导包,然后再settings.py中配置static文件夹路径#}
   <script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
   <script src="/static/jquery-3.3.1/jquery-3.3.1.js"></script>
   <title>Title</title>
</head>
<body>
<input type="text" id="d1">
+
<input type="text" id="d2">
=
<input type="text" id="d3">

<p>
   <button id="btn">点我</button>
</p>


<script>
   // 先给id="btn"的按钮绑定一个点击事件
   $('#btn').click(function () {
       $.ajax({
           // 1.指定朝那个后端发送ajax请求
           url: '/index/', //不写就是朝当前地址提交

           // 2.请求方式
           type: 'post', //不写默认就是get

           // 3.数据
           data: {
               'i1': $('#d1').val(),  //$('#d1'):找到元素id为d1的元素,val()拿到元素的value值
               'i2': $('#d2').val()
          },

           // 4.回调函数:当后端给你返回结果的时候会自动触发,args接受后端的返回结果,就算返回的是个页面也是回调函数接收
           success: function (args) {
               // 通过dom操作动态渲染到第三个input框中
               $('#d3').val(args) //如果val()里带参数会把参数渲染到页面
          }
      })
  })
</script>


</body>

{#如果后端用的是HttpResponse返回的数据,回调函数不会自动帮你反序列化,结果还是字符串#}
{#但是,如果后端直接用的是JsonResponse返回的数据,回调函数会自动帮你反序列化将字符串变为对象#}
   
   
{#HttpResponse解决方法#}
{#   1.自己在前端利用JSON.parse()#}
{#   2.在ajax里配置一个参数ContentType: true#}

</html>

view.py

def ab_ajax(request):
   if request.method == 'POST':
       i1 = request.POST.get('i1')
       i2 = request.POST.get('i2')
       res = int(i1) + int(i2)
  return HttpResponse(res)
   return render(request, 'test.html')

 

2 前后端传输数据的编码格式

# 1 我们主要研究post请求数据的编码格式
"""
get请求数据就是直接放在url后面的,如:
url?username=xpj&password=123
"""

# 2 前后端传输数据的三种格式
"""
1 urlencoded: form表单提交数据格式

2 multipart/formdata: 针对文件格式,封装到request.FILES里

3 json
"""

# 3 可以朝后端发送post请求的方式
"""
1 form表单
默认的数据编码格式是urlencoded
数据格式:username=xpj&password=123
django后端针对urlencoded编码格式的数据会自动帮你封装到request.POST中

如果你把编码格式改为formdata,那么针对普通的键值对还是解析到request.POST中,而针对文件会解析到request.FILFES中

form表单是没有办法传输json个是数据的

2 ajax请求
默认的数据编码格式是urlencoded
数据格式:username=xpj&password=123
django后端针对urlencoded编码格式的数据会自动帮你封装到request.POST中
"""

 

3 ajax发送json格式数据

'''
前后端传输数据的时候一定要确保编码格式跟数据格式是一致的

如果传输的是json格式的数据request.post里是找不到的

request.is_ajax(),判断当前请求是否是ajax请求,返回bool值

django针对json格式的数据不会做任何处理,需要自己处理

解决方法:
1.json_bytes = request.body
json_str = json_bytes.decode('utf-8')
json_dict = json.loads(json_str)

2.json_dict = json.loads(json_bytes)

'''

#1 ajax改变发送的编码格式
$.ajax({
   '''''
  cententType: 'application/json', //指定编码格式
  ''''''
})

 

4 ajax发送文件

'''
ajax发送文件需要借助js内置对象FormData
'''
<script>
       $('#d4').on('click', function (){
           
           // 1 需要先利用FormData内置对象生成一个对象
           let formdata_obj = new FormData()
           
           // 2 添加普通的键值对
           formdata_obj.append('username', $('#d1').val());
           formdata_obj.append('password', $('#d2').val());
           
           // 3 添加文件对象,$('#d3')是jquery对象, $('#d3')[0]转成原生js对象标签对象, $('#d3')[0].files[0]拿到用户传进来的文件对象
           formdata_obj.append('myfile', $('#d3')[0].files[0])
           
           // 4 将对象基于ajax发送给后端
           $.ajax({
               url: '',
               type: 'post',
               data: formdata_obj, //直接将对象放在data后面即可

               //ajax发送文件必须要指定的两个参数
               contentType: false, // 不需要使用任何编码,django后端能够自动识别formdata对象
               processData: false, // 告诉你的游览器不要对你的数据进行任何处理
               
               success: function (args){
                   alert(1)
              }
          })
      })
</script>

 

5 ajax结合sweetalert实现二次确认

<p>
   <button class="del" delete_id="{{ user_obj.pk }}"></button>
</p>

<script>
   $('.del').on('click', function (){
       alert($(this).attr('delete_id'))    //this拿到的是当前标签.attr拿到标签的属性
  })
</script>

 

6 批量插入数据

# bulk_create()

book_list = []
for i in range(100000):
   book_obj = models.Book.objects.all()
   book_list.append(book_list)
models.Book.objects.bulk_create(book_list)
return render(request, 'ab_pl.html', locals())

 

2 auth

1 auth常用方法

# 1 对比用户名和密码是否正确
user_obj = auth.authenticate(request, username=username, password=password) # 括号内必须同时传入request, 用户名和密码
print(user_obj) # 用户对象 jason
print(user_obj.username) # jason
print(user_obj.password) # 密文

# 2 保存用户状态
auth.login(request, user_obj) # 执行了该方法,你可以在任何地方通过request.user获取当前登录的对象

# 3 判断当前用户是否登录
request.user.is_authenticated()

# 4 获取当前登录用户
request.user

# 5 校验用户是否登录装饰器
from django.contrib.auth.decorators import login_required

# 局部配置,用户没有登录会跳转到login页面
@login_required(login_url='/login/')

# 全局配置,可以在settings.py里配置LOGIN_URL = '/login/'
@required_login()

# 局部>全局,全局的好处在于无需重复写代码但是只能跳转一个页面,局部的好处在于不同的试图函数在没有用户登录的情况下可以跳转到不同的页面

# 6 密码处理
# 比对原密码
request.user.check_password(old_password)

# 修改密码
request.user.set_password(new_password) # 仅仅是在修改对象的属性
request.user.save() # 这一步才是真正操作数据库

# 7 注销
auth.logout(request)

# 8 注册
# 直接创建但是密码不加密
User.objects.create(username=username, password=password)

# 创建普通用户密码能加密
User.objects.create_user(username=username, password=password)

# 创建超级用户
User.objects.create_superuser(username=username, email='[email protected]', password=password)

 

2 auth模块表拓展

class UserInfo(AbstractUser):
   """
  如果继承了AbstractUser
  那么在执行数据库迁移命令的时候auth_user表就不会再创建出来了
  UserInfo表中会出现auth_user所有的字段外加自己拓展的字段
  """
   phone = models.BigIntegerFeild()
   
   """
  前提:
  1. 必须在auth_user没有被创建之前继承
  2. 必须在settings.py里声明
  AUTH_USER_MODEL = 'app01.UserInfo'
  3. 继承的类不能出现同名字段
  """

 

3 orm

1 单表操作

测试脚本

models.py

class User(models.Model):
   name = models.CharField(max_length=32)
   age = models.IntegerField()
   register_time = models.DateTimeField(auto_now_add=True)

   def __str__(self):
       return self.name

test.py

# 去manage.py文件中复制前四行代码,粘贴进test.py文件中并写入两行代码,即可在单个py文件中进行测试

import os

def main():
   os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject3.settings')
   # 这两行是新加入的
   import django
   django.setup()

2 必知必会13条

# 1 create()
models.User.objects.create(name='kerwin', age=24)

# 2 delete()
models.User.objects.filter(pk=2).delete()
(1, {'app01.User': 1}) # 返回剩余个数

# 3 update()
models.User.objects.filter(pk=1).update(age=18)
1 # 修改成功返回1

# 4 filter()
models.User.objects.filter(pk=1)
<QuerySet [<User: xpj>]> # 拿到的是queryset,不存在返回空

# 5 fisrt()
models.User.objects.filter(pk=1).first()
<User: xpj> # 拿到对象

# 6 get()
models.User.objects.get(pk=1)
<User: xpj> # 拿到的是User对象,但是如果不存在的话会报错

# 7 values()
models.User.objects.values('name') # 字段查询
<QuerySet [{'name': 'xpj'}]> # 列表套字典的queryset

# 8 values_list()
models.User.objects.values_list('name', 'age')
<QuerySet [('xpj', 24)]> # 列表套元组的queryset

# 9 distinct()
models.User.objects.values('name', 'age').distinct()

# 10 order_by()
models.User.objects.order_by('age')
models.User.objects.order_by('-age') # 降序

# 11 count()
models.User.objects.filter(pk=1).count()

# 12 reverser() # 反转
# 13 exists() # 存在
# 14 exclude() #

3 双下划线查询

#1 年龄大于35岁
models.User.objects.filter(age__gt=35)

#2 年龄小于35岁
models.User.objects.filter(age__lt=35)

#3 年龄大于等于,小于等于35岁
models.User.objects.filter(age__gte=35)
models.User.objects.filter(age__lte=35)

#4 年龄是18,32,40
models.User.objects.filter(age__in=[18,32,40])

#5 年龄是18到40岁之间的
models.User.objects.filter(age__range=[18,40])

 

2 多表操作

1 多表准备

models.py


class Book(models.Model):
   title = models.CharField(max_length=32)
   price = models.DecimalField(max_digits=8, decimal_places=2)
   publish_date = models.DateTimeField(auto_now_add=True)

   publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
   authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
   name = models.CharField(max_length=32)
   addr = models.CharField(max_length=64)
   email = models.EmailField()


class Author(models.Model):
   name = models.CharField(max_length=32)
   age = models.IntegerField()
   author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
   phone = models.BigIntegerField()
   addr = models.CharField(max_length=64)

2 一对多

# 1 增
# 直接写id
models.Book.objects.create(title='三国演义', price=123.45, publish_id=1)

# 虚拟字段对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦', price=66.21, publish_id=publish_obj.pk)

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

# 3 改
models.User.objects.filter(pk=1).update(publish_id=3)

3 多对多

# 多对多关系表的增删改查其实就是第三张关系表的增删改查
# 1 通过book表给author表添加作者,通过第三张表
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors # 相当于进入authorsDetail表
book_obj.authors.add(1)
book_obj.authors.add(2,3)
author_obj = models.Author.objects.filter(pk=2).first()
book_obj.author.add(author_obj.pk)


# 2 删
remove(2)

# 3 改
括号内必须传一个可迭代对象
set([1,2])

# 4 清空
clear()

4 正反向概念

# 正向
看外键字段在哪个表,外键字段所在表查外键字段的表就是正向
book--->外键字段在book表--->publish(正向)

# 反向
反之

"""
正向查询按字段
反向查询按表名小写
"""

5 多表的跨表查询

子查询(基于对象的跨表查询)
# 1 查询书籍主键为1的出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
publish_obj = book_obj.publish
publish_obj.name

# 2 查询书籍主键为2的作者
book_obj = models.Book.objects.filter(pk=2).first()
author_obj = book_obj.authors.all() # 结果可能有多个加all

# 3 查询作者为jason的电话号码
author_obj = models.Author.objects.filter(name='jason').first()
author_detail_obj = authos_obj.author_detail

# 4 查询出版社是东方出版社出版的书(反向)
publish_obj = models.Publish.objects.filterr(name='东方出版社').first()
book_obj = publish_obj.book_set.all() # 表名小写_set一般是对对象

# 5 查询作者是jason写过的书(反向)
author_obj = models.Author.objects.filter(name='jason').first()
book_obj = author_obj.book_set.all()

# 6 查询手机号是110的作者姓名
author_detail_obj = models.AuthorDetil.objects.filter(phone=110).first()
author_obj = author_detail_obj.author_set
连表查询(基于双下划线的跨表查询)
# 1 查询jason的手机号和作者姓名
# 正向
phone = models.Author.objects.filter(name='jason').values('author_detail__phone','name')
# 反向
models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__name')


# 2 查询书籍主键为1的出版社名称和书的名字
# 正向
models.Book.objects.filter(pk=1).values('title', 'publish__name')
# 反向
models.Publish.objects.filter(book__id=1).values('name', 'book__title')

# 3 查询书籍主键为1的作者姓名
# 正向
models.Book.objects.filter(pk=1).values('authors__name') # 正向查询按字段
# 反向
models.author.objects.filter(book__id=1).values('name')

# 4 查询书籍主键1的作者的手机号
models.Book.objects.filter(pk=1).values('authors__author_detail__phone')

 

3 聚合查询

aggregate()
# 一般是配合分组一起使用
from app01 import models
from django.db.models import Max, Min, Count, Avg, Sum

models.Book.objects.aggregate(Max('price'), Min('price'), Avg('price'), Count('pk'), Sum('price'))

 

4 分组查询

  • annotate() 内写聚合函数

  • 重点: 只要你写的orm得出的结果是一个queryset对象,那么你就可以无限的.queryset的方法,比如.values, .filter等等

  • values表示group by的字段

  • values表示取某几个字段

  • filter表示where

  • filter表示having

# 1 统计每一本书的作者个数
models.Book.objects.annotate(author_num=Count('authors')).values('author_num') # models后面.什么就按什么分组,author_num是作者个数的别名,一个变量,本来跨表是要authors__id的,但是orm很智能,可以省略__id
models.Book.objects.annotate(author_num=Count('authors__id')).values('author_num')


# 2 统计每个出版社卖的最便宜的书的价格
models.Publish.objects.annotate(min_book_pirce=Min('book__price')).values('min_book_price')
print(res)

# 3 统计不止一个作者的图书
models.Book.objects.annotate(author_num=Count('authors__id')).filter(author_num__gt=1)
# <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>

models.Book.objects.annotate(author_num=Count('authors__id')).filter(author_num__gt=1).values('title', 'author_num')

# 4 查询每个作者书的总价格
models.Author.objects.annotate(total_price=Sum('book__price')).values('total_price')

重点: 只要你写的orm得出的结果是一个queryset对象,那么你就可以无限的.queryset的方法,比如.values, .filter等等

 

5 F查询

# 1 查询卖出数大于库存数的书籍
"""
F能够帮助你直接获取数据表中某个字段在表中对应的数据
"""
from django.db.models import F
models.Book.objects.filter(maichu__gt=F('kucun'))


# 2 将所有书的价格提升50块
models.Book.objects.update(price=F('price')+50)

# 3 将所有书的名称后面加上爆款2个字
"""
在操作字符串的时候F不能直接做到字符串的拼接
"""
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title').value('爆款')))

 

6 Q查询

# 1 查询卖出数大于100或者价格小于600的书籍
models.Book.objects.filter(maichu__gt=100, price__lt=600)
# <QuerySet []> 因为filter内部多个参数是and的关系

 

7 django中开启事务

"""
原子性
一致性
隔离性
持久性

回滚 roolback

确认
commit
"""
from django.db import transaction
try:
   with transaction.atomic():
       # with中写的所有orm都属于一个事务
except Exception as e:
   print(e)

 

8 ORM中常用字段和参数

//www.cnblogs.com/Dominic-Ji/p/9203990.html

9 数据库查询优化

# 1 only与defer