Django框架

Django框架

Flask与Django的区别

Flask中:
request请求的取值:
GET:     request.args.get(key)
POST:    request.form.get(key)
COOKIES: request.cookies.get(key)
FILES:   request.files.get(key)
response响应的值:
author='Echo'
return render_template('xxx.html',author=author)
views
在views包中路由和视图函数是一体的,路由作为一个装饰器来装饰视图函数
蓝图:
    bp = Blueprint('user',__name__,url_prefix='/user') #定义蓝图  #url_prefix:路径的前缀
    @user_bp.route('/')  #使用蓝图对象定义路由,相当于app.route('/')
    def index():
        return
重定向:
      return redirect(url_for('blueprintname.视图函数名'))        
template模板中
在template模板中:
{{url_for('index',a=1,b=2)}}
Django中
request请求的取值:
GET:     request.GET.get(key)
POST:    request.POST.get(key)
COOKIES: request.COOKIES.get(key)
FILES:   request.FILES.get(key)
response响应的值:
1.HttpResponse('响应内容')

2.render(request,'模板xxx.html',{'username':username})
路由urls.py
在django中路由和视图函数是分开的,路由在urls中,视图函数在views中
1.主路由中定义:
     urlpatterns = [
       path('user/',include('user.urls',namespace='user'))#http://127.0.0.1:8000/user/login/
       path('news',include('news.urls',namespace='news'))
     ]
--------------------------------------------------------------
2.在应用中添加urls.py
app_name = 'user'  ------>如果没有app_name,会报错
urlpatterns = [
  path('',index,name='index')
  path('login/',login,name='login')
]
视图函数views.py
def index():
        return
重定向:redirect(reverse('namespace#主路由名字:name#子路由名字'))
模板template中
模板中:
{%url'namespace:name'%}

1.简介

Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。

Django是一个开放源代码的Web应用框架,由Python写成。

2.构建虚拟环境

打开电脑黑屏终端,输入命令:mkvirtualenv django1901,构建django的虚拟环境。

在配置好虚拟环境之后,创建一个django项目。

在pycharm的控制台Terminal上,安装: pip install django==2.0

​ pip install mysqlcline

3.项目结构的搭建

创建一个django项目
项目
  |---项目同名文件夹
        |----settings.py   -----> 配置文件 1. 第一步   database  语言 时区
        | ---urls.py    -----> 主路由文件
        | ---wsgi.py
        | -- __init__.py
  | ---user
        |--migrations文件夹
        |-- __init__.py
        |--views.py
        |--models.py
        |--tests.py
        |--apps.py
        |--admin.py
        |--urls.py  ----->自己添加

  | ---templates   ----> 模板文件夹
  | ---manage.py
第一步
创建一个django项目之后,会有一个与项目同名的文件夹,在这个文件夹里面有:
   settings.py ------->配置文件
   urls.py     ------->主路由文件
   wsgi.py
   __init__.py
--------------------------------------------------------------
修改settings.py文件中DATABASES的默认值为:
                   """
                   DATABASES = {
                    'default': {
                        'ENGINE': 'django.db.backends.mysql',
                        'NAME': 'XXX',
                        'USER':'XXX',
                        'PASSWORD':'XXX',
                        'HOST':'39.106.150.87',
                        'PORT':3306
                    }
                }
                   """
--------------------------------------------------------------
修改settings.py文件中语言模式和时区模式为:
                   """
                   LANGUAGE_CODE = 'zh-hans'

                   TIME_ZONE = 'Asia/Shanghai'

                   USE_I18N = True

                   USE_L10N = True

                   USE_TZ = False
                   """
--------------------------------------------------------------
当使用静态文件时需要在settings.py中配置:
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),]
--------------------------------------------------------------
在使用pip install startapp 应用名 在项目中添加应用时,需要在配置文件settings.py中的NSTALLED_APPS 列表中手动添加上自己创建的应用名。
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',  # 启动session功能
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user.apps.UserConfig',
    'articles',
-----------------------------------------------------------
 
第二步
安装应用:
python manage.py startapp 应用名

4.路由

flask框架中:
@app.route('/')
def index():
    pass
--------------------------------------------------
django框架中:
urls.py  ------>专门设置路由
#导入视图函数
from user.views import login
urlpatterns = [
  path('login/',login),--->注意:flask中必须添加前导'/',而在django中无需添加。
  path('路由路径',视图函数名)
]

5.视图函数

views.py-------> 视图函数

def index(request)----->参数request在定义函数的时候必须传递
    #参数request此时就是一个对象
    request.path---->
    request.method-->
    return HttpResponse('hello world')
------------------------------------------------------------
注:render() ------->同flask中的render_template()

6.request的取值:

​ flask Django

GET: request.args.get(key) request. GET.get(key)

POST: request.form.get(key) request.post.get(key)

COOKIES: request.cookies.get(key) request.COOKIES.get(key)

FILES: request.files.get(key) request.FILES.get(key)

相同:

request.method

request.path

7.response对象

1.HttpResponse(‘响应内容’)

2.render(request,‘模板xxx.html’)

8.主子路由

步骤:
1.主路由中定义:
     urlpatterns = [
       path('user/',include('user.urls',namespace='user'))#http://127.0.0.1:8000/user/login/
       path('news',include('news.urls',namespace='news'))
     ]
--------------------------------------------------------------
2.在应用中添加urls.py
app_name = 'user'  ------>如果没有app_name,会报错
urlpatterns = [
  path('',index,name='index')
  path('login/',login,name='login')
]
--------------------------------------------------------------
3.使用

9.反向解析

反向解析:给一个函数名,自动的找到路径

反向解析目的:
1.超级链接,form action=''
2.重定向
---------------------------------------------------------------
              flask                             
模板:  {{url_for('login',a=1,b=2)}} 
重定向:redirect(url_for('blueprintname.视图函数名'))
---------------------------------------------------------------
              django
模板:  {%url'namespace:name'%}
代码:  reverse('namespace:name')
重定向:redirect(reverse('namespace:name'))

10.csrf中间件

在这里插入图片描述

在表单提交的时候需要加上{%csrf_token%}才能通过csrf中间件验证

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="{% url 'user:login' %}" method="post">
    {% csrf_token %}
    <p><input type="text" name="username" placeholder="输入用户名"></p>
    <p><input type="password" name="password" placeholder="输入密码"></p>
    <p><input type="submit" value="登录"></p>
</form>
</body>
</html>

11template模板

在views视图函数中:

from django.shortcuts import render


# Create your views here.

def index(request):
    data = {
        'username': 'echo',
        'age': 20,
        'height': '183cm',
        'articles': ['美女是如何修炼成的?', '焊工五级和程序员双重技能修炼术', '葵花宝典', '一阳指', '六脉神剑'],
        'desc': '<h1>我是Echo</h1>'
    }
    return render(request, 'article/index.html', context=data)
