前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Django】 开发:补充知识

【Django】 开发:补充知识

作者头像
杨丝儿
发布2022-02-18 15:50:24
6.4K0
发布2022-02-18 15:50:24
举报
文章被收录于专栏:杨丝儿的小站

有需要上网现查现学的东西。

分页

  • 分页是指在web页面有大量数据需要显示,为了阅读方便在每个页页中只显示部分数据。
  • 好处:
    1. 方便阅读
    2. 减少数据提取量,减轻服务器压力。
  • Django提供了Paginator类可以方便的实现分页功能
  • Paginator类位于django.core.paginator 模块中。

Paginator对象

  • 负责分页数据整体的管理
  • 对象的构造方法
    • paginator = Paginator(object_list, per_page)
    • 参数
      • object_list 需要分类数据的对象列表
      • per_page 每页数据个数
    • 返回值:
      • Paginator的对象
  • Paginator属性
    • count:需要分类数据的对象总数
    • num_pages:分页后的页面总数
    • page_range:从1开始的range对象, 用于记录当前面码数
    • per_page 每页数据的个数
  • Paginator方法
    • page(number)
      • 参数 number为页码信息(从1开始)
      • 返回当前number页对应的页信息
      • 如果提供的页码不存在,抛出InvalidPage异常
  • Paginator异常exception
    • InvalidPage:总的异常基类,包含以下两个异常子类
      • PageNotAnInteger:当向page()传入一个不是整数的值时抛出
      • EmptyPage:当向page()提供一个有效值,但是那个页面上没有任何对象时抛出

Page对象

  • 负责具体某一页的数据的管理
  • 创建对象

Paginator 对象的 page () 方法返回 Page 对象

代码语言:javascript
复制
page = paginator.page(页码)
  • Page 对象属性

object_list:当前页上所有数据对象的列表

number:当前页的序号,从 1 开始

paginator:当前 page 对象相关的 Paginator 对象

  • Page 对象方法

has_next ():如果有下一页返回 True

has_previous ():如果有上一页返回 True

has_other_pages ():如果有上一页或下一页返回 True

next_page_number ():返回下一页的页码,如果下一页不存在,抛出 InvalidPage 异常

previous_page_number ():返回上一页的页码,如果上一页不存在,抛出 InvalidPage 异常

len ():返回当前页面对象的个数

  • 说明:

Page 对象是可迭代对象,可以用 for 语句来 访问当前页面中的每个对象

  • 参考文档 https://docs.djangoproject.com/en/2.2/topics/pagination/
  • 分页示例:

视图函数

代码语言:javascript
复制
from django.core.paginator import Paginato
def book(request):  
    bks = Book.objects.all()
    paginator = Paginator(bks, 10)
    cur_page = request.GET.get('page', 1)  # 得到默认的当前页
    page = paginator.page(cur_page)
    return render(request, 'bookstore/book.html', locals())

模板设计

代码语言:javascript
复制
    <html>
    <head>
        <title>分页显示</title>
    </head>
    <body>
    {% for b in page %}
        <div>{{ b.title }}</div>
    {% endfor %}
    
    {% if page.has_previous %}
    <a href="{% url 'book' %}?page={{ page.previous_page_number }}">上一页</a>
    {% else %}
    上一页
{% endif %}
    
    {% for p in paginator.page_range %}
        {% if p == page.number %}
            {{ p }}
        {% else %}
            <a href="{% url 'book' %}?page={{ p }}">{{ p }}</a>
        {% endif %}
{% endfor %}
    
    {% if page.has_next %}
    <a href="{% url 'book' %}?page={{ page.next_page_number }}">下一页</a>
    {% else %}
    下一页
    {% endif %}
    </body>
</html>

文件下载

Django可直接在视图函数中生成csv文件 并响应给浏览器

代码语言:javascript
复制
import csv
from django.http import HttpResponse
from .models import Book

