Django

Django

Django项目是一个python定制框架,采用了MVT的框架模式,即模型M,视图V和模板T

本质还是MVC(Models、Views、Controller)

Django项目的创建

  1. 命令行式

    #1.cmd
    >>django-admin startproject project_name
    
    #2.切换到项目文件夹下
    #>>python2 manage.py runserver 127.0.0.1:8000(可指定ip地址)
    >>python3 manage.py runserver
    
    #3.创建应用(django支持多应用开发)
    >>python3 manage.py startapp app_name
    '''
    注意:
    1.不会自动创建templates文件夹
    2.配置文件中不会自动书写templates文件路径
    '''
    

    Django中的app

    Django是一个以开发app为主要功能的web框架

    一个app是一套Django功能的集合,通常包括模型和视图,按python的包结构的方式存在

    Django为app提供了前期的环境配置

    *创建好的app需要在Django配置文件中注册方可生效

Django框架的分层

Django框架就是为了开发app,而app的工作过程本质就是根据不同的请求返回不同的数据

Django框架将工作过程分为四层:

  1. 路由层 urls.py 根据不同的地址执行不同的视图函数u
  2. 视图层 views.py 定义处理业务逻辑的视图函数
  3. 模型层 models.py 和数据库交互
  4. 模板层 templates.py 存储返回给浏览器的html文件

请求生命周期

Django文件功能

Django项目名(根目录)

项目同名的文件夹

settings.py 暴露给用户可以配置的配置文件

urls.py 路由和视图函数的对应关系

manage.py

Django的入口文件

应用名文件夹

migrations文件夹 所有数据库的相关操作记录

admin.py Django-admin后台管理

apps.py 注册app使用

models.py 存放数据库所有有关的模型类

tests.py 测试文件

views.py 处理业务逻辑的视图函数

基本操作

#HttpRespnonse	返回字符串
def httpresp(request):
    return HttpRespnonse('这是一个字符串')


#render		返回html文件,可以给html页面传值
def ren(request):
    user_dic = {'username':'slk'}
    return render(request,'login.html',{'user_info':user_dic})


#redirect  重定向,可以是本网站的路径后缀,也可以是全路径
def home(request):
    return redirect('https://baidu,com')
	retur redirect('/add_user/')  #如果是本网站路径后缀要加斜杠

注意事项

前期配置相关

  • 静态文件配置

    1. 默认情况下,所有的html文件都是放在templates文件夹内

    2. 静态文件是指网站所用到的提前写好的css、js、第三方的前端模块以及图片等静态资源

    3. 默认情况下,网站所用到的静态文件资源全部放在static文件夹(需要手动创建)下,static文件夹下可以在细分css文件夹、js文件夹、font文件夹、img文件夹、Bootstrap文件夹以及fontawesome文件夹等

    4. 路径配置

      STATIC_URL = '/static/'
      
      STATICFILES_DIRS = [
          os.path.join(BASE_DIR, 'static')
      ]
      
    5. 静态文件夹的动态绑定

      #在html的py文件中
      {% load static %}
      <link rel="stylesheet" href="{% static 'css文件相对路径' %}">
      <script src="{% static 'js文件相对路径' %}"></script>
      
  • 前期在向后端提交post请求出现403,需要在配置文件中注释一行内容

    # 中间件
    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
  • 连接数据库
    Django自带SQLite
    在右侧点击Database;第一次连接某个数据库时,需要下载驱动
    Django只会帮你建表,数据库需要手动创建,一个项目用一个数据库

    #配置文件
    DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.mysql',  # 指定数据库类型
        'NAME': 'day49',  # 指定库的名字
        'USER':'root',  # 注意 键必须是全大写
        'PASSWORD':'123qwe',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'CHARSET':'utf8'
        }
    }
    
    #更改连接模块
    #在项目名下的__init__.py 或 应用名下的__init__.py 中
    import pymysql
    pymysql.install_as_MySQLdb()
    
  • orm 对象关系映射 缺点:封装程度太高,效率偏低;一个项目对应一个数据库

  • 取消django自动浏览器加斜杠的功能:

    #settings
    APPEND_SLASH = False
    

