Django 全干货分享包括ORM视图查询语法接口写法一对一 一对多

 Django-admin startproject mysite --项目名称

启动 Django
python manage.py runserver 127.0.0.1:80 --启动IP地址,端口号(默认127.0.0.1:8000)
创建应用

python manage.py startapp app01

1.配置数据库
MySQL数据库首先需要安装驱动程序

pip install PyMySQL

在__init__.py包文件引入

from pymysql import install_as_MySQLdb
install_as_MySQLdb() # 让pymysql以MySQLDB的运行模式和Django的ORM对接

运行
修改
DATABASES配置信息

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,  # 数据库端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123',  # 数据库用户密码
        'NAME': 'student'  # 数据库名字
    }
}

在MySQL中创建数据库
create database student; # mysql8.0默认就是utf8mb4;
create database student default charset=utf8mb4; # mysql8.0之前的版本
注意3: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}  

读写分离多个操作多个数据库
https://www.cnblogs.com/shaoyishi/p/17038652.html
https://blog.csdn.net/weixin_44346972/article/details/127107886
https://www.jb51.net/article/248460.htm
6.3、数据迁移
将模型类定义表架构的代码转换成SQL同步到数据库中,这个过程就是数据迁移。django中的数据迁移,就是一个类,这个类提供了一系列的终端命令,帮我们完成数据迁移的工作。
(1)生成迁移文件
所谓的迁移文件, 是类似模型类的迁移类,主要是描述了数据表结构的类文件.

python manage.py makemigrations #student #student 就是你自己构建模块名称

(2)同步到数据库中

python manage.py migrate #student#student 就是你自己构建模块名称

补充:在django内部提供了一系列的功能,这些功能也会使用到数据库,所以在项目搭建以后第一次数据迁移的时候,会看到django项目中其他的数据表被创建了。其中就有一个django内置的admin站点管理。

1.可以使用引入JsonResponse 直接返回json数据
(注意如果返回列表类型数据需要改变 JsonResponse 的参数 safe=False )


from django.http import JsonResponse

#来序列号json类型数据

def jsoss(request):
   # book = {'title': '金苹果吗', 'price': 199}
    books = [{'title': '金苹果吗', 'price': 199},{'title': '水浒传', 'price': 299}]
    return JsonResponse(books,json_dumps_params={'ensure_ascii': False}, safe=False,charset='utf-8')

静态文件配置修改

STATIC_URL = ‘/static/’ # 别名
X_FRAME_OPTIONS = ‘ALLOWALL’


STATIC_ROOT = BASE_DIR / ‘static’

STATICFILES_DIRS = [BASE_DIR / ‘static’, r"N:\phpstudy_pro\pythonLixi\commerce_pro\commerce_html\admin\dist", ]

STATIC_URL = '/static/' 
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static') ]

跨域允许

ALLOWED_HOSTS = ['*']

Django的POST请求报403,及四种解决方法
发布于2018-10-10 10:15:39阅读 11.8K0
Django默认开启防止csrf(跨站点请求伪造)攻击,在post请求时,没有上传 csrf字段,导致校验失败,报403错误
解决方法1:

注释掉此段代码,即可。
缺点:导致Django项目完全无法防止csrf攻击
解决方法2:
在 views.py文件中
#导入,可以使此次请求忽略csrf校验

from django.views.decorators.csrf import csrf_exempt

#在处理函数加此装饰器即可

@csrf_exempt
def post(request):
     name=request.post['name']
     return HttpResponse('welcome!{}'.format(name))
.请求方式 POST
def show(request):
    # print("moblie", m, type(m))
    #print(request.method)
    print(request.body) #获取json 格式
    user = request.POST.get('user') # 获取 urlenceded
    pwd = request.POST.get('pwd')
    qq = request.POST.getlist('qq')
    return HttpResponse("hi用户 {} \n密码 {} \nQQ: {}".format(user,pwd,qq))

请求方式 GET

#获取请求路径
获取全部get 请求数据
request.GET()
request.GET.get()

request.path
request.get_full_path()
print(request.path)  # /users
print(request.get_full_path()) # /users?a=1
获取请求头
# 获取请求头数据
# print(request.META)
# print(request.META.get("HTTP_HOST"))
# print(request.META.get("HTTP_XXX"))