#   return render_template('article/index.html',username='',age=20,height='',articles=[])

在template模板中:

{% extends 'base.html' %}
{% block title %}
    文章首页
{% endblock %}

{% block content %}
    {% autoescape off %}
        {{ username }}  --- {{ age }}  -- {{ height }} --- {{ gender | default:'男' }}--{{ desc }}
    {% endautoescape %}
    文章内容: {{ articles | last }} ---- {{ 3.895312 | floatformat:2 }} --- {{ articles.2 }}


    {# 遍历#}
    {% for article in articles %}
        <div>{{ article }}</div>
    {% empty %}
        <div>暂无数据</div>

    {% endfor %}

    {% if age == 20 %}
        年龄等于20岁
    {% endif %}

    {% ifequal age 20 %}
        年龄等于20岁------------22222
    {% endifequal %}

    <br>

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

{% endblock %}

{% block myjs %}
    <script>
        button = document.getElementById('btn')
        button.onclick = function () {
            alert('笑到你。。。。')
        }
    </script>
{% endblock %}
模板与flask使用的对比

Tag:

​ flask Django

autoescape:{%autorscape Flase/True%}{%endautoescape%} | {%autorscape on/off%}{%endautoescape%}


for: {%for…%}…{%else%}…{%endfor%} | {%for…%}…{%empty%}…{%endfor%}


​ {% loop.index 索引%} | {% forloop.counter%}


csrf: 在flask-wtf中 CSRFProtect(app) | 中间件中默认开启了保护,{% csrf_token %}


if: {% if 条件 %} …{%else%}… {%endif%} | {% if 条件 %} …{%else%}… {%endif%}

​ 不可以使用{%ifequal %} | {% ifequal age 20 %}…{% endifequal %}


url: 无此标签 {{ url_for(‘blueprintname.endpoint’,key=value,key=value)}} | {% url ‘namespace:name’ arg1 arg2 %}

模板渲染:

Flask:
      return render_template('xxx.html',key=value,key=value,....)

     使用: 模板中{{key}}   ---->获取value值
 Django:
     return render(request,'xxx.html',context={key:value,key:value,...})

     使用: 模板中: {{key}}   ---->获取value值

12静态文件的使用

1.在settings文件中
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),]

2.在模板xxx.html页面应用静态文件:
   {%load staticfiles %}

3.在模板template中加载静态:
   <img src='{%static 'images/a1.jpg'%}' />
   <link ref='styleshoots' src='{%static 'css/mycss'%}'>
   <script ref='styleshoots' src='{%static 'js/myjs'%}'>

13.model 模型

"""
1. 定义model,自定义一个类继承models.Model

2. 添加类属性

3. 迁移 同步:
   python manage.py makemigrations  ----> 迁移   产生一个0001.initial.py
   python manage.py migrate         ----> 同步   构成数据库的映射

  注意:如果不明确声明表名: 自动生成的表名就是: appName_model名字

"""
-----------------------------------------------------------
class User(models.Model):  # 模型类
    username = models.CharField(max_length=12, unique=True)
    password = models.CharField(max_length=256)

    add_time = models.DateTimeField(default=datetime.now)
    isdelte = models.BooleanField(default=False)

    def __str__(self):
        return self.username

    class Meta:
        db_table = 'user'    
添加
添加:
  方式1:
      user = User()
    # user.username = 'lily'
    # user.password = '123456'
    # user.age = 18
    # user.gender = 'girl'
    # user.save()
  方式2# User.objects.create(username='lucy',password='13kjhfjd',age=20,gender='girl')
删除
删除:  
flask  :  db.session.delete(user对象)   db.session.commit()

Django:
单个对象的删除
user = User.objects.filter(username='lily').first()
user.delete()
多个对象 的删除:
User.objects.filter(age__gt=18).delete()
更新
更新:
  批量更新:
  User.objects.filter(isdelte=False).update(aa='123',age=22)

  单个用户:
    user = User.objects.get(pk=6)
    user.age = 18
    user.save()
查询
查询:

Flask:
     User.query.all()                               
     User.query.filter(User.uname==zhi)          
     User.query.get(id)    
-------------------------------------------
Django:
      User.objects.all()
      User.objects.filter(isdelte=False)
      User.objects.get(pk=id) 
-------------------------------------------