数据库相关

  • 夺命13条

    1. # all()	查询所有	返回Queryset对象
      res = models.Table.objects.all()
      
    2. # filter()	筛选	相当于sql中的where关键字
      res = models.Table.objects.filter(pk=1,)
      
    3. # get()	筛选		获取到的是对象本身	条件不存在直接报错
      res = models.Table.objects.get(title='西游记',)
      
    4. # first()	取queryset中的第一个数据对象
      res = models.Books.objects.filter(title='西游记').first()
      
    5. # last()		取queryset中的最后一个数据对象
      res = models.Books.objects.filter(title='西游记').last()
      
    6. # count()  统计数据的个数   数字
      num = models.Books.objects.count()
      print(type(num))
      
    7. # values()  获取数据对象中指定的字段的值    返回queryset对象  列表套字典
      res = models.Books.objects.values('title','price')
      print(res)
      # <QuerySet [{'title': '三国演义', 'price': Decimal('222.66')}, {'title': '红楼梦', 'price': Decimal('888.99')}, {'title': '西游记', 'price': Decimal('444.66')}, {'title': '西游记', 'price': Decimal('666.22')}]>
      
    8. # values_list()  获取数据对象中指定的字段的值   返回queryset对象  列表套元祖
      res = models.Books.objects.values_list('title','price')
      print(res)
      #<QuerySet [('三国演义', Decimal('222.66')), ('红楼梦', Decimal('888.99')), ('西游记', Decimal('444.66')), ('西游记', Decimal('666.22'))]>
      
    9. # order_by()      按照指定的字段排序
      res = models.Books.objects.order_by('price')  # 默认是升序
      res1 = models.Books.objects.all().order_by('price')  # 默认是升序   两者等价 下面的方式 语义更明确
      # 降序  字段前面加负号
      res1 = models.Books.objects.all().order_by('-price')
      print(res1)
      
    10. # reverse()      颠倒顺序   前提是跌倒的对象必须有顺序(提前排序之后才能跌倒)
      res = models.Books.objects.all()
      res1 = models.Books.objects.all().reverse()
      res2 = models.Books.objects.all().order_by('price')
      res3 = models.Books.objects.all().order_by('price').reverse()
      print(res2,res3)
      
    11. # exclude()      排除什么什么之外   queryset对象
      res = models.Books.objects.all().exclude(title='三国演义')
      print(res)
      <QuerySet [<Books: 红楼梦>, <Books: 西游记1>, <Books: 西游记2>]>
      
    12. # exists()      判断查询结果是否有值 返回结果是一个布尔值	鸡肋
      res = models.Books.objects.filter(pk=1).exists()
      print(res)
      
    13. # distinct()    对查询结果进行去重操作     去重的前提:数据必须是完全想要的情况下 才能够去重(容易忽略主键),多和values()连用
      res = models.Books.objects.values('title','price')
      res = models.Books.objects.values('title','price').distinct()
      print(res)
      
    14. 小结:

      • 返回QuerySet对象的方法:

        all(),filter(),exclude(),order_by(),reverse(),ditince()
        
      • 特殊的QuerySet:

        values			返回列表套字典
        values_list		返回列表套元组
        
      • 返回具体对象:

        get(),first(),last()
        
      • 返回布尔值:

        exists()
        
      • 返回数字:

        count()
        

urls相关

  • url正则匹配

    
    
  • 首页地址

    url(r'^$', views.home, name='home'),
    