三、利用[field.verbose_name]增加针对mysql字段注释的处理
修改django/db/backends/base/schema.py 文件,column_sql 函数,如下:
步骤一:找到Python按照根目录;如:
D:\python\Python38-32
步骤二:找到需要修改的文件;如:
D:\python\Python38-32\Lib\site-packages\django\db\backends\base\schema.py
步骤三:找到 column_sql 函数 的结尾处,大概 256 行,如下修改:

利用[field.verbose_name]增加针对mysql字段注释的处理

if self.connection.client.executable_name =='mysql' and field.verbose_name:

    sql +=" COMMENT '%s'" % field.verbose_name

Return the sql

模板替换语法 (深度查询)
什么.什么.查找模板中的变量即可

from django.shortcuts import render, HttpResponse
# from django.template.loader import get_template
class book(object):
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return "书记名称: {} 价钱: {}".format(self.name, self.price)
# Create your views here.
def index(request):
    name = '立下了'
    age = 28
    # 是否结婚
    Married = False
    shendu = '深度查询'
    book_list = ['三国', '水浒', '西游', '红楼']

    zhangsan = {'name': "张三", "age": 39, 'occupation': '罪犯'}

    resbook0 = book('三体', 299)
    resbook1 = book('乱', 299)
    resbook2 = book('红粉佳人', 299)
    resbook3 = book('无敌卡', 299)

    books = [resbook0,resbook1,resbook2,resbook3]
    return render(request, 'get_template.html', locals())

什么.什么.查找模板中的变量即可

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>获取模板文件</title>
    <style >
        span{
            display: inline-block;
            margin-bottom:18px ;
        }

    </style>
</head>
<body>
<h1>{{ shendu }}</h1>
姓名:<span style="color: #0a53be">{{ name }}</span><br>
年龄:<span style="color: #37be0a">{{ age }}</span><br>
婚否:<span style="color: #be0a55">{{ Married }}</span><br>
四大名著:<span style="color: #000000">{{ book_list }}</span><br>
第二本名著:<span style="color: #000000">{{ book_list.1 }}</span><br>


法外狂赌{{zhangsan.name}}:<span style="color: #000000">他的年龄:{{ zhangsan.age }}</span> <span style="color: #000000">他的职业:{{ zhangsan.occupation }}</span><br>
</body>
<h2>书籍名称 {{ resbook.name }}</h2>
<div>
   {{ resbook.age }}
</div>
<!-- 最最查询方法 -->
<div>{{ books.2.price }} </div>
</html>

如果仍然无法获得代码提示,则可以尝试强制PyCharm重新加载项目缓存。在PyCharm中,选择“File”->“Invalidate Caches / Restart”,然后选择“Invalidate and Restart”。
5.3.2、变量渲染之内置过滤器
内置过滤器
过滤器用法代码last获取列表/元组的最后一个成员{{liast | last}}first获取列表/元组的第一个成员{{list|first}}length获取数据的长度{{list | length}}defualt当变量没有值的情况下, 系统输出默认值,{{str|default=“默认值”}}safe让系统不要对内容中的html代码进行实体转义{{htmlcontent| safe}}upper字母转换成大写{{str | upper}}lower字母转换成小写{{str | lower}}title每个单词首字母转换成大写{{str | title}}date日期时间格式转换{{ value| date:“D d M Y” }}cut从内容中截取掉同样字符的内容{{content | cut:“hello”}}list把内容转换成列表格式{{content | list}}add加法{{num| add}}filesizeformat把文件大小的数值转换成单位表示{{filesize | filesizeformat}}join按指定字符拼接内容{{list| join(“-”)}}random随机提取某个成员{list | random}}slice按切片提取成员{{list | slice:“:-2”}}truncatechars按字符长度截取内容{{content | truncatechars:30}}truncatewords按单词长度截取内容同上

5.3.4、标签

1if 标签
{% if age > 18 %}
<p>成年电影 </p>
{% else %}
<p>为成年电影</p>
{% endif %}