筛选条件:
     filter:
     CharFiled:
        users = User.objects.filter(username__startswith='l').filter(username__endswith='y')
        users = User.objects.filter(username__regex=r'^l\w+y$')

     IntegerField:
         users = User.objects.filter(age__lte=19)   小于等于19
         users = User.objects.filter(age__gte=19)   大于等于19
         users = User.objects.filter(age__range=(17,20))

     DatetimeField:

     users = User.objects.filter(add_time__month=3).order_by('-age')


     and  or  聚合函数(Q()  F()  aggregate()

14.ORM(关系模型)

ORM:

11关系:(Flask没有的)
   1                              1
   User          ---- 》      UserProfile(理解成UserProfile是User表的升级版)
常用的字段
uname                               age,gender,联系地址  全称
phone
password
 id  uname  phone  password            u_id     age   gender   address  full_name

  1   aa    1188     3477                1      18     女      beijing    sdhfjsh
user = models.OneToOneField(to='',on_delete='')   ----> 外键+唯一 = 11
 u_id  必须是外键参照user的主键,特点: 必须唯一unique

代码查询:
User ----》 Userprofile

   user.userprofile.age

Userprofile  -----> user

   userprofile.user.username

User 会使用次数较多
--------------------------------------------------------------------
1对多关系:
1 user- --> 多 Article

模型中建立一对多:
在多的那个模型中添加:

user = models.ForeignKey('User', on_delete=models.CASCADE)  # foreign key  ==one  to  many

代码:
根据1找多:
user = User.objects.get(pk=5)
user.article_set.all    ----> 获取所有的该用户发表的文章

根据多找1:

 article  = Article.objects.get(pk=2)

 article.user.username   ----> 因为user是Article模型的一个属性 ,article.user  此时的user是一个用户对象


 添加:
     添加多:
        uid = 6  # session 以后必须保证用户登录

        title = request.POST.get('title')
        desc = request.POST.get('desc')
        content = request.POST.get('content')

 删除:
    删除article
       article = Article.objects.get(pk=3)
       article.delete()

    删除用户:
      user = User.objects.get(pk=1)
      user.delete()

      on_delete=models.CASCADE   级联删除
--------------------------------------------------------------------

多对多关系:
user   ---  book
模型中添加:
# 定义一个多对多的关系
    user = models.ManyToManyField(to='User')

自动产生一个关系表:  user_id  ---> user(id) , book_id   ---> book(id)


代码:

user  ---》 book

user = User.objects.get(pk=1)

user.book_set.all()   ---->用户收藏的书有哪些


book  ----》 users

book =Book.objects.get(pk=2)

book.users.all()   ----> 2号这本书被哪些用户收藏了

15.单表

User.objects.create(username='',age=20)

  user= User(username='',)
  user.save()

  user.delete()

  User.objects.filter(gender='boy').update(age=20)


  User.objects.all()
  User.objects.get(pk=1)
  User.objects.filter(age__lt=18)

16.多表(relationship 关系)

11   1对多  多对多
--------------------------------------------------------------------
user = models.OneToOneField(to='',on_delete='')   ----> 外键+唯一 = 11

users =models.ForeignKey(to='',on_delete='')  ----> 外键  ==  1对多   User --- Article

user.article_set.all()

article.user.username

models.ManyToManyField(to='')  ----> 自动产生关系表   User --- Book

user.book_set.all()

book.users.all()

17.密码加密

使用内置加密方法:
make_password(password)---->返回加密的密码

check_password(password,加密后的密码) ----> 返回boolean

18.Cookie

设置cookie
response对象设置cookie
response.set_cookie(key,value,max_age=)

获取cookie
request.COOKIES.get(key)

删除cookie
response.delete_cookie(key)

19.session

#设置  session是一个字典类型的
request.session[key] = value #【】里面的key可以加’‘也可以不加,如果加了’‘在request.seesion.get('key')的时候也要加,如果没有加,在get的时候也不加,当不加的’‘的时候里面的key是一个变量,加了就代表着是一个字符串键名。
-------------------------------------------------------------------
#获取
request.seesion.get(key)
====================================================================
 # 获取、设置、删除Session中数据

request.session['k1']

request.session.get('k1',None)

request.session['k1'] = 123

request.session.setdefault('k1',123) # 存在则不设置

del request.session['k1']#删除某个键值对


# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()


# 用户session的随机字符串
request.session.session_key


# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()


# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")

20.邮件发送

网易邮箱:
账号:echo5438@163.com

密码:

授权码:

1.配置settings.py文件
#在settings.py文件中,配置邮件发送SMTP:
#以163邮箱为例
#在163邮箱设置中的POP3/SMTP/IMAP中将 POP3/SMTP服务,IMAP/SMTP服务 打对勾
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = 'echo5438@163.com'
EMAIL_HOST_PASSWORD = ''  # 授权码
EMAIL_USE_TLS = True
2.设置路由
在用户user的urls.py中设置:
app_name='user'
urlpatterns = [
    path('register/',register,name='register'),
    path('login/',login,name='login'),
    path('',index,name="index"),
    path('logout/',logout,name="logout"),
    path('active/',active,name='active'), #设置激活路由
]
3.设置视图函数
def register(request):
    pass
def active(request):
    pass
4.设置Template模板
#jihuo.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户激活</title>
</head>
<body>
<h3>用户激活成功</h3><a href="{% url 'user:login' %}">登录</a>

</body>
</html>
5.使用视图函数完成功能
#注册
def register(request):
    if request.method=='GET':
        return render(request,'register.html')
    else:
        username = request.POST.get('username')
        if not User.objects.filter(username = username).exists():
            password = request.POST.get('password')
            repassword = request.POST.get('repassword')
            email = request.POST.get('email')
            phone = request.POST.get('phone')
            if password==repassword:
                password = make_password(password)
                user = User.objects.create(username=username, password=password,email=email,phone=phone)
                # 发送邮件:激活用户的邮件

                msg = '''
                                  欢迎注册苏展书店!亲爱的用户请赶快激活使用吧!
                                  <a href='http://127.0.0.1:8000/active/?id=%d'>点击激活</a>
                                '''%user.id
                send_mail('书店用户激活', message='', html_message=msg, from_email=EMAIL_HOST_USER, recipient_list=[email])
                return HttpResponse('注册成功')

            else:
                return render(request,'register.html',{'msg':'密码不一致'})

        else:
            return render(request, 'register.html', {'msg': '用户名已被注册'})
--------------------------------------------------------------------
#激活
def active(request):
    uid = request.GET.get('id')
    user=User.objects.filter(pk=uid).first()
    user.isactive = True
    user.save()
    return render(request,'jihuo.html')
--------------------------------------------------------------------
#登录设置未激活限制
#登录
def login(request):
    if request.method=='GET':
        return render(request, 'login.html')
    else:
        username = request.POST.get('username')
        qw=User.objects.filter(username=username).filter(isactive=True)
        if qw.exists():
            password = request.POST.get('password')
            if check_password(password, qw.first().password):
                request.session['username'] = username
                request.session.set_expiry(60 * 15)
                return redirect(reverse('user:index'))
            else:
                return render(request,'login.html',{'msg':'密码不正确'})
        else:
            return render(request,'register.html',{'msg':'用户密码错误或者不存在或未激活'})

21.短信验证

网易云信:

账号:17664207079

密码:

1.设置路由
在用户user的urls.py中设置:
app_name='user'
urlpatterns = [
    path('sendcode/',sendcode,name='sendcode'),
    path('codelogin/',codelogin,name='codelogin')
]
2.配置视图函数
def sendcode(request):
    pass

def codelogin(request):
    pass
3.设置Template模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>发送手机验证码</title>
    <script
      src="https://code.jquery.com/jquery-3.3.1.min.js"
      integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
      crossorigin="anonymous"></script>
</head>
<body>
<form action="{% url 'user:codelogin' %}" method="post">
    {%csrf_token %}
    <p><input type="text" name="phone" placeholder="输入手机号码" id="nm"></p>
    <p><input type="text" name="code" placeholder="输入验证码"><button type="button" id="btn">获取验证码</button></p>
    <p><input type="submit" value="登录"></p>
</form>
<script>
  btn = document.getElementById('btn');
    var phone_input = document.getElementById('nm');
    btn.onclick = function () {
        var phone_number = phone_input.value;
        console.log(phone_number);
        $.getJSON('/sendcode/', {number: phone_number}, function (data) {
            console.log(data);
            alert(data.msg)
        })


    }


</script>
</body>
</html>
4.使用视图函数完成功能
#发送短信验证码
def sendcode(request):
    phone_number = request.GET.get('number')

    #准备网易云信服务器发送信息
    server_url = 'https://api.netease.im/sms/sendcode.action'

    #模拟浏览器发送请求
    appkey = ''
    nonce = '123456'
    curtime = str(time())
    appsecret = ''
    content= appsecret+nonce+curtime
    checksum = hashlib.sha1(content.encode('utf-8')).hexdigest()
    headers = {'AppKey':appkey,"Nonce":nonce,"CurTime":curtime,"CheckSum":checksum}
    body = {'mobile':phone_number}
    res = requests.post(server_url,body,headers=headers)
    result = res.text  # result是一个字符串类型  获取响应体
    result = json.loads(result)  # json.dumps(data)  dict---->string    |   json.loads(string)   string---->dict

    if result.get('code') == 200:

        check_code = result.get('obj')
        # session
        request.session['phone_number'] = check_code
        data = {
            'status': 200,
            'msg': '验证码已发送,请查收'
        }
    else:
        data = {
            'status': 500,
            'msg': '验证码发送失败'
        }
    return JsonResponse(data)

#手机验证码登录
def codelogin(request):
    if request.method == 'GET':
        return render(request, 'codelogin.html')
    else:
        phone = request.POST.get('phone')
        code = request.POST.get('code')

        check_code = request.session.get('phone_number')

        if code == check_code:
            user = User.objects.filter(phone=phone).first()
            request.session['username'] = user.username
            del request.session['phone_number']  # 删除验证码的key

            return redirect(reverse('user:index'))

22中间件

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出。

class XXX(MiddlewareMixin):
     process_request
     process_view
     process_exception
     process_response
     process_template_response

激活:settings  ---> MIDDLEWARE=[ ....]

23.自定义中间件

1. 新建一个包命名为middleware
2. 定义一个中间件的MyMiddleware.py文件
3. 定义一个类继承MiddlewareMixin      class LoginMiddleware(MiddlewareMixin):
4. 重写:
    process_request   ----> 请求
    process_view
    process_exception
    process_template_response
    process_response
---------------------------=----------------------------------------
    from django.shortcuts import render
    from django.utils.deprecation import MiddlewareMixin

    required_path = [
        '/sendtz/','/center/',
    ]

    class LoginMiddleware(MiddlewareMixin):
        def process_request(self,request):
            path = request.path
            if path in required_path:
                username = request.session.get('username')
                if not username:
                    return render(request, 'login.html')
--------------------------------------------------------------------
5. 激活中间件:settings文件中:
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',
    'middleware.MyMiddleware.HelloMiddleware',  # 激活中间件    ----->添加自定义额中间件
    'middleware.MyMiddleware.LoginMiddleware'
]