models相关

  • 数据库中已有记录,要新建字段

    1. 设置默认值,default=xxx
    2. 允许控制,null=True
    3. 根据报错提示,给默认值
  • CharField字段,必须要有max_length属性

  • INtegerField字段,默认长度11位

  • 与数据库结构相关的修改,必须要有数据库迁移命令,将操作同步到数据库中

    >>python manage.py makemigrations
    >>python manage.py migrate
    
  • 默认帮你定义了id(主键),自定义的是主键AutoField()

  • 添加外键

    # 一对多
    models.ForeignKey(to='表',to_field='字段',to_delete='级联操作')
    
    # 默认关联主键字段
    #默认级联删除和更新(models.CASCADE),只在应用层生效,在db层(数据库直接操作)RESTRICT(受限制)
    
    # 多对多,建议建在查询频率较高的表中,虚拟字段,在表中看不见,orm会自动创建一张关系表
    models.ManyToManyField(to='表')
    
    **************************************************************************************
    # through参数 可以来自定义的多对多关系的第三张表
    
    # Artical表
    tags = models.ManyToManyField(
        to='Tag',through='Article2Tag',
        through_fields=('article','tags')
    )
    
    # 自定义的Artical2Tag表
    class Article2Tag(models.Model):
        '''文章to标签表'''
    
        article = models.ForeignKey(to='Article')
        tags = models.ForeignKey(to='Tag')
    
    # 一对一,建议建在查询频率较高的表中
    models.OneToOneField(to='表')
    
    # 外键+唯一,不推荐
    models.FoeignKey(to='表',db_constraint='unique')
    
  • choice参数

    可以明确列出用户的所有选择

    先定义好对应关系,在通过choices参数来指定关系

  • auth模块:自动生成的包含各种用户信息的表

    from django.contrib import auth
    
    # 没有自定义用户表时
    from django.contrib.auth.models import User
    
    # 创建普通用户 密码自动加密
    User.objects.create_user(
        username=username,
        password=password
    )  
    
    # 创建超级用户   需要邮箱数据
    User.objects.create_superuser(
    	username=username,
    	password=password,
    	email='123@qq.com'
    )
    
    # 校验用户
    from django.contrib import auth
    user_obj = auth.authenticate(
    	request,
    	username=username,
    	password=password
    	)
    
    # 保存用户状态 执行了这句话,之后在任意位置就可通过 request.user获得当前登陆的用户对象
    auth.login(request,user_obj)  #只能使用调用一次?
    
    # 判断用户登陆
    request.user.is_authenticated()
    
    # 校验密码
    request.user.check_password(old_password)
    
    # 修改密码
    request.user.set_password(new_password)
    request.user.save()
    
    #注销用户 没有登陆也不会报错
    auth.logout(request)
    
    # 自定义继承user表的用户表,会保留原有的字段
    from django.contrib.auth.models import AbstractUser
    
    class Userinfo(AbstractUser):
        '''用户信息表'''
    
        phone = models.BigIntegerField(null=True)
        # auto_now_add会在创建时添加时间,auto_now会在创建和修改时修改时间
        register_time = models.DateField(auto_now_add=True)
        
    # 一定要注意 还需要去配置文件中配置
    # 这么写完之后 之前所有的auth模块功能全都以你写的表为准
    AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名.表名
    

views相关

  • 获取请求方式

    type_of_request = request.method(都是大写)
    
  • 获取请求数据

    #如果是a标签中href中携带的数据也用GET
    #当请求方式是GET时,一般使用render返回页面
    name = request.GET.get('name')
    
    #当请求方式时POST时,一般使用redirect重定向一个页面
    name = request.POST.get('name')
    
    #使用get()默认拿到列表的最后一个
    request.GET.getlist()
    request.POST.getlist()
    
  • 数据库操作

    #增
    new_obj = models.ClassName.objects.create(**kwargs)
    
    #删	根据filter查询的结果批量操作
    models.ClassName.objects.filter(**kwargs).delete()
    
    #改 根据filter查询结果批量操作
    models.ClassName.objects.filter(**kwargs).update(key=value)
    
    #查,支持切片,但不持支负数切片
    obj_list = models.ClassName.objects.filter(**kwargs)
    obj = obj_list.first()
    
    all_obj_list = models.ClassName.objects.all()
    #等价于
    all_obj_list = models.ClassName.objects.filter()
    

前后端传输数据编码格式

前后端交互是一个数据编码格式,针对不同的数据类型,后端会进行不同的处理

  • a标签href参数:get
  • form表单:get/post
  • ajax:get/post
#获取方式

request.POST
request.GET
request.FILES
#三种格式
urlencoded
formdata
application/json
  • form表单默认的编码方式是urlencoded,对应的数据格式username=jason&password=123,Django中会自动解析,并封装到POST中
  • form表单发送文件编码格式ContentType: multipart/formdata,针对formdata格式的数据,在浏览器上是无法查看到的;Django后端只要数据满足urlencoded格式,就会自动帮你解析到request.POST中;如果是文件对象,Django也会自动识别并封装到request.FILES
  • form表单无法发送json格式的数据,只能借助ajax
  • ajax能发送urlencodedformdataapplication/json三种格式数据;ajaz默认的编码格式是urlencoded,Django后端也是将数据解析到request.POST

Ajax

Asynchronous(异步) Javascript And XML

ajax可以只刷新页面局部

当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应

Ajax基本语法结构

$.ajax({
    url:'',
    type:'post',
    data:{'i1':$('#d1').val(),},
    success:function (data) {
        $('#d3').val(data)
    }
})

Ajax传输json格式数据

Django后端针对json格式的数据,不会做任何处理,只会放到requset.body中,需要手动处理

$('#d1').click(function () {
      $.ajax({
          url:'',
          type:'post',
          contentType:'application/json',  # 1.注意点1
          data:JSON.stringify({'username':'jason','password':'123'}),  # 2.注意点2
          success:function (data) {
              alert(123)
          }
      })
  })

Ajax传输文件数据