def make_csv_view(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="mybook.csv"'
	all_book = Book.objects.all()
    writer = csv.writer(response)
    writer.writerow(['id', 'title'])
    for b in all_book:    
    	writer.writerow([b.id, b.title])

    return response
  • 响应获得一个特殊的MIME类型text / csv。这告诉浏览器该文档是CSV文件,而不是HTML文件
  • 响应会获得一个额外的Content-Disposition标头,其中包含CSV文件的名称。它将被浏览器用于“另存为…”对话框
  • 对于CSV文件中的每一行,调用writer.writerow,传递一个可迭代对象,如列表或元组。

文件上传

  • 文件上传必须为 POST 提交方式
  • 表单 <form> 中文件上传时必须有带有 enctype="multipart/form-data" 时才会包含文件内容数据。
  • 表单中用 <input type="file" name="xxx"> 标签上传文件

名字 xxx 对应 request.FILES['xxx'] 对应的内存缓冲文件流对象。可通能过 request.FILES['xxx'] 返回的对象获取上传文件数据

file=request.FILES['xxx'] file 绑定文件流对象,可以通过文件流对象的如下信息获取文件数据

file.name 文件名

file.file 文件的字节流数据

  • 上传文件的表单书写方式
代码语言:javascript
复制
<!-- file: index/templates/index/upload.html -->
<html>
<head>
    <meta charset="utf-8">
    <title>文件上传</title>
</head>
<body>
    <h3>上传文件</h3>
    <form method="post" action="/test_upload" enctype="multipart/form-data">
        <input type="file" name="myfile"/><br>
        <input type="submit" value="上传">
    </form>
</body>
</html>
  • 在 setting.py 中设置 MEDIA 相关配置;Django 把用户上传的文件,统称为 media 资源
代码语言:javascript
复制
# file : settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  • 在当前项目文件夹下创建 media 文件夹
代码语言:javascript
复制
$ mkdir media
  • 上传文件的视图处理函数 方案 1 传统写入
代码语言:javascript
复制
# file views.py
from django.http import HttpResponse
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
import os

@csrf_exempt
def upload_view(request):
    if request.method == 'GET':
        return render(request, 'test_upload.html')
    elif request.method == "POST":
        a_file = request.FILES['myfile']
        print("上传文件名是:", a_file.name)
        filename =os.path.join(settings.MEDIA_ROOT, a_file.name)
        with open(filename, 'wb') as f:
            data = a_file.file.read()
            f.write(data)  
        return HttpResponse("接收文件:" + a_file.name + "成功")
  • 上传文件的视图处理函数 方案 2 借助 orm
代码语言:javascript
复制
#test_upload/models.py
from django.db import models
  
# Create your models here.
class Content(models.Model):

    desc = models.CharField(max_length=100)
    myfile = models.FileField(upload_to='myfiles')

#test_upload/views.py
from test_upload.models import *
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def upload_view_dj(request):
    if request.method == 'GET':
        return render(request, 'test_upload.html')
    elif request.method == 'POST':
        title = request.POST['title']
        a_file = request.FILES['myfile']
        Content.objects.create(desc=title,myfile=a_file)
        return HttpResponse('----upload is ok-----')
  • 若要在浏览器中访问 上传的资源,runserver 环境下,需要在项目得主路由下添加 media 路由的绑定
代码语言:javascript
复制
  from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

浏览器可以访问 http://127.0.0.1:8000/media/xxxx

Django中的用户认证 (使用Django认证系统)

  • Django带有一个用户认证系统。 它处理用户账号、组、权限以及基于cookie的用户会话。
  • 作用:
    1. 添加普通用户和超级用户
    2. 修改密码
  • 文档参见
  • User模型类
    • 位置: from django.contrib.auth.models import User
    • 默认user的基本属性有:

auth基本模型操作:

  • 创建用户

创建普通用户 create_use

代码语言:javascript
复制
from django.contrib.auth.models import Use
user = User.objects.create_user(username='用户名', password='密码', email='邮箱',...)
  • 创建超级用户 create_superuse
代码语言:javascript
复制
from django.contrib.auth.models import Use
user = User.objects.create_superuser(username='用户名', password='密码', email='邮箱',...)
  • 删除用户
代码语言:javascript
复制
from django.contrib.auth.models import Use
try:
    user = User.objects.get(username='用户名')
    user.is_active = False  # 记当前用户无效
    user.save()
    print("删除普通用户成功!")
except:
    print("删除普通用户失败")
  • 修改密码 set_password
代码语言:javascript
复制
from django.contrib.auth.models import Use
try:
    user = User.objects.get(username='xiaonao')
    user.set_password('654321')
    user.save()
    return HttpResponse("修改密码成功!")
except:
    return HttpResponse("修改密码失败!")
  • 检查密码是否正确 check_password
代码语言:javascript
复制
  from django.contrib.auth.models import Use
try:
    user = User.objects.get(username='xiaonao')
    if user.check_password('654321'):  # 成功返回True,失败返回False
        return HttpResponse("密码正确")
    else:
        return HttpResponse("密码错误")
except: 
    return HttpResponse("没有此用户!")

auth扩展字段

如果需要在默认auth表上扩展新的字段,如phone

  1. 添加新的应用
  2. 定义模型类 继承 AbstractUser
  3. settings.py中 指明 AUTH_USER_MODEL = ‘应用名.类名’
代码语言:javascript
复制
#models.py案例
from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.
class UserInfo(AbstractUser):

    phone = models.CharField(max_length=11, default='')
    
#settings.py添加配置
AUTH_USER_MODEL = 'user.UserInfo'

#添加用户
from user.models import UserInfo
UserInfo.objects.create_user(username='guoxiao', password='123456', phone='13488871101')

电子邮件发送

  • 利用QQ邮箱发送电子邮件
  • django.core.mail 子包封装了 电子邮件的自动发送SMTP协议
  • 前其准备:
    1. 申请QQ号
    2. 用QQ号登陆QQ邮箱并修改设置
      • 用申请到的QQ号和密码登陆到 https://mail.qq.com/
      • 修改 QQ邮箱->设置->帐户->“POP3/IMAP......服务”
    3. 设置Django服务器端的,用简单邮件传输协议SMTP(Simple Mail Transfer Protocol) 发送电子邮件
  • settings.py 设置
代码语言:javascript
复制
# 发送邮件设置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 固定写法
EMAIL_HOST = 'smtp.qq.com' # 腾讯QQ邮箱 SMTP 服务器地址
EMAIL_PORT = 25  # SMTP服务的端口号
EMAIL_HOST_USER = 'xxxx@qq.com'  # 发送邮件的QQ邮箱
EMAIL_HOST_PASSWORD = '******'  # 在QQ邮箱->设置->帐户->“POP3/IMAP......服务” 里得到的在第三方登录QQ邮箱授权码
EMAIL_USE_TLS = True  # 与SMTP服务器通信时,是否启动TLS链接(安全链接)默认false

视图函数中

代码语言:javascript
复制
from django.core import mail
mail.send_mail(
            subject,  #题目
            message,  # 消息内容
            from_email,  # 发送者[当前配置邮箱]
            recipient_list=['xxx@qq.com'],  # 接收者邮件列表
            )

项目部署

  • 项目部署是指在软件开发完毕后,将开发机器上运行的开发板软件实际安装到服务器上进行长期运行
  • 部署要分以下几个步骤进行

在安装机器上安装和配置同版本的环境

  1. django 项目迁移
  2. $ sudo scp 当前项目源代码 远程主机地址和文件夹
代码语言:javascript
复制
sudo scp /home/tarena/django/mysite1 root@88.77.66.55:/home/root/xxx
请输入root密码:

3. 用 uwsgi 替代 python3 manage.py runserver 方法启动服务器

4. 配置 nginx 反向代理服务器

5.用 nginx 配置静态文件路径,解决静态路径问题

uWSGI 网关接口配置 (ubuntu 18.04 配置)

  • WSGI (Web Server Gateway Interface) Web 服务器网关接口,是 Python 应用程序或框架和 Web 服务器之间的一种接口,被广泛使用
  • 使用 python manage.py runserver 通常只在开发和测试环境中使用。
  • 当开发结束后,完善的项目代码需要在一个高效稳定的环境中运行,这时可以使用 WSGI
  • uWSGI 是 WSGI 的一种,它实现了 http 协议 WSGI 协议 以及 uwsgi 协议
  • 安装 uWSGI

终端输入如下命令

代码语言:javascript
复制
sudo pip3 install uwsgi==2.0.18 -i https://pypi.tuna.tsinghua.edu.cn/simple/

检查是否安装成功

代码语言:javascript
复制
sudo pip3 freeze|grep -i 'uwsgi'
#如果成功安装,则会输出
uWSGI==2.0.18
  • 配置 uWSGI
  • 添加配置文件 项目同名文件夹/uwsgi.ini

如: mysite1/mysite1/uwsgi.ini

代码语言:javascript
复制
    [uwsgi]
    # 套接字方式的 IP地址:端口号
    # socket=127.0.0.1:8000
    # Http通信方式的 IP地址:端口号
    http=127.0.0.1:8000
    # 项目当前工作目录
    chdir=/home/tarena/.../my_project 这里需要换为项目文件夹的绝对路径
    # 项目中wsgi.py文件的目录,相对于当前工作目录
    wsgi-file=my_project/wsgi.py
    # 进程个数
    process=4
    # 每个进程的线程个数
    threads=2
    # 服务的pid记录文件
    pidfile=uwsgi.pid
    # 服务的目志文件位置
    daemonize=uwsgi.log
    # 开启主进程管理模式
master=true
  • 修改 settings.py 将 DEBUG=True 改为 DEBUG=False
  • 修改 settings.py 将 ALLOWED_HOSTS = [] 改为 ALLOWED_HOSTS = [‘网站域名’] 或者 [‘服务监听的 ip 地址’]
  • uWSGI 的运行管理

启动 uwsgi

代码语言:javascript
复制
$ 进入到项目同名文件夹下 【即settings.py所在目录】
$ sudo uwsgi --ini uwsgi.ini

停止 uwsgi

代码语言:javascript
复制
$ 进入到项目同名文件夹下 【即settings.py所在目录】
$ sudo uwsgi --stop uwsgi.pid

说明:

  • 当 uwsgi 启动后,当前 django 项目的程序已变成后台守护进程,在关闭当前终端时此进程也不会停止。
  • 若执行 stop 操作失败,则需要执行如下操作杀死进程
代码语言:javascript
复制
ps aux|grep 'uwsgi'  -> 查看uwsgi进程

tarena   103408  0.0  0.9 137172 39984 ?        S    10:02   0:01 uwsgi --ini uwsgi.ini
tarena   103410  0.0  0.9 436200 38552 ?        Sl   10:02   0:00 uwsgi --ini uwsgi.ini

ps -ef | grep 'uwsgi' | grep -v grep | awk '{print $2}' | xargs sudo kill -9

测试:

  • 在浏览器端输入 http://127.0.0.1:8000 进行测试
  • 注意,此时端口号为 8000

nginx 及反向代理配置

  • Nginx 是轻量级的高性能 Web 服务器,提供了诸如 HTTP 代理和反向代理、负载均衡、缓存等一系列重要特性,在实践之中使用广泛。
  • C 语言编写,执行效率高
  • nginx 作用
  • 负载均衡, 多台服务器轮流处理请求
  • 反向代理
  • 原理:
  • 客户端请求 nginx, 再由 nginx 将请求转发 uWSGI 运行的 django
  • ubuntu 下 nginx 安装 $ sudo apt install nginx
代码语言:javascript
复制
vim /etc/apt/sources.list
更改国内源
sudo apt-get update
  • nginx 配置
  • 修改 nginx 的配置文件 /etc/nginx/sites-enabled/default
代码语言:javascript
复制
# 在server节点下添加新的location项,指向uwsgi的ip与端口。
server {
    ...
    location / {
        uwsgi_pass 127.0.0.1:8000;  # 重定向到127.0.0.1的8000端口
        include /etc/nginx/uwsgi_params; # 将所有的参数转到uwsgi下
    }
    ...
}
nginx 服务控制

SHELL
1
2
3
$ sudo /etc/init.d/nginx start|stop|restart|status
# 或
$ sudo service nginx start|stop|restart|status

通过 start,stop,restart,status 可能实现 nginx 服务的启动、停止、重启、操作

  • 修改 uWSGI 配置

修改项目同名文件夹/uwsgi.ini 下的 Http 通信方式改为 socket 通信方式

代码语言:javascript
复制
[uwsgi]
# 去掉如下
# http=127.0.0.1:8000
# 改为
socket=127.0.0.1:8000
  • 重启 uWSGI 服务
代码语言:javascript
复制
进入到 项目同名文件夹下
$ sudo uwsgi --stop uwsgi.pid
$ sudo uwsgi --ini uwsgi.ini

测试:

在浏览器端输入 http://127.0.0.1 进行测试

注意 :

1,此时端口号为 80 (nginx 默认值)

2,Django 中有任何修改 需要重启 uwsgi , 否则修改不生效

nginx 配置静态文件路径

  • 创建新路径 - 主要存放 Django 所有静态文件 如: /home/tarena/ 项目名_static/
  • 在 Django settings.py 中添加新配置
代码语言:javascript
复制
STATIC_ROOT = '/home/tarena/项目名_static/static  
#注意 此配置路径为 存放所有正式环境中需要的静态文件
  • 进入项目,执行 python3 manage.py collectstatic 。执行该命令后,Django 将项目重所有静态文件 复制到 STATIC_ROOT 中 ,包括 Django 内建的静态文件【如 admin 后台的样式】
  • Nginx 配置中添加新配置
代码语言:javascript
复制
# file : /etc/nginx/sites-enabled/default
# 新添加location /static 路由配置,重定向到指定的 第一步创建的路径即可
server {
    ...
    location /static {
        # root 第一步创建文件夹的绝对路径,如:
         root /home/tarena/项目名_static;          
    }
    ...      
}

404/500 界面

  • 在模板文件夹内添加 404.html 模版,当视图触发 Http404 异常时将会被显示
  • 404.html 仅在发布版中 (即 setting.py 中的 DEBUG=False 时) 才起作用
  • 当向应处理函数触发 Http404 异常时就会跳转到 404 界面
代码语言:javascript
复制
from django.http import Http404
def xxx_view( ):
    raise Http404  # 直接返回404

邮件告警

报错邮件中会显示一些错误的追踪,这些错误追踪中会出现如 password等敏感信息,Django已经将配置文件中的敏感信息 过滤修改为 多个星号,但是用户自定义的视图函数需要用户手动过滤敏感信息

1,视图函数中的局部变量

代码语言:javascript
复制
from django.views.decorators.debug import sensitive_variables

@sensitive_variables('user', 'pw', 'cc')
def process_info(user):
    pw = user.pass_word
    cc = user.credit_card_number
    name = user.name
    ...
#注意:
#1 若报错邮件中牵扯到user,pw,cc等局部变量的值,则会将其替换成  *****, 而 name 变量还显示其真实值
#2 多个装饰器时,需要将其放在最顶部
#3 若不传参数,则过滤所有局部变量的值

2,POST提交中的数据

代码语言:javascript
复制
from django.views.decorators.debug import sensitive_post_parameters

@sensitive_post_parameters('password', 'username')
def index(request):
    s = request.POST['username'] + request.POST['abcd']
	#'abcd' 并不存在,此时引发error
#POST中 username 及 password的值会被替换成  ******
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分页
    • Paginator对象
      • Page对象
      • 文件下载
      • 文件上传
      • Django中的用户认证 (使用Django认证系统)
        • auth基本模型操作:
          • auth扩展字段
          • 电子邮件发送
          • 项目部署
            • 邮件告警
            相关产品与服务
            云服务器
            云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档