django 开设接口 以及图片防盗链
开设接口:
""" 1 网址所使用的静态文件默认放在static文件夹下 2 用户上传的静态文件也应该单独放在某个文件夹下 media配置 该配置可以让用户上传的所有文件都固定存放在某一个指定的文件夹下 # 配置用户上传的文件存储位置 MEDIA_ROOT = os.path.join(BASE_DIR,'media') # 文件名 随你 自己 会自动创建多级目录 如何开设后端指定文件夹资源 首先你需要自己去urls.py书写固定的代码 from django.views.static import serve from BBS14 import settings # 暴露后端指定文件夹资源 url(r'^media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT}) """
步骤:
settings.py中添加一行
MEDIA_ROOT = os.path.join(BASE_DIR, 'files') #上传路径,文件名随意 MEDIA_URL = '/files/' # 访问路径
urls.py中添加
from django.conf.urls import url from django.contrib import admin from app01 import views from django.views.static import serve # 暴露接口使用 #from BBS import settings # 暴露接口 from django.conf import settings # 以后都用这个导配置文件,暴露接口 urlpatterns = [ url(r'^admin/', admin.site.urls), # 注册 url(r'^register/', views.register,name='register'), # 登录 url(r'^login/', views.login, name='login'), # 退出登陆 url(r'^logout/', views.logout, name='logout'), # 图片验证码 url(r'^get_code/', views.get_code, name='get_code'), # 首页 url(r'^home/', views.home, name='home'), # 修改密码 url(r'^set_password/', views.set_password, name='set_password'), # 暴露后端指定文件夹资源,这样就会把files暴露给外界 url(r'^files/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}) ]
home.html
展示头像:
<img class="media-object" src="/files/{{ article_obj.blog.userinfo.avatar }}" alt="..." width="80px">
完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}"> </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> {% if request.user.is_authenticated %} <li><a href="#">{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#" data-toggle="modal" data-target=".bs-example-modal-lg">修改密码</a></li> <li><a href="#">修改头像</a></li> <li><a href="#">后台管理</a></li> <li role="separator" class="divider"></li> <li><a href="{% url 'logout' %}">退出登录</a></li> </ul> <!-- Large modal --> <div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <h1 class="text-center">修改密码</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <div class="formgroup"> <label for="">用户名</label> <input type="text" value="{{ request.user.username }}" class="form-control" disabled> </div> <div class="formgroup"> <label for="id_old_password">旧密码</label> <input type="password" id="id_old_password" class="form-control"> </div> <div class="formgroup"> <label for="id_new_password">新密码</label> <input type="password" id="id_new_password" class="form-control"> </div> <div class="formgroup"> <label for="">确认密码</label> <input type="password" id="id_confirm_password" class="form-control"> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal" id="id_edit_close">取消 </button> <button class="btn btn-primary" id="id_edit">修改</button> <span style="color: red;font: bold 16px 微软雅黑" id="password_error"></span> </div> </div> </div> </div> </div> </div> </li> {% else %} <li><a href="{% url 'register' %}">注册</a></li> <li><a href="{% url 'login' %}">登录</a></li> {% endif %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container-fluid"> <div class="row"> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">重金求子</h3> </div> <div class="panel-body"> 事成之后,上海别墅一套 </div> </div> <div class="panel panel-danger"> <div class="panel-heading"> <h3 class="panel-title">千万大奖</h3> </div> <div class="panel-body"> 事成之后,上海别墅一套 </div> </div> <div class="panel panel-info"> <div class="panel-heading"> <h3 class="panel-title">线上赌场</h3> </div> <div class="panel-body"> 性感荷官 </div> </div> </div> <div class="col-md-8"> <ul class="media-list"> {% for article_obj in article_queryset %} <li class="media"> <h4 class="media-heading"><a href="#">{{ article_obj.title }}</a></h4> <div class="media-left"> <a href="#"> <img class="media-object" src="/files/{{ article_obj.blog.userinfo.avatar }}" alt="..." width="80px"> </a> </div> <div class="media-body"> {{ article_obj.desc }} </div> <br> <div> <span><a href="#">{{ article_obj.blog.userinfo.username }} </a></span> <span>发布于 </span> <span>{{ article_obj.create_time|date:'Y-m-d' }} </span> <span><i class="fa fa-commenting" aria-hidden="true"></i>评论({{ article_obj.comment_num }}) </span> <span><i class="fa fa-thumbs-up" aria-hidden="true"></i>点赞{{ article_obj.up_num }}</span> </div> </li> <hr> {% endfor %} </ul> </div> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">重金求子</h3> </div> <div class="panel-body"> 事成之后,上海别墅一套 </div> </div> <div class="panel panel-danger"> <div class="panel-heading"> <h3 class="panel-title">千万大奖</h3> </div> <div class="panel-body"> 事成之后,上海别墅一套 </div> </div> <div class="panel panel-info"> <div class="panel-heading"> <h3 class="panel-title">线上赌场</h3> </div> <div class="panel-body"> 性感荷官 </div> </div> </div> </div> </div> <script src="{% static "js/mysteup.js" %}"></script> <script> $('#id_edit').click(function () { $.ajax({ url: '/set_password/', type: 'post', data: { 'old_password': $('#id_old_password').val(), 'new_password': $('#id_new_password').val(), 'confirm_password': $('#id_confirm_password').val(), 'csrfmiddlewaretoken': '{{ csrf_token }}' }, success: function (args) { if (args.code == 1000) { window.location.reload() } else { $("#password_error").text(args.msg) } } }) }) </script> </body> </html>
views.py
from django.shortcuts import render, HttpResponse, redirect from app01.myforms import MyRegForm from app01 import models from django.http import JsonResponse from app01.lib.common import create_validate_code from io import BytesIO from django.contrib import auth from django.contrib.auth.decorators import login_required # Create your views here. def register(request): form_obj = MyRegForm() if request.method == "POST": back_dic = {"code": 1000, "msg": ""} # 校验数据是否合法 form_obj = MyRegForm(request.POST) if form_obj.is_valid(): clean_data = form_obj.cleaned_data # 将校验通过的数据字典赋值给一个变量 clean_data.pop("confirm_password") # {'username': 'alias', 'password': '123', 'email': '123@qq.com'} # 用户头像 file_obj = request.FILES.get("avatar") """针对用户头像一定要判断是否传值 不能直接添加到字典中""" if file_obj: clean_data['avatar'] = file_obj # 操作数据库保存数据 models.UserInfo.objects.create_user(**clean_data) back_dic["url"] = "/login/" else: back_dic["code"] = 2000 back_dic["msg"] = form_obj.errors print(form_obj.errors) return JsonResponse(back_dic) return render(request, "register.html", locals()) def login(request): if request.is_ajax(): if request.method == "POST": back_dic = {"code": 1000, "msg": ""} username = request.POST.get("username") password = request.POST.get("password") code = request.POST.get("code") # 校验验证码是否正确 自己决定是否忽略验证码大小写 统一转大写或小写即可 if request.session.get("code").lower() == code.lower(): # 校验用户名和密码 user_obj = auth.authenticate(request, username=username, password=password) if user_obj: # 保存用户状态 auth.login(request, user_obj) back_dic["url"] = '/home/' else: back_dic["code"] = 2000 back_dic["msg"] = "用户名或密码错误" else: back_dic["code"] = 3000 back_dic["msg"] = "验证码错误" return JsonResponse(back_dic) return render(request, 'login.html') def get_code(request): f = BytesIO() # 创建一个内存地址存放图片 img, code = create_validate_code() # 调用方法生成图片对象和验证码 request.session['code'] = code # 设置session print(code) img.save(f, 'PNG') # 保存图片 return HttpResponse(f.getvalue()) # 返回图片 @login_required def logout(request): auth.logout(request) return redirect("/home/") def home(request): # 查询本网站所有的文章数据展示到前端 article_queryset = models.Article.objects.all() return render(request, 'home.html', locals()) @login_required def set_password(request): if request.is_ajax(): if request.method == "POST": back_dic = {"code": 1000, "msg": ""} old_password = request.POST.get("old_password") new_password = request.POST.get("new_password") confirm_password = request.POST.get("confirm_password") is_right = request.user.check_password(old_password) if is_right: if new_password == confirm_password: request.user.set_password(new_password) request.user.save() back_dic["msg"] = "修改成功" else: back_dic["code"] = 2000 back_dic["msg"] = "两次密码不一致" else: back_dic["code"] = 3000 back_dic["msg"] = "原密码错误" return JsonResponse(back_dic)
models.py
from django.db import models from django.contrib.auth.models import AbstractUser # Create your models here. class UserInfo(AbstractUser): phone = models.BigIntegerField(null=True, blank=True, verbose_name="手机号") # 头像 avatar = models.FileField(upload_to="avatar/", default='avatar/default.png') """ 给avatar字段传文件对象 该文件会自动存储到avatar文件夹 然后avatar字段只保存文件路径avatar/default.png """ create_time = models.DateTimeField(auto_now_add=True) blog = models.OneToOneField(to='Blog', null=True) class Meta: verbose_name_plural = "用户表" # 修改admin后台管理默认的表名 def __str__(self): return self.username class Blog(models.Model): site_name = models.CharField(max_length=32, verbose_name='站点名称') site_title = models.CharField(max_length=32, verbose_name='站点标题') # 简单模拟 认识样式内部原理的操作 site_theme = models.CharField(max_length=64, verbose_name='站点样式') # 存css/js的文件路径 class Meta: verbose_name_plural = "个人站点" def __str__(self): return self.site_name class Category(models.Model): name = models.CharField(max_length=32, verbose_name='文章分类') blog = models.ForeignKey(to='Blog', null=True) class Meta: verbose_name_plural = "文章分类" def __str__(self): return self.name class Tag(models.Model): name = models.CharField(max_length=32, verbose_name='文章标签') blog = models.ForeignKey(to='Blog', null=True) tags = models.ManyToManyField(to='Article', through='Article2Tag', through_fields=('tag', 'article') ) class Meta: verbose_name_plural = "文章标签" def __str__(self): return self.name class Article(models.Model): title = models.CharField(max_length=64, verbose_name='文章标题') desc = models.CharField(max_length=255, verbose_name='文章简介') # 文章内容有很多 一般情况下都是使用TextField content = models.TextField(verbose_name='文章内容') create_time = models.DateTimeField(auto_now_add=True) # 数据库字段设计优化 up_num = models.BigIntegerField(default=0, verbose_name='点赞数') down_num = models.BigIntegerField(default=0, verbose_name='点踩数') comment_num = models.BigIntegerField(default=0, verbose_name='评论数') # 外键字段 blog = models.ForeignKey(to='Blog', null=True) category = models.ForeignKey(to='Category', null=True) tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag') ) class Meta: verbose_name_plural = "文章" def __str__(self): return self.title class Article2Tag(models.Model): article = models.ForeignKey(to='Article') tag = models.ForeignKey(to='Tag') class UpAndDown(models.Model): user = models.ForeignKey(to='UserInfo') article = models.ForeignKey(to='Article') is_up = models.BooleanField() # 传布尔值存0/1 class Comment(models.Model): user = models.ForeignKey(to='UserInfo') article = models.ForeignKey(to='Article') content = models.CharField(max_length=255, verbose_name="评论内容") create_time = models.DateTimeField(auto_now_add=True, verbose_name='评论时间') # 自关联 parent = models.ForeignKey(to='self', null=True) # 一定要加null=True,因为有些评论就是根评论
admin.py
from django.contrib import admin from app01 import models # Register your models here. admin.site.register(models.UserInfo) # 注册的表名会默认加个后缀s,如果想自定义可以在models.py中在类中定义一个Meta类,见下面 admin.site.register(models.Blog) admin.site.register(models.Category) admin.site.register(models.Tag) admin.site.register(models.Article) admin.site.register(models.Article2Tag) admin.site.register(models.UpAndDown) admin.site.register(models.Comment)
注:此时再注册用户时,会自动新建files文件夹并新建头像的avatar目录
访问资源例如
http://127.0.0.1:8000/files/avatar/default.png
图片防盗链:
# 如何避免别的网站直接通过本网站的url访问本网站资源 # 简单的防盗 我可以做到请求来的时候先看看当前请求是从哪个网站过来的 如果是本网站那么正常访问 如果是其他网站直接拒绝 请求头里面有一个专门记录请求来自于哪个网址的参数 Referer: http://127.0.0.1:8000/xxx/ # 如何绕过防盗链技术 1.要么修改请求头referer 2.直接写爬虫把对方网址的所有资源直接下载到我们自己的服务器上