在 Django 模板中,可以使用嵌套的 {% if %} 标签来实现逻辑判断。嵌套的 {% if %} 标签需要注意缩进和正确的语法,以下是一个示例:

{% if condition1 %}
    {% if condition2 %}
        ... some content ...
    {% endif %}
{% endif %}

(2)for标签

{% for student in student_list %}
    <tr>
        <td>{{ forloop.counter }}</td>
        <td>{{ student.name }}</td>
        <td>{{ student.age }}</td>
        <td>{{ student.get_sex_display }}</td>
        <td>{{ student.birthday|date:'Y-m-d' }}</td>
        <td>{{ student.clas.name }}</td>
        <td>
            {% if student.courses.all %}
                {% for course in student.courses.all %}
                 <button class="btn btn-sm btn-success">{{ course.title }}</button>
                {% endfor %}
            {% else %}
                <button class="btn btn-sm btn-success">暂时没有任何选修</button>
            {% endif %}

        </td>

        <td>
            <a class="btn-sm btn-warning" href="/student/edit/{{ student.pk }}">编辑</a>
            <a class="btn-sm btn-danger" href="/student/delete/{{ student.pk }}">删除</a>
        </td>
    </tr>
{% endfor %}

{% for i in book_list %}
    <ul>
        <li style="list-style: none">{{ i }}</li>
    </ul>
{% endfor %}
<table width="800" border="1">
    <tr>
        <th>序号</th>
        <th>书籍名称</th>
        <th>价格</th>
        <th>出版社</th>
    </tr>
{% for t in books %}
        <tr>
            <th>{{ forloop.counter }}</th>
            <th>{{ t.name }}</th>
            <th>{{ t.price }}</th>
            <th>{{ t.press }}</th>
        </tr>
{% endfor %}
模板嵌套继承
传统的模板分离技术,依靠{% include "模板文件名"%}实现,这种方式,虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升.因此, Django框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承给开发者.
{% include "模板文件名"%}  # 模板嵌入
{% extends "base.html" %} # 模板继承 
1.include
{% include 'ad.html' %}
2.extends
{% extends 'base.html' %}
{% block title %}
    <title>订单</title>
{% endblock title %}
{% block content %}
    {{ block.super }}
<h3>我的订单</h3>
<ul>
    {% for foo in order_list  %}
        <li>{{ foo }}</li>
    {% endfor %}
    
</ul>
{% include 'ad.html' %}
{% endblock content %}
ORM
在models.py 文件中定义模型类。
from django.db import models
from datetime import datetime
​

模型类必须要直接或者间接继承于 models.Model

class BaseModel(models.Model):
    """公共模型[公共方法和公共字段]"""
    # created_time = models.IntegerField(default=0, verbose_name="创建时间")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # auto_now_add 当数据添加时设置当前时间为默认值
    # auto_now= 当数据添加/更新时, 设置当前时间为默认值
    updated_time = models.DateTimeField(auto_now=True)
    class Meta(object):
        abstract = True # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型.class Student(BaseModel):
    """Student模型类"""
    #1. 字段[数据库表字段对应]
    SEX_CHOICES = (
        (0,"女"),
        (1,"男"),
        (2,"保密"),
    )# 字段名 = models.数据类型(约束选项1,约束选项2, verbose_name="注释")
    # SQL: id bigint primary_key auto_increment not null comment="主键",
    # id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk# SQL: name varchar(20) not null comment="姓名"
    # SQL: key(name),
    name = models.CharField(max_length=20, db_index=True, verbose_name="姓名" )# SQL: age smallint not null comment="年龄"
    age = models.SmallIntegerField(verbose_name="年龄")# SQL: sex tinyint not null comment="性别"
    # sex = models.BooleanField(verbose_name="性别")
    sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2)# SQL: class varchar(5) not null comment="班级"
    # SQL: key(class)
    classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")
    # SQL: description longtext default "" not null comment="个性签名"
    description = models.TextField(default="", verbose_name="个性签名")#2. 数据表结构信息
    class Meta:
        db_table = 'tb_student'  # 指明数据库表名,如果没有指定表明,则默认为子应用目录名_模型名称,例如: users_student
        verbose_name = '学生信息表'  # 在admin站点中显示的名称
        verbose_name_plural = verbose_name  # 显示的复数名称#3. 自定义数据库操作方法
    def __str__(self):
        """定义每个数据对象的显示信息"""
        return "<User %s>" % self.name

