文件下载

  • Django可直接在视图函数中生成csv文件 并响应给浏览器
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文件的字节流数据
<!-- 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资源
# file : settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  • 在当前项目文件夹下创建 media 文件夹
mkdir media
  • 上传文件的视图处理函数方案传统写入
# 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 + "成功")
  • 上传文件的视图处理函数方案借助orm
#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路由的绑定
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中的用户认证

User模型类

  • 位置: from django.contrib.auth.models import User
属性名 类型
username 用户名
password 密码
email 邮箱
first_name
last_name
is_superuser 是否是管理员帐号(/admin)
is_staff 是否可以访问admin管理界面
is_active 是否是活跃用户,默认True。一般不删除用户,而是将用户的is_active设为False。
last_login 上一次的登录时间
date_joined 用户创建的时间

auth基本模型操作

  • 创建普通用户create_user
from django.contrib.auth.models import User
user = User.objects.create_user(username='用户名', password='密码', email='邮箱',...)
  • 创建超级用户create_superuser
from django.contrib.auth.models import User
user = User.objects.create_superuser(username='用户名', password='密码', email='邮箱',...)
  • 删除用户
from django.contrib.auth.models import User
try:
    user = User.objects.get(username='用户名')
    user.is_active = False  # 记当前用户无效
    user.save()
    print("删除普通用户成功!")
except:
    print("删除普通用户失败")
  • 修改密码set_password
from django.contrib.auth.models import User
try:
    user = User.objects.get(username='xiaonao')
    user.set_password('654321')
    user.save()
    return HttpResponse("修改密码成功!")
except:
    return HttpResponse("修改密码失败!")
  • 检查密码是否正确check_password
from django.contrib.auth.models import User
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 = '应用名.类名'

#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添加配置
# 使用自定义的用户模型替换django默认的用户模型
# 修改配置文件后 如果之前已经进行过数据库迁移 需要重新迁移
# 1. 删除所有应用中生成的迁移文件000x_xxxx.py
# 2. 删除数据库 重新创建数据库
# 3. 重新生成迁移文件 重新迁移到数据库
AUTH_USER_MODEL = 'user.UserInfo'

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

登录验证

# http://127.0.0.1:8000/user/test
# path('test/', views.test_login),
# login_required 如果用户没有登录 直接重定向到settings.py中LOGIN_URL指定的路由 完成登录操作

from django.contrib.auth.decorators import login_required


@login_required
def test_login(request):
    # django向request中添加的一个用户对象  如果没有登录时值为AnonymousUser
    # 如果登录成功后 取值为登录中的对象
    user = request.user
    print(user, type(user))
    return HttpResponse('ok')

电子邮件发送

  • 利用QQ邮箱发送电子邮件
  • django.core.mail 子包封装了 电子邮件的自动发送SMTP协议
  • settings.py 设置
# 发送邮件设置
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
  • 视图函数中
from django.core import mail
mail.send_mail(
            subject,  #题目
            message,  # 消息内容
            from_email,  # 发送者[当前配置邮箱]
            recipient_list=['xxx@qq.com'],  # 接收者邮件列表
            )

项目部署

  • 项目部署是指在软件开发完毕后,将开发机器上运行的开发板软件实际安装到服务器上进行长期运行
  • 部署要分以下几个步骤进行
  1. 在安装机器上安装和配置同版本的环境
  2. django 项目迁移
  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协议
sudo pip3 install uwsgi==2.0.18 -i https://pypi.tuna.tsinghua.edu.cn/simple/

#检查是否安装成功
sudo pip3 freeze|grep -i 'uwsgi'
#如果成功安装,则会输出
uWSGI==2.0.18
  • 配置uWSGI
  • 添加配置文件 项目同名文件夹/uwsgi.ini
  • 如: mysite1/mysite1/uwsgi.ini
[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
  • uWSGI的运行管理
  • 正式环境中需要修改settings.py将 DEBUG=True 改为DEBUG=False
  • 正式环境中需要修改settings.py将ALLOWED_HOSTS = [] 改为ALLOWED_HOSTS = ['网站域名'] 或者 ['服务监听的ip地址']
#启动 uwsgi
$ 进入到项目同名文件夹下 【即settings.py所在目录】
$ sudo uwsgi --ini uwsgi.ini

#停止 uwsgi
$ 进入到项目同名文件夹下 【即settings.py所在目录】
$ sudo uwsgi --stop uwsgi.pid
  • 当uwsgi 启动后,当前django项目的程序已变成后台守护进程,在关闭当前终端时此进程也不会停止。
  • 若执行 stop 操作失败,则需要执行如下操作杀死进程
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

nginx 及反向代理配置

  • Nginx是轻量级的高性能Web服务器,提供了诸如HTTP代理和反向代理、负载均衡、缓存等一系列重要特性,在实践之中使用广泛
  • 客户端请求nginx,再由nginx 将请求转发 uWSGI 运行的django
  • 部署Nginx参考38.综合架构网站服务
# 在server节点下添加新的location项,指向uwsgi的ip与端口。
server {
    ...
    location / {
        uwsgi_pass 127.0.0.1:8000;  # 重定向到127.0.0.1的8000端口
        include /etc/nginx/uwsgi_params; # 将所有的参数转到uwsgi下
    }
    ...
}
  • 修改项目同名文件夹/uwsgi.ini下的Http通信方式改为socket通信方式
[uwsgi]
# 去掉如下
# http=127.0.0.1:8000
# 改为
socket=127.0.0.1:8000
  • 重启uWSGI服务
#进入到 项目同名文件夹下
$ 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/
  • 在Djangosettings.py中添加新配置
STATIC_ROOT = '/home/tarena/项目名_static/static'
#注意 此配置路径为 存放所有正式环境中需要的静态文件
  • 执行python3 manage.py collectstatic执行该命令后Django将项目重所有静态文件复制到STATIC_ROOT中 ,包括Django内建的静态文件如admin后台的样式
# file : /etc/nginx/sites-enabled/default
# 新添加location /static 路由配置,重定向到指定的 第一步创建的路径即可
server {
    ...
    location /static {
        # root 第一步创建文件夹的绝对路径
        root /home/tarena/项目名_static;
    }
    ...      
}