24.admin管理员用户

class UserProfile(AbstractUser):
        pass

相当于想让userprofile替换auth_user表,修改settings.py  AUTH_USER_MODEL = 'users.UserProfile'

python manage.py createsuperuser


http://127.0.0.1:8000/admin/   ---->path('admin/', admin.site.urls),
在app中admin.py中添加:

class UserAdmin(admin.ModelAdmin):
    list_display = ['username', 'email', 'phone', 'date_joined']
    search_fields = ['username', 'phone']

admin.site.register(UserProfile, UserAdmin) 激活后才能在后天显示表

25.用户的注册和登录(auth模块中函数)

前提:UserProfile(AbstractUser)

AbstractUser:

python manage.py makemigrations  ----> auth_user  ----> 保存系统用户的表

python manage.py createsuperuser

username:
email:
password:


----->auth_user

报错的话,检查下面的方法
python manage.py makemigrations  user


AUTH_USER_MODEL='app.modelName'



----->  用户登录,注册

1.注册:
    UserProfile.objects.create_user(username=username,password=password)  ----> 其中密码部分默认加密

  2.登录:
    authenticate(username=username,password=password)  ----> 返回值是:如果是认证通过,返回的就是user对象,否则返回None

    login(request,user)  ----> 将认证过得user放到login中。 保存认证的用户

    判断此用户有没有登录:
    request.user.is_atuthenticated()  -----> 返回值是:boolean :True False

  3. 注销:
     logout(request)  ---> 底层执行了:将认证的用户从request中移除,session.flush()
    
--------------------------------------------------------------------

匹配:
@login_required   ----> 进行登录验证


@login_required
def comment(request):
    return HttpResponse('欢迎进入评论页面!')

26.forms

在user文件夹中创建一个forms.py文件使用python语言来生成HTML表单标签,相当于template模板中的forms表单的功能,只不过是不在模板中了而是迁移到forms.py文件中使用python语言生成。

步骤:
1.创建forms.py文件
2.在文件中定义类:class UserForm(form.Form):
3.在类中添加属性
   #添加fields
4.使用:
在视图函数中,创建此form的对象
	userform=UserForm
5.将userform渲染model
--------------------------------------------------------------------
class UserRegisterForm(forms.Form):
    # 添加fields
    username = forms.CharField(max_length=16, min_length=6, required=True,
                               error_messages={'required': '用户名必须填写', 'max_length': '用户名最长16位',
                                               'min_length': '用户名不能少于6位'}, label='用户名',
                               widget=forms.widgets.TextInput(attrs={'class': 'a1'}))
    
    
    password = forms.CharField(max_length=16, min_length=6, required=True,
                               error_messages={'required': '密码必须填写', 'max_length': '密码最长16位',
                                               'min_length': '密码不能少于6位'}, widget=forms.widgets.PasswordInput,
                               label='密码')
    
    
    repassword = forms.CharField(max_length=16, min_length=6, required=True,
                                 error_messages={'required': '密码必须填写', 'max_length': '密码最长16位',
                                                 'min_length': '密码不能少于6位'}, widget=forms.widgets.PasswordInput,
                                 label='确认密码')
    
    
    age = forms.IntegerField(required=True, error_messages={'required': '年龄必须填写'}, label='年龄')
    # gender = forms.IntegerField(required=True, error_messages={'required': '性别必须填写'}, label='性别')
    # gender = forms.ChoiceField(choices=((1, '男'), (2, '女')), label='性别')  # 下拉列表
    
    gender = forms.ChoiceField(choices=((1, '男'), (2, '女')), widget=forms.widgets.RadioSelect, label='性别')
    
    email = forms.EmailField(required=True, error_messages={'required': '邮箱必须填写'}, label='邮箱')
    
    phone = forms.CharField(required=True, error_messages={'required': '手机号码必须填写'}, label='手机号码')

    # 用户类型的集合
    # utype_choices = UserType.objects.values_list('id','typename')  # [(1,'学生'),(2,'老师'),..]
    # utype = forms.ChoiceField(choices=utype_choices, label='用户类型')

    def __init__(self, *args, **kwargs):
        super(UserRegisterForm, self).__init__(*args, **kwargs)
        utype_choices = UserType.objects.values_list('id', 'typename')
        self.fields['utype'] = forms.ChoiceField(choices=utype_choices, label='用户类型')

    # 钩子函数
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if username.isdigit():
            raise ValidationError('用户名不能是数字')
        else:
            return username

    # 全局钩子函数
    def clean(self):
        password = self.cleaned_data.get('password')
        repassword = self.cleaned_data.get('repassword')

        if password == repassword:
            return self.cleaned_data
        else:
            raise ValidationError('两次密码不一致')  