(1) 数据库表名
模型类如果未指明表名db_table,Django默认以 小写app应用名_小写模型类名 为数据库表名。
可通过db_table 指明数据库表名。
(2) 关于主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列。
如果使用选项设置某个字段的约束属性为主键列(primary_key)后,django不会再创建自动增长的主键列。
class Student(models.Model):
# django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
id = models.AutoField(primary_key=True, null=False, verbose_name=“主键”) # 设置主键
默认创建的主键列属性为id,可以使用pk代替,pk全拼为primary key。
(3) 属性命名限制
不能是python的保留关键字。
不允许使用连续的2个下划线,这是由django的查询方式决定的。__ 是关键字来的,不能使用!!!
定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:

属性名 = models.字段类型(约束选项, verbose_name=“注释”)
(4)字段类型
类型说明AutoField自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性BooleanField布尔字段,值为True或FalseNullBooleanField支持Null、True、False三种值CharField字符串,参数max_length表示最大字符个数,对应mysql中的varcharTextField大文本字段,一般大段文本(超过4000个字符)才使用。IntegerField整数DecimalField十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数,常用于表示分数和价格 Decimal(max_digits=7, decimal_places=2) ==> 99999.99~ 0.00FloatField浮点数DateField日期
参数auto_now表示每次保存对象时,自动设置该字段为当前时间。
参数auto_now_add表示当对象第一次被创建时自动设置当前。
参数auto_now_add和auto_now是相互排斥的,一起使用会发生错误。TimeField时间,参数同DateFieldDateTimeField日期时间,参数同DateFieldFileField上传文件字段,django在文件字段中内置了文件上传保存类, django可以通过模型的字段存储自动保存上传文件, 但是, 在数据库中本质上保存的仅仅是文件在项目中的存储路径!!ImageField继承于FileField,对上传的内容进行校验,确保是有效的图片
(5)约束选项
选项说明null如果为True,表示允许为空,默认值是False。相当于python的Noneblank如果为True,则该字段允许为空白,默认值是False。 相当于python的空字符串,“”db_column字段的名称,如果未指定,则使用属性的名称。db_index若值为True, 则在表中会为此字段创建索引,默认值是False。 相当于SQL语句中的keydefault默认值,当不填写数据时,使用该选项的值作为数据的默认值。primary_key如果为True,则该字段会成为模型的主键,默认值是False,一般不用设置,系统默认设置。unique如果为True,则该字段在表中必须有唯一值,默认值是False。相当于SQL语句中的unique
注意:null是数据库范畴的概念,blank是表单验证范畴的
(6) 外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
CASCADE
级联,删除主表数据时连通一起删除外键表中数据
PROTECT
保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
SET_NULL
设置为NULL,仅在该字段null=True允许为null时可用
SET_DEFAULT
设置为默认值,仅在该字段设置了默认值时可用
SET()
设置为特定值或者调用特定方法,例如:

from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
​
def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]class UserModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )
   # 一对多
    # on_delete= 关联关系的设置
    # models.CASCADE    删除主键以后, 对应的外键所在数据也被删除
    # models.DO_NOTHING 删除主键以后, 对应的外键不做任何修改
    # 反向查找字段 related_name
    clas = models.ForeignKey(to='clas',related_name='claslit', on_delete=models.CASCADE,db_constraint=False)


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

   courses = models.ManyToManyField("Course",related_name='claslit', db_table="db_student2course",db_constraint=False)# 一对一,使用同一对多
    stu_detail = models.OneToOneField("StudentDetail",related_name='claslit', on_delete=models.CASCADE,db_constraint=False)

模糊查询
def select_student2(requset):
    # data=MyHeadline.objects.filter(name__contains='个').values('name')
    # data = Student.objects.filter(name__contains='李').values('id', 'name', 'age')
    data = Student.objects.filter(age__gt=22).values('id', 'name', 'age').order_by('-id')
    return Jsonbases(data)