借助于内置对象new,该对象既可以携带文件数据,也支持普通的键值对

$('#d1').click(function () {
   // 先生成一个内置对象
   var MyFormData = new FormData();
   // 1. 先添加普通的键值
   MyFormData.append('username','jason');  // 添加了一组普通的简直对
   MyFormData.append('password','123');
   // 2. 添加文件数据
   MyFormData.append('myfile',$('#d2')[0].files[0]);  // 如何获取input框中文件对象$('#d1')[0].files[0]
   $.ajax({
      url:'',
      type:'post',
      data:MyFormData,  # 1

      // 发送文件必须要指定的两个参数
      contentType:false,  // 不适用任何编码  MyFormData对象内部自带编码 django后端能够识别  # 2
      processData:false,  // 不要处理数据  # 3

      success:function (data) {

      }

   })
 })

orm相关

  • only

    only方法返回的是一个queryset对象,本质上是列表套对象;该对象内只含有only括号内所指定的属性
    
  • defer

    defer返回的是一个queryset对象,本质是列表套对象;该对象只含有除了defer括号内所指定的属性
    
  • select_related

    括号内只能放外键字段,并且外键字段只能是一对一或一对多;

    内部是连表操作;

    返回的结果是一个queryset,列表套对象;

    该数据对象后取当前表中的数据或关联表中的数据,不会再走数据库;

    主要耗时在连表操作;

  • prefetch_related

    括号内外键字段,类型全部支持;

    内部是子查询;

    返回结果是queryset,列表套对象;

    该数据对象后取当前表中的数据或关联表中的数据,不会再走数据库;

    主要耗时在查询次数;

前端js相关

  • 获取input框中文件对象

    $('#d2')[0].files[0])
    
  • 序列化表单内键值对

     {# 自动序列化form表单内键值对 #}
     $.each($('#myform').serializeArray(), function (index, obj) {
     	MyFormData.append(obj.name, obj.value)
     });
    
  • 利用内置对象FormData传文件

    $('#submit').click(function () {
    
            {# FormData既可以传普通键值对,也可传文件对对象 #}
            let MyFormData = new FormData();
            {# 自动序列化form表单内键值对 #}
            $.each($('#myform').serializeArray(), function (index, obj) {
                MyFormData.append(obj.name, obj.value)
            });
    
            MyFormData.append('avatar', $('#mdd')[0].files[0]);
            console.log($('#mdd')[0].files[0]);
            $.ajax({
                url:'',
                type:'post',
                data:MyFormData,
                {#  发送文件一定要指定两个参数  #}
                processData:false,
                contentType:false,
    
                success:function (data) {
                    if (data.code == 1000){
                        window.location.href = data.url
                    }else{
                        // index是报错字段,obj是数组形式的报错信息
                        $.each(data.msg, function (index, obj) {
                            /* 上面for循环渲染的input框,foo.auto_id给每个input框添										加'id_fieldname'形式的id #}*/
                            let targetId = '#id_' + index;
                            {# 当输入有误时,打印错误信息并是对应的输入框变红 #}
                            $(targetId).next().text(obj[0]).parent().addClass('has-error')
    
                        })
                    }
                
                }
            })
        });
    

其他

  • django是默认重启的,内有检测机制,实时检测所有文件的变化

  • form表单默认请求方式是get请求,也能携带极小量的数据而且不安全

    <a href="http://127.0.0.1:8000/login/?username=jason&password=jason123"></a>
    
  • web身份校验(cookie、session、token)

    • cookie:Cookie指的是浏览器里能永久存储的一种数据,是浏览器实现的一种数据存储功能。Cookie是由服务端生成,发送给浏览器,浏览器把Cookie以key-value的形式保存到某个目录下的文本文件内,下一次请求同一个网站的时候会把该Cookie发送给服务端。由于Cookie是存在客户端上的,所以浏览器加入了一些限制确保Cookie不会被恶意使用,同时不会占据太多的磁盘空间,每个域的Cookie的数量都是有限的
    • session:会话。Coookie中存放着一个sessionID,请求时会发送这个sessionID;session因为请求(request对象)而产生;session是一个容器,相当于一个字典,可以存放会话过程中的任何对象;session的创建与使用总是在服务端,浏览器从来没有得到过session对象;session是一种http存储机制,目的是为了武装http提供持久机制
    • token:令牌,是用户身份的验证方式。可以在token中包含足够多的信息,以便在后续请求中减少查询数据库的几率;
原文地址:https://www.cnblogs.com/shenblog/p/11918418.html