Django内置字段:
Field
	required=Ture,				是否允许为空
	widget=None,				HTML插件
	label=None,					用于生成Label
	initial=None,				初始值
	help_text='',				帮助信息(在标签旁边显示)
	error_messages=None,		错误信息{'required':'不能为空','invalid':'格式错误'}
	show_hidden_initial=False,	是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
	validators=[],				自定义验证规则
	localize=False,				是否支持本地化
	disabled=False,				是否可以编辑
	label_suffix=None,			Label内容后缀
	
CharField(Field)
	max_length=None,			最大长度
	min_length=None,			最小长度
	strip=True,					是否移除用户输入空白
	
IntegerField(Field)
	max_value=None,				最大值
	min_value=None,				最小值
	
FloatField(IntegerField)
	....

DecimalField(IntegerField)
	max_value=None,				最大值
	min_value=None,				最小值
	max_digits=None,			总长度
	decimal_places=None,		小数位长度
	
BaseTemporalField(Field)
	input_formats=None			时间格式化
	
DateField(BaseTemporalField)	格式:2015-09-01
TimeField(BaseTemporalField)	格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12

DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...

RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}

EmailField(CharField)
    ...

FileField(Field)
    allow_empty_file=False     是否允许空文件

ImageField(FileField)
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)

URLField(Field)
    ...


BooleanField(Field)
    ...

NullBooleanField(BooleanField)
    ...

ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示


ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选

ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField



TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值

MultipleChoiceField(ChoiceField)
    ...

TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值

ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])

MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用

SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']

FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''

GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...

UUIDField(CharField)           uuid类型


Django内置插件 widget

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

27.ModelForm

Form ------>继承---->BaseForm

ModelForm---->继承---->BaseModelForm---->继承---->BaseForm

Form和model 组成为ModelForm

ModelForm------>Form + Model

在forms.py文件中
class RegisterForm(forms.ModelForm):
    # repassword = forms.CharField(max_length=16, min_length=6, required=True,
    #                              error_messages={'required': '密码必须填写', 'max_length': '密码最长16位',
    #                                              'min_length': '密码不能少于6位'}, widget=forms.widgets.PasswordInput,
    #                              label='确认密码')

    class Meta:
        model = models.User
        fields = '__all__'


# class UserLoginForm(forms.ModelForm):
#     class Meta:
#         model = models.User
#         fields = ['username', 'password']
#         # fields = '__all__'  # 获取model中的哪个字段  __all__ 表示的是所有的字段
#         # exclude = ['age', 'email', 'gender']  # 往往和__all__结合使用    exclude不想显示的字段列在列表中
#         # labels = {
#         #     'username': '账户',
#         #     'phone': '电话号码'
#         # }
#         # 明确指明密码框类型
#         widgets = {
#             'password': forms.widgets.PasswordInput,
#             # 'phone': forms.widgets.NumberInput,
#         }
#
#     # 定义用户的名字不能是纯数字
#     def clean_username(self):
#         username = self.cleaned_data.get('username')
#         if username.isdigit():
#             raise ValidationError('用户名不能是纯数字')
#         else:
#
#             return username
--------------------------------------------------------------------
class RegisterForm(forms.ModelForm):
    repassword = forms.CharField(max_length=256 ,error_messages={'required': '密码必须填写', 'max_length': '密码最长16位'},
                                 widget=forms.widgets.PasswordInput,
                                 label='确认密码')

    class Meta:
        model = models.User
        fields = '__all__'
        exclude = ['isactive']
        widgets = {
                    'password': forms.widgets.PasswordInput,
                    'phone': forms.widgets.NumberInput,
                }

        # 钩子函数

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if username.isdigit():
            raise ValidationError('用户名不能是数字')
        else:
            return username

        # 全局钩子函数

    def clean(self):
        password = self.cleaned_data.get('password')
        repassword = self.cleaned_data.get('repassword')

        if password == repassword:
            return self.cleaned_data
        else:
            raise ValidationError('两次密码不一致')
在视图函数中
在视图函数views.py中,将forms.py中的表单渲染到template模板中
def register(request):
    if request.method == 'GET':
        userform = RegisterForm()
        return render(request,'register.html',{'forms': userform})
    else:
        #获取表单数据
        userform = RegisterForm(request.POST)
        if userform.is_valid():
            # 取值  返回的是字典类型
            data = userform.cleaned_data
            username = data.get('username')
            password = data.get('password')
            repassword = data.get('repassword')
            email = data.get('email')
            phone = data.get('phone')
            if password == repassword:
                # 保存到数据库中
                user = User()
                user.username = username
                user.password = make_password(password)
                user.email = email
                user.phone = phone
                user.save()
             return HttpResponse('保存成功')
         else:
               return render(request, 'register.html', {'forms': userform})

28.忘记密码

1.设置路由
在用户user的urls.py中设置:
app_name='user'
urlpatterns = [
    path('getpass/',getpass,name='getpass')
]
2.配置视图函数
#忘记密码,找回getpass
def getpass(request):
    pass
3.设置Template模板
getpass.html
--------------------------------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>忘记密码</title>
    <script
      src="https://code.jquery.com/jquery-3.3.1.min.js"
      integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
      crossorigin="anonymous"></script>
</head>
<body>
<form action="{% url 'user:getpass' %}" method="post">
    {% csrf_token %}
    <p>手机号:<input type="text" name="phone" placeholder="请输入手机号" id="nm"></p>
    <p>验证码:<input type="text" name="code" placeholder="请输入验证码"><button type="button" id="btn">发送验证码</button></p>
    <p>新密码:<input type="password" name="newpass" placeholder="请输入新密码"></p>
    <p><input type="submit" placeholder="提交"></p>
</form>
<script>
    btn = document.getElementById('btn');
    var phone_input = document.getElementById('nm');
    btn.onclick  = function () {
        var phone_number = phone_input.value;
        $.getJSON('/sendcode/',{'number':phone_number},function (data) {
            alert(data.msg)
        })
    }
</script>

</body>
</html>
4.使用视图函数完成功能
#忘记密码,找回getpass
def getpass(request):
    if request.method == 'GET':
        return render(request,'getpass.html')
    else:
        phone_number = request.POST.get('phone')
        user = User.objects.filter(phone=phone_number)

        if user.exists():
            code = request.POST.get('code')
            newpass = request.POST.get('newpass')
            check_code = request.session.get('phone_number')

            if code == check_code:
                user = User.objects.filter(phone=phone_number).first()
                user.password = make_password(newpass)
                user.save()
                del request.session['phone_number']  # 删除验证码的key

                # return redirect(reverse('user:login'))
                return HttpResponse('修改密码成功')