8.1.1.自定义中间件
(1)定义中间件
创建存放自定义中间件的文件这里选择在app01里创建mdws.py文件:
from django.utils.deprecation import MiddlewareMixin
​
​
class Md1(MiddlewareMixin):def process_request(self, request):
        print("Md1请求")
        # return HttpResponse("Md1中断")    # 拦截def process_response(self, request, response):
        print("Md1返回")
        return response
​
​
class Md2(MiddlewareMixin):def process_request(self, request):
        print("Md2请求")
        # return HttpResponse("Md2中断")def process_response(self, request, response):
        print("Md2返回")
        return response


process_request默认返回None,返回None,则继续执行下一个中间件的process_request;一旦返回响应体对象,则会拦截返回。process_response必须有一个形参response,并return response;这是view函数返回的响应体,像接力棒一样传承给最后的客户端。

Django 存取cookie
取cookie

request.get_signed_cookie('islogin', salt=你的密钥)
def index(request):
    try:
        res_islogin = request.get_signed_cookie('islogin', salt=ORM2.settings.SAIT)
        if res_islogin:
            userid = request.get_signed_cookie('userid',salt=ORM2.settings.SAIT)
            student_list = Student.objects.filter(isdel=0).all()
            stuuser = Student.objects.get(id=userid)
        # data = [{'name': i.courses} for i in student_list]
        # print(data)
            return render(request, 'xinliu/html/ltr/index.html',
                      {'student_list': student_list, 'stuusername': stuuser.name})
    # return render(request, 'student/index.html', {'student_list': student_list})
        else:
            return redirect(to='/student/login')
    except Exception as e:
        return redirect(to='/student/login')

res_islogin.set_signed_cookie(‘islogin’, “true”,max_age=’失效时间‘,salt=’你的密钥‘)
max_age参数用于设置cookie的最大有效期(以秒为单位)

def login(request):
    exampleModal = ''
    if request.method == 'POST':
        data = request.POST.dict()

        user = data['username']
        # data = json.loads(data)
        try:
            resstu = Student.objects.get(name=user)

            res_islogin = HttpResponseRedirect('/student/')
            res_islogin.set_signed_cookie('islogin', "true",max_age=30,salt=ORM2.settings.SAIT)
            res_islogin.set_signed_cookie('userid', resstu.id,max_age=30,salt=ORM2.settings.SAIT)
            return res_islogin
        except Exception as e:
            exampleModal = 2
        # return Jsonbases(data)

    return render(request, 'xinliu/html/ltr/login/login-9.html', {'exampleModal': exampleModal})

Django 存取session
session写入  
request.session["last_time"] = now
def shop(request):
    last_time = request.session.get("last_time")
    now = datetime.datetime.now().strftime("%Y-%m-%d %X")
    request.session["last_time"] = now
​
    return render(request, "shop.html", {"last_time": last_time})


读session

def s_index(request):
    # 读session
    is_login = request.session.get("is_login")
    if is_login:
        username = request.session.get("username")
        return render(request, "index.html", {"user": username})
    else:
        return redirect("/s_login/")
del request.session["last_time"]

(3)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,

默认修改之后才保存(默认)

使用特殊装饰完成数据库事务
以下是一个使用
atomic()装饰器来打开事务的示例代码:
from django.db import transaction

@transaction.atomic
def my_view(request):
# 在这里执行数据库操作

8.2.3、用户认证组件
Django默认已经提供了认证系统Auth模块,我们认证的时候,会使用auth模块里面给我们提供的表。认证系统包含:
用户管理
权限
用户组
密码哈希系统
用户登录或内容显示的表单和视图
一个可插拔的后台系统 admin

(1)Django用户模型类
Django认证系统中提供了用户模型类User保存用户的数据,默认的User包含以下常见的基本字段:
字段名字段描述username必选。150个字符以内。 用户名可能包含字母数字,_,@,+ . 和-个字符。first_name可选(blank=True)。 少于等于30个字符。last_name可选(blank=True)。 少于等于30个字符。email可选(blank=True)。 邮箱地址。password必选。 密码的哈希加密串。 (Django 不保存原始密码)。 原始密码可以无限长而且可以包含任意字符。groups与Group 之间的多对多关系。user_permissions与Permission 之间的多对多关系。is_staff布尔值。 设置用户是否可以访问Admin 站点。is_active布尔值。 指示用户的账号是否激活。 它不是用来控制用户是否能够登录,而是描述一种帐号的使用状态。is_superuser是否是超级用户。超级用户具有所有权限。last_login用户最后一次登录的时间。date_joined账户创建的时间。 当账号创建时,默认设置为当前的date/time。
上面缺少一些字段,所以后面我们会对当前内置的用户模型进行改造,比如说它里面没有手机号字段,后面我们需要加上。
(2)重要方法
Django 用户认证(Auth)组件需要导入 auth 模块

认证模块

from django.contrib import auth

对应数据库用户表,可以继承扩展

from django.contrib.auth.models import User
(1)用户对象
create() # 创建一个普通用户,密码是明文的。
create_user() # 创建一个普通用户,密码是密文的。
User.objects.create_user(username='wang', password='1234')
create_superuser() # 与create_user() 相同,但是设置is_staff 和is_superuser 为True。
​User.objects.create_superuser(username='wang', password='1234')
User.objects.set_password(*raw_password*)

设置用户的密码为给定的原始字符串,并负责密码的。 不会保存User对象。当None为raw_password时,密码将设置为一个不可用的密码。

User.objects.check_password(*raw_password*)

如果给定的raw_password是用户的真实密码,则返回True,可以在校验用户密码时使用。

(2)认证方法

auth.authenticate(username,password) 

将输入的密码转为密文去认证,认证成功返回用户对象,失败则返回None

(3)登录和注销方法

from django.contrib import auth

该函数接受一个HttpRequest对象,以及一个认证了的User对象。此函数使用django的session框架给某个已认证的用户附加上session id等信息。

auth.login() 

该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

auth.logout()
(4)request.user
Django有一个默认中间件,叫做AuthenticationMiddleware,每次请求进来都会去session中去一个userid,取不到的话,赋值request.user = AnonymousUser() , 一个匿名用户对象。
当用户组件auth.login一旦执行,将userid到session中后,再有请求进入Django,将注册的userid对应的user对象赋值给request.user,即再后面的任何视图函数中都可以从request.user中取到该客户端的登录对象。
(5)自定义用户表
from django.contrib.auth.models import AbstractUser设置Auth认证模块使用的用户模型为我们自己定义的用户模型格式:“子应用目录名.模型类名”AUTH_USER_MODEL = ‘users.User’
8.3、Django的分页器
from django.core.paginator import Paginator
(1) index视图

def index(request):
    '''
    批量导入数据:
​
    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    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(1) # 第1页的page对象
    for i in page1:         # 遍历第1页的所有数据对象
        print(i)
​
    print(page1.object_list) #第1页的所有数据
​
​
    page2=paginator.page(2)
​
    print(page2.has_next())            #是否有下一页
    print(page2.next_page_number())    #下一页的页码
    print(page2.has_previous())        #是否有上一页
    print(page2.previous_page_number()) #上一页的页码
​
​
​
    # 抛错
    #page=paginator.page(12)   # error:EmptyPage
​
    #page=paginator.page("z")   # error:PageNotAnInteger
​
    '''
​
    book_list = Book.objects.all()
​
    paginator = Paginator(book_list, 10)
    page = request.GET.get('page', 1)
    current_page = int(page)try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)return render(request, "index.html", {"book_list": book_list, "paginator": paginator, "currentPage": current_page})(2) index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 
    integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body><div class="container"><h4>分页器</h4>
    <ul>{% for book in book_list %}
             <li>{{ book.title }} -----{{ book.price }}</li>
        {% endfor %}</ul>
​
​
    <ul class="pagination" id="pager">{% if book_list.has_previous %}
                    <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
                 {% else %}
                    <li class="previous disabled"><a href="#">上一页</a></li>
                 {% endif %}
​
​
                 {% for num in paginator.page_range %}{% if num == currentPage %}
                       <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
                     {% else %}
                       <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>{% endif %}
                 {% endfor %}
​
​
​
                 {% if book_list.has_next %}
                    <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
                 {% else %}
                    <li class="next disabled"><a href="#">下一页</a></li>
                 {% endif %}</ul>
</div>
​
​
​
</body>
</html>

from django.core.paginator import Paginator
from django.shortcuts import render
def my_view(request):

获取数据列表

data_list = MyModel.objects.all()

初始化分页器

paginator = Paginator(data_list, 10)  # 每页显示10条数据

获取当前页面号码

page_number = request.GET.get('page')

获取当前页面的数据对象

page_obj = paginator.get_page(page_number)

渲染分页器网页

return render(request, 'my_template.html', {'page_obj': page_obj})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Django Bootstrap 3分页器</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<h1>分页数据列表</h1>
{% if page_obj.has_other_pages %}
<nav aria-label="Page navigation">
<ul class="pagination">
{% if page_obj.has_previous %}
<li>
<a href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
      {% for i in page_obj.paginator.page_range %}
      {% if page_obj.number == i %}
      <li class="active"><a href="#">{{ i }} <span class="sr-only">(current)</span></a></li>
      {% else %}
      <li><a href="?page={{ i }}">{{ i }}</a></li>
      {% endif %}
      {% endfor %}

      {% if page_obj.has_next %}
      <li>
        <a href="?page={{ page_obj.next_page_number }}" aria-label="Next">
          <span aria-hidden="true">&raquo;</span>
        </a>
      </li>
      {% endif %}
    </ul>
  </nav>
  {% endif %}

  <table class="table">
    <thead>
      <tr>
        <th>ID</th>
        <th>名称</th>
        <th>年龄</th>
      </tr>
    </thead>
    <tbody>
      {% for obj in page_obj %}
      <tr>
        <td>{{ obj.id }}</td>
        <td>{{ obj.name }}</td>
        <td>{{ obj.age }}</td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
</div>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</body>
</html>

分页接口
from django.core.paginator import Paginator
from django.http import JsonResponse
def my_view(request):

获取数据列表

data_list = MyModel.objects.all()

初始化分页器

paginator = Paginator(data_list, 10) # 每页显示10条数据

获取当前页面号码

page_number = request.GET.get(‘page’)

获取当前页面的数据对象

page_obj = paginator.get_page(page_number)

将页面数据转换为JSON对象

page_data = {
“current_page”: page_obj.number,
“total_pages”: paginator.num_pages,
“data”: [
{“id”: obj.id, “name”: obj.name, “age”: obj.age} for obj in page_obj
]
}

返回JSON响应

return JsonResponse(page_data)

8.4.3、RESTful API规范
RESTful是一种专门为Web 开发而定义API接口的设计风格,尤其适用于前后端分离的应用模式中。
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。

POST http://www.xxx.com/api/students/ 添加学生数据
GET http://www.xxx.com/api/students/ 获取所有学生
GET http://www.xxx.com/api/students/1/ 获取id=pk的学生
DELETE http://www.xxx.com/api/students/1/ 删除id=pk的一个学生
PUT http://www.xxx.com/api/students/1/ 修改一个学生的全部信息 [id,name,sex,age,]
PATCH http://www.xxx.com/api/students/1/ 修改一个学生的部分信息[age]
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
GET/students获取所有学生请求方法请求地址后端操作POST/students增加学生GET/students/获取编号为pk的学生PUT/students/修改编号为pk的学生DELETE/students/删除编号为pk的学生
restful规范是一种通用的规范,不限制语言和开发框架的使用。事实上,我们可以使用任何一门语言,任何一个框架都可以实现符合restful规范的API接口。
参考文档:http://www.runoob.com/w3cnote/restful-architecture.html
接口实现过程中,会存在幂等性。所谓幂等性是指代客户端发起多次同样请求时,是否对于服务端里面的资源产生不同结果。如果多次请求,服务端结果还是一样,则属于幂等接口,如果多次请求,服务端产生结果是不一样的,则属于非幂等接口。
请求方式是否幂等是否安全GET幂等安全POST不幂等不安全PUT/PATCH幂等不安全DELETE幂等不安全
8.4、FBV与CBV
8.4.4、CBV使用

FBV模式

path(‘index/’, views.index),

CBV模式

path(“index/”,views.IndexView.as_view()),
path(“books/”,views.BookView.as_view())

import inspect
from django.core import serializers

class cbcview(View):
    def __init__(self):

        self.init = str(inspect.currentframe().f_code.co_name).upper()

    def handle_request(self, method):
        return HttpResponse('CBV ' + str(method.__name__).upper())

    def get(self, request):

        stu= Student.objects.all()
        seriali = serializers
        resjson=seriali.serialize('json',stu)
        return HttpResponse(resjson,content_type='json')

    def post(self, request):
        return self.handle_request(self.post)

    def delete(self, requset):
        return self.handle_request(self.delete)

8.6、ORM进阶
8.6.1、queryset特性
(1)可切片
使用Python 的切片语法来限制查询集记录的数目 。它等同于SQL 的LIMIT 和OFFSET 子句。

Article.objects.all()[:5] # (LIMIT 5)
Article.objects.all()[5:10] # (OFFSET 5 LIMIT 5)
不支持负的索引(例如Article.objects.all()[-1])。通常,查询集 的切片返回一个新的查询集 —— 它不会执行查询。
(2)可迭代
articleList=models.Article.objects.all()

for article in articleList:
print(article.title)
(3)惰性查询
查询集 是惰性执行的 —— 创建查询集不会带来任何数据库的访问。你可以将过滤器保持一整天,直到查询集 需要求值时,Django 才会真正运行这个查询。
queryResult=models.Article.objects.all() # not hits database
print(queryResult) # hits database
for article in queryResult:
print(article.title) # hits database
一般来说,只有在“请求”查询集 的结果时才会到数据库中去获取它们。当你确实需要结果时,查询集 通过访问数据库来求值。 关于求值发生的准确时间。
(4)缓存机制
每个查询集都包含一个缓存来最小化对数据库的访问。理解它是如何工作的将让你编写最高效的代码。
在一个新创建的查询集中,缓存为空。首次对查询集进行求值 —— 同时发生数据库查询 ——Django 将保存查询的结果到查询集的缓存中并返回明确请求的结果(例如,如果正在迭代查询集,则返回下一个结果)。接下来对该查询集 的求值将重用缓存的结果。
请牢记这个缓存行为,因为对查询集使用不当的话,它会坑你的。例如,下面的语句创建两个查询集,对它们求值,然后扔掉它们:
queryset = Book.objects.all()
print(queryset) # hit database
print(queryset) # hit database
注:简单地打印查询集不会填充缓存。
这意味着相同的数据库查询将执行两次,显然倍增了你的数据库负载。同时,还有可能两个结果列表并不包含相同的数据库记录,因为在两次请求期间有可能有Article被添加进来或删除掉。为了避免这个问题,只需保存查询集并重新使用它:
queryset = Book.objects.all()
ret = [i for i in queryset] # hit database
print(queryset) # 使用缓存
print(queryset) # 使用缓存
何时查询集会被缓存?
遍历queryset时if语句(为了避免这个,可以用exists()方法来检查是否有数据)
所以单独queryset的索引或者切片都不会缓存。
queryset = Book.objects.all()
one = queryset[0] # hit database
two = queryset[1] # hit database
print(one)
print(two)
(5)exists()与iterator()方法
exists
简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些 数据!为了避免这个,可以用exists()方法来检查是否有数据:
if queryResult.exists():
#SELECT (1) AS “a” FROM “blog_article” LIMIT 1; args=()
print(“exists…”)
iterator
当queryset非常巨大时,cache会成为问题。
处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法 来获取数据,处理完数据就将其丢弃。
objs = Book.objects.all().iterator()

iterator()可以一次只从数据库获取少量数据,这样可以节省内存

for obj in objs:
print(obj.title)
#BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
for obj in objs:
print(obj.title)
当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使 #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询。
queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能 会造成额外的数据库查询。 
总结:在使用缓存机制还是生成器机制的选择上如果是,数据量大情况主要使用生成器;数据少使用次数多的情况使用缓存机制。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值