29.缓存

Django提供了6种缓存方式

开发调试缓存
内存缓存
文件缓存
数据库缓存
Memcache缓存(使用python-memcached模块)
Memcache缓存(使用pylibmc模块)
经常使用的有文件缓存和Memcache缓存

数据库缓存
在settings.py中添加:
'database_cache': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }

然后执行:python manage.py createcachetable

如果想缓存信息则可以通过装饰器:
@cache_page(timeout=30)
def test_cache(request):
    pass
本地文件缓存
需要在settings.py中添加:
'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': 'c:/foo/bar',
    }

如果想缓存信息则可以通过装饰器:
@cache_page(timeout=30)
def test_cache(request):
    pass
redis缓存
步骤:
1.安装redis组件:
  pip install django-redis

2.在settings.py文件中添加:

 'redis_cache': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://用户:密码@39.106.150.87:6379/0',
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            # "PASSWORD": "yoursecret",
        }
 3. 使用缓存:
  cache = caches['redis_cache']  # redis对象   通过可以获取cache对象

  其中key就是settings.py文件中设置的'redis_cache'

 4.
    cache.set('v', '555', 60*60)      #写入key为v,值为555的缓存,有效期30分钟
    cache.has_key('v') #判断key为v是否存在
    cache.get('v')     #获取key为v的缓存   

30.Xadmin

1. 源码安装:

下载:https://github.com/sshwsfc/xadmin/tree/django2

解压:
1. 安装requirements.txt
   在黑屏终端上cd到下载的xadmin目录下
   pip install -r requirements.txt

2. 复制xadmin文件夹到项目

3. 在xadmin上面右键,mark directory as  ----> Sources Root

4. 在settings.py 添加

   INSTALLED_APPS=[
     xxx,
     'xadmin',
     'crispy_forms'
   ]
5. 设置路由:

   urlpatterns = [
    # path('admin/', admin.site.urls),
    re_path(r'xadmin/', xadmin.site.urls),
]

6.配置:
在应用中将admin.py文件重命名为:adminx.py 文件
在里面注册models
class UserAdmin:
    list_display = ['username', 'email']
    search_fields =['username']
    list_filter = ['email']


xadmin.site.register(User, UserAdmin)

在这里插入图片描述

31.原生验证码

1.配置字体

pip install pillow

将fonts文件夹复制到静态文件夹static中,
在settings.py文件中,进行字体的配置:
FONT_PATH = os.path.join(BASE_DIR, 'static/fonts/ADOBEARABIC-BOLD.OTF')
2.设置路由urls.py
from django.urls import path

from user.views import *

app_name = 'user'

urlpatterns = [
    path('register/', user_register, name='register'),
    path('login/', user_login, name='login'),
    path('getcode/', get_code, name='getcode'),
]
3.配置视图函数
def login(request):
    pass
    
def getcode(request):
    pass
4.在forms.py文件中创建表单
from django import forms


class UserLoginForm(forms.Form):
    username = forms.CharField(max_length=16, min_length=6,
                               error_messages={'max_length': '用户名不能超过16位', 'min_length': '用户名不能少于6位'})
    password = forms.CharField(max_length=16, min_length=6,
                               error_messages={'max_length': '密码不能超过16位', 'min_length': '密码不能少于6位'},
                               widget=forms.widgets.PasswordInput)

    checkcode = forms.CharField(max_length=4, min_length=4,
                                error_messages={'max_length': '验证码必须4位', 'min_length': '验证码必须4位'})

5.创建模板template
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<p>{{ msg }}</p>
<form action="{% url 'user:login' %}" method="post">
    {% csrf_token %}
    {{ forms.as_p }}
    <img src="{% url 'user:getcode' %}" id="code">
    <p><input type="submit" value="登录"></p>
</form>
<script>
    img_obj = document.getElementById('code')
    img_obj.onclick = function () {
        this.src = '{% url 'user:getcode' %}?t=' + Math.random()
    }

</script>

</body>
</html>
6.使用视图函数完成功能
def user_login(request):
    if request.method == 'GET':
        uform = UserLoginForm()
        return render(request, 'user/login.html', {'forms': uform})

    else:
        uform = UserLoginForm(request.POST)
        if uform.is_valid():
            datas = uform.cleaned_data
            form_code = datas.get('checkcode')
            store_code = request.session.get('code')
            # 比较session中code和用户输入code
            if form_code.lower() != store_code.lower():
                return render(request, 'user/login.html', {'forms': uform, 'msg': '验证码错误'})
            else:
                username = datas.get('username')
                password = datas.get('password')
                result = User.objects.filter(username=username, password=password)
                if result.exists():
                    request.session['uid'] = result.first().id
                    return HttpResponse('登录成功')
                else:
                    return render(request, 'user/login.html', {'forms': uform, 'msg': '用户名或者密码有误'})

        return HttpResponse('ok')
--------------------------------------------------------------------
--------------------------------------------------------------------
def get_code(request):
    # 初始化画笔和画布
    mode = 'RGB'
    size = (200, 80)
    red = get_color()
    green = get_color()
    blue = get_color()

    bg_color = (red, green, blue)
    image = Image.new(mode, size, color=bg_color)  # 准备画布

    draw = ImageDraw(image, mode=mode)

    font = ImageFont.truetype(font=settings.FONT_PATH, size=80)

    code = generate_code()  # 产生验证码

    # 保存在session中
    request.session['code'] = code

    # 逐个画字母
    for i in range(4):
        fill_color = (get_color(), get_color(), get_color())
        draw.text(xy=(50 * i, 0), text=code[i], font=font, fill=fill_color)
    # 设置干扰点
    for i in range(10):
        fill_color = (get_color(), get_color(), get_color())
        import random
        position = (random.randrange(201), random.randrange(81))
        draw.point(xy=position, fill=fill_color)
        # line = random.randrange(100)
        # print(line)
        # draw.line(xy=position,fill=fill_color,width=line)

    # io缓存
    bi = BytesIO()

    image.save(bi, 'png')

    return HttpResponse(bi.getvalue(), content_type='image/png')

32.captcha验证码插件

https://django-simple-captcha.readthedocs.io/en/latest/usage.html 中文文档

1.安装插件
1.pip install django-simple-captcha

2.Add captcha to the INSTALLED_APPS in your settings.py

3.Run python manage.py migrate

4.Add an entry to your 主路由urls.py:
     urlpatterns = [
          url(r'^captcha/', include('captcha.urls')),
      ]
2.设置路由
from django.urls import path

from user.views import *

app_name = 'user'

urlpatterns = [
    path('login/', user_login, name='login'),
    path('ajax_check/', ajax_check, name='ajaxcheck'),
]
3.在forms.py中生成表单
lass UserLoginForm(forms.ModelForm):
    checkcode = CaptchaField(label='验证码')

    class Meta:
        model = models.User
        fields = ['username', 'password']
        widgets = {
            'password': forms.widgets.PasswordInput
        }

--------------------------------------------------------------------
# class LoginForm(forms.Form):
#     username = forms.CharField(max_length=16, min_length=6,
#                                error_messages={'max_length': '用户名不能超过16位', 'min_length': '用户名不能少于6位'})
#     password = forms.CharField(max_length=16, min_length=6,
#                                error_messages={'max_length': '密码不能超过16位', 'min_length': '密码不能少于6位'},
#                                widget=forms.widgets.PasswordInput)
#     checkcode = CaptchaField()

4.配置视图函数
def user_login(request):
    pass
    
def ajax_check(request):
    pass
5.设置template模板
login.html
--------------------------------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<form action="{% url 'user:login' %}" method="post">
    {% csrf_token %}
    {{ forms.as_p }}
    <p><input type="submit" value="登录"></p>
</form>
<script>
    $('.captcha').css({'cursor': 'pointer'});

    $('.captcha').click(function () {
        $.getJSON('/captcha/refresh/', function (data) {
            // data 就是一个json数据
            $('.captcha').attr('src', data.image_url);
            $('#id_checkcode_0').val(data.key)

        })
    });

    // 验证验证码是否输入正确事件
    $('#id_checkcode_1').blur(function () {
        //获取文本框中输入的验证码
        var $input = $(this);
        var checkcode = $input.val();
        var keyvalue = $('#id_checkcode_0').val();

        $.getJSON('{% url 'user:ajaxcheck' %}', {checkcode: checkcode, keyvalue: keyvalue}, function (data) {
            {#$('#captcha_status').html('')#}
            $input.next('#captcha_status').remove()
            if (data.status == 1) {

                $input.after("<span id='captcha_status'>验证码正确 </span>")
            } else {
                $input.after("<span id='captcha_status'>验证码错误 </span>")
            }
        });
    });

</script>
</body>
</html>
6.使用视图函数完成相应功能
def user_login(request):
    if request.method == 'GET':
        uform = UserLoginForm()
        return render(request, 'login.html', {'forms': uform})
    else:
        pass

--------------------------------------------------------------------
def ajax_check(request):
    if request.is_ajax():
        checkcode = request.GET.get('checkcode')
        keyvalue = request.GET.get('keyvalue')
        cs = CaptchaStore.objects.filter(response=checkcode.lower(), hashkey=keyvalue)
        if cs.exists():
            json_data = {
                'status': 1
            }
        else:
            json_data = {
                'status': 0
            }
        return JsonResponse(json_data)
    else:
        json_data = {
            'status': 0
        }
        return JsonResponse(json_data)

33.分页器:

1.设置路由
path('index/', user_index, name='index')
2.配置视图函数
def user_index(request):
    users = User.objects.all()
    paginator = Paginator(users, 3)  # 分页器对象
    # 分页器对象属性:
    print(paginator.count)  # 获取的总记录数
    print(paginator.num_pages)  # 一共分了几页
    print(paginator.page_range)  # 页码范围

    page = request.GET.get('page', 1)
    try:
        page = paginator.page(number=page)  # 通过分页器对象获取指定的页码数据
        # print(page)
        # print(page.object_list)  # 该页的所有对象  <QuerySet [<User: tom>, <User: steven>, <User: qizhi>]>
        # print(page.has_next())  # 有没有下一页   True
        # print(page.has_previous())  # 有没有上一页  True
        # print(page.next_page_number())  # 获取下一页的页码值
        # print(page.previous_page_number())  # 获取上一页的页码值
        # print(page.number)  # 当前页码数
        # print(page.paginator.num_pages)  # 一共是几页
    except EmptyPage:
        page = paginator.page(number=1)
    except PageNotAnInteger:
        page = paginator.page(number=paginator.num_pages)

    return render(request, 'index.html', {'page': page})

3.设置模板template
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户首页</title>
</head>
<body>
<table border="1" width="40%">
    {% for user in page.object_list.all %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ user.username }}</td>
            <td>{{ user.email }}</td>
            <td>
                <a href="#">删除</a>
                <a href="#">更新</a>
            </td>
        </tr>
    {% endfor %}


</table>
<div>
    <a href="{% url 'user:index' %}?page=

            {% if page.has_previous %}{{ page.previous_page_number }}{% else %}1{% endif %} ">上一页</a> {{ page.number }}/{{ page.paginator.num_pages }}
    <a href="{% url 'user:index' %}?page=
            {% if page.has_next %}{{ page.next_page_number }} {% else %} {{ page.paginator.num_pages }} {% endif %}">下一页</a>
</div>
</body>
</html>

34.文件上传

1.模型models中配置:
# models.FileField(upload_to='相对路径')  可以保存任意的文件  图片  文本  ..txt  png  jpg pdf ...
    # media 目录  media/user/icon     user/2019/4/aaa.jpg
    icon = models.ImageField(upload_to='user/%Y/%m', verbose_name='用户头像')
2.settings.py中配置:
settings配置:ImageField(upload_to=''----->media

    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
3.设置上传文件路由
urlpatterns = [
    path('admin/', admin.site.urls),
    path('register/', user_register, name='register'),
    path('showicon/', show_icon, name='showicon'),
    # path('media/<int:id>')   media/user/2019/04/shjf.png   path = user/2019/04/shjf.png
    re_path(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
]
4.使用forms完成验证上传
使用forms完成验证上传:
        class UserRegisterForm(forms.ModelForm):
    repassword = forms.CharField(max_length=12, error_messages={'max_length': '密码不能超过12位'}, label='确认密码',
                                 widget=forms.widgets.PasswordInput)

    class Meta:
        model = User
        fields = '__all__'
        widgets={
            'password':forms.widgets.PasswordInput
        }
5.设置模板
 template:
 register.html
       <form action="{% url 'register' %}" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        {{ forms.as_p }}
        <p><input type="submit" value="注册"></p>
    </form>
    <p>{{ msg }}</p>
--------------------------------------------------------------------
show.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>显示</title>
</head>
<body>
<table>
    <div>{{ MEDIA_URL }}</div>
 显示图片:
    {% for user in users %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ user.username }}</td>

            <td><img src="{{ MEDIA_URL }}{{ user.icon }}" alt=""></td>
        </tr>
    {% endfor %}


</table>

</body>
</html>
--------------------------------------------------------------------
注:
想让模板识别MEDIA_URL

   在settings.py 添加:
    TEMPLATES=[
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                # 让模板识别{{MEDIA_URL}}
                'django.template.context_processors.media'
            ],
        },
    },
]
6.配置视图函数完成功能
def user_register(request):
    if request.method == 'GET':
        rform = UserRegisterForm()
        return render(request, 'register.html', {'forms': rform})
    else:
        print(request.POST)
        print(request.FILES)

        # rform = UserRegisterForm(request.POST, request.FILES)
        # print(rform)
        # if rform.is_valid():
        #     datas = rform.cleaned_data
        #     password = datas.get('password')
        #     repassword = datas.get('repassword')
        #     if password == repassword:
        #         rform.save()
        #     else:
        #         return render(request, 'register.html', {'forms': rform, 'msg': '密码不一致'})
        
        #手动保存:
        image_object = request.FILES.get('icon')
        print(type(image_object))
        print(image_object.name)  # 获取文件的名称

        with open(os.path.join(MEDIA_ROOT, 'user', image_object.name), 'wb') as fw:
            for chunk in image_object.chunks():
                fw.write(chunk)

        #  username  password  age ,gender  icon

        # User.objects.create(username=username,password=password,...,icon=os.path.join('user',文件名))

        return HttpResponse('文件保存完毕')
--------------------------------------------------------------------

# 显示头像:
def show_icon(request):
    users = User.objects.all()

    return render(request, 'show.html', {'users': users})

35.富文本

editor富文本下载:https://ueditor.baidu.com/doc/

将下载压缩包解压之后的文件夹重命名为ueditor,然后放到静态文件夹static中

1.建立model模型
class CommentTest(models.Model):
    content = models.TextField(verbose_name='评论',default='')

    def __str__(self):
        return self.content

    class Meta:
        db_table = 'comment_test'
        verbose_name = '评论表'
        verbose_name_plural = verbose_name
2.设置路由
app_name = 'user'

urlpatterns = [
  path('editor/', show_editor, name='editor'),
  path('comment/', send_comment, name='comment')
]
3.定义视图函数
def show_editor(request):
  pass

def send_comment(request):
  pass
4.建立editor.html模板
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>富文本编辑器</title>
    <!-- 配置文件 -->
    <script type="text/javascript" src="{% static 'ueditor/ueditor.config.js' %}"></script>
    <!-- 编辑器源码文件 -->
    <script type="text/javascript" src="{% static 'ueditor/ueditor.all.js' %}"></script>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <style>
        .a1 {
            border: 1px solid black;
            padding: 10px;
            margin-bottom: 5px;
        }
    </style>
</head>
<body>
<div style="width: 100%;height: 1000px;border: 1px solid gray">
    {% for comment in comments %}
        <div class="a1">
            {{ comment.content |safe }}
        </div>
    {% endfor %}


</div>


<!-- 加载编辑器的容器 -->
<script id="container" name="content" type="text/plain">
</script>

<button id="btn">发表评论</button>
<!-- 实例化编辑器 -->
<script type="text/javascript">
    var ue = UE.getEditor('container', {autoHeight: false});

    ue.ready(function () {
        ue.setContent('<h1>hello</h1>')
    })

    $(function () {
        $('#btn').click(function () {
            console.log(ue.getContentTxt())
            console.log(ue.getContent())
            var content = ue.getContent();
            $.getJSON('{% url 'user:comment' %}', {content: content}, function (data) {
                if (data.status == 200) {
                    // 改变请求的路径
                    window.location.href = '{% url 'user:editor' %}'
                } else {
                    alert('发表失败!')
                }
            });
        })
    });

</script>

</body>
</html>
5.使用视图函数完成功能
# 显示富文本
def show_editor(request):

    comments = CommentTest.objects.all()

    return render(request, 'editor.html', {'comments': comments})
--------------------------------------------------------------------
# 发送评论
def send_comment(request):

    content = request.GET.get('content')
    comment = CommentTest.objects.create(content=content)
    if comment:
        data = {
            'status': 200
        }
    else:
        data = {
            'status': 500
        }
    return JsonResponse(data)

36.Celery异步加载

1.简介

Celery是一个用Python开发的异步的分布式任务调度模块

当用户触发的一个操作需要较长时间才能执行完成时,可以把它作为任务交给Celery去异步执行,执行完再返回给用户。这段时间用户不需要等待,提高了网站的整体吞吐量和响应时间。

2.Celery有一下5个核心角色

Task
就是任务,有异步任务和定时任务
Broker
中间人,接收生产者发来的消息即Task,将任务存入队列。任务的消费者是Worker。Celery本身不提供队列服务,推荐用Redis或RabbitMQ实现队列服务。
Worker
执行任务的单元,它实时监控消息队列,如果有任务就获取任务并执行它。
Beat
定时任务调度器,根据配置定时将任务发送给Broker。
Backend
用于存储任务的执行结果

pip install redis

pip install celery

pip install celery-with-redis

3.配置步骤:
  1. settings:
BROKER_URL = 'redis://127.0.0.1:6379/0'
# celery 结果返回, 可用于跟踪结果
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0'  # djang-db

# 配置celery内容 消息的格式
CELERY_ACCEPT_CONTENT = ['application/json', ]

CELERY_TASK_SERIALIZER = 'json'

CELERY_RESULT_SERIALIZER = 'json'

# celery的时区设置
CELERY_TIMEZONE = TIME_ZONE

在settings同级的目录中定义:celery.py

import os

from celery import Celery

from djangoday9 import settings

project_name = os.path.split(os.path.abspath('.'))[-1]

print(project_name)

project_settings = '%s.settings' % project_name

# 设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', project_settings)
# 实例化celery
app = Celery(project_name)

# 使用django的配置文件进行配置
app.config_from_object('django.conf:settings')
  1. 在同级的__init__.py文件中添加:
from __future__ import absolute_import,unicode_literals

from .celery import app as celery_app
  1. 在对应的app中添加task.py

    user —> task.py

    article---->task.py

    news ----->task.py

import time

from celery import shared_task


# 往往都是耗时的任务
@shared_task
def sendmail(email):
    print('start send email to %s' % email)
    time.sleep(5)
    print('success')
    return True
  1. 启动任务
 path('',index)  ----> 首页: http://127.0.0.1:8000/

 def index(request):
    # 耗时任务   delay() 调用任务
    ret=sendmail.delay('6563457@qq.com')   # 悄悄的将任务交给一个线程默默的后台执行
    print(ret.task_id)

    # 做数据库的查询
    users = User.objects.all()

    return render(request, 'index.html', {'users': users})
4.补充

使用orm数据库 mysql数据

pip install django-celery

在INSTALL_APPS=[
…,
‘djcelery’

]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值