Django 仿博客园练习

数据库搭建

在这里插入图片描述

部分功能介绍

【一】注册

(1)效果显示、简单简介

  • 主要亮点
    1. 结合了layui和forms组件
    2. 默认头像可以随着性别的选择发生改变
    3. 自定义头像可以实时更新显示
    4. forms组件报错信息可以局部刷新显示在对应框体下面
      • 没有直接使用layui的前端验证
      • 后端验证更加安全
    5. 报错信息随鼠标的聚焦可以消失

请添加图片描述

(2)重要代码逻辑梳理

(2.1)头像随性别切换
  1. 首先给性别按钮绑定事件监听
  2. 根据当前的性别进行进行img标签的src属性进行修改
<script>
{#头像随性别切换#}
let genderButtons = document.getElementsByName('gender');
genderButtons.forEach(function (button) {button.addEventListener('click', function () {{#定义默认路径#}let defaultMaleAvatar = '/static/avatar/default_male.png'let defaultFemaleAvatar = '/static/avatar/default_female.png'{#获取当前的值进行修改#}let selectGender = $(this).val();let avatarImg = $("#avatarImg")if (selectGender === 'm') {avatarImg.attr('src', defaultMaleAvatar)} else if (selectGender === 'f') {avatarImg.attr('src', defaultFemaleAvatar)}});
});
</script>
(2.2)自定义头像预览
  1. 创建FileReader对象
  2. 获取当前头像数据$()[0].files[0]
  3. 转换读取文件内容为DataURL
  4. FileReader对象调用方法onload实时预览
<script>
{#头像预览#}
$("#selectAvatar").change(() => {{#创建FileReader对象#}let fileReader = new FileReader();{#读取头像#}let avatarData = $("#selectAvatar")[0].files[0];{#读取文件内容转换为Data URL对象#}fileReader.readAsDataURL(avatarData){#重新赋值,实现预览功能#}fileReader.onload = () => {$("#avatarImg").attr('src', fileReader.result)}
})
</script>
(2.3)报错信息预览、添加报错红框
  • 视图层代码和介绍
def register(request):register_form = RegisterForm()if request.method == "POST" and request.is_ajax():register_form = RegisterForm(request.POST)# 使用forms组件校验,不合法返回错误信息if not register_form.is_valid():return json_response(code=2001, errors=register_form.errors)# 拿出所有检验通过的数据clean_data = register_form.cleaned_data# 合法信息需要抛出confirm_password,userinfo表中没有clean_data.pop('confirm_password')# 获取头像数据avatar = request.FILES.get("avatar")# 拿不到数据就用默认头像if not avatar:if clean_data.get('gender') == 'm':clean_data['avatar'] = "static/avatar/default_male.png"else:clean_data['avatar'] = "static/avatar/default_female.png"else:clean_data['avatar'] = avatar# 注册,密码加密处理,clean_data解压赋值user_obj = UserInfo.objects.create_user(**clean_data)# 反向解析跳转地址next_url = reverse("login")return json_response(message=f"{user_obj.username}注册成功", next_url=next_url)return render(request, 'register.html', locals())
  1. 将视图层返回的报错信息response.errors
  2. 根据前端页面的文本框的ID进行标签查找
  3. 链式操作
    • 找到span标签添加errroMessage
    • 找到input标签添加layui红框样式
$.each(response.errors, (spanId, errorMessage) => {let tagId = "#id_" + spanId{#根据id找到span添加报错信息#}{#找到input的标签添加红框#}    $(tagId).next().next().text(errorMessage[0]).parent().find('input').addClass("layui-form-danger")
})

【二】登录

(1)效果显示、简单介绍

  • 主要亮点是
    • 验证码的处理
    • 背景白色、字符颜色偏暗且不会出现很亮的颜色
    • 前端页面验证码刷新方法简单,点击图片即可
    • 验证码图片更新方式简单,在标签内添加事件即可

在这里插入图片描述

(2)重要代码逻辑梳理

(2.1)验证码生成

  1. 使用PIL模块中Image对象生成白板
  2. 使用PIL模块中ImageDraw对象根据白板创建画笔
  3. 使用PIL模块中的ImageFont对象指定画笔的字体和大小
  4. 使用循环和随机颜色的方式
    • 依次在不同的位置绘画不同颜色的验证码字符
  5. 再次使用for循环和随机颜色添加背景噪点
  6. 使用IO模块的BytesIO对象创建内存缓存区
  7. 将图片对象保存为PNG格式
  8. 将验证码字符和验证码图片字节流数据返回
import random
import stringfrom PIL import Image, ImageFont, ImageDraw
# Image:生成图片
# ImageDraw:图片内容绘制
# ImageFont:字体样式# BytesIO:临时存储数据,返回二进制数据
from io import BytesIO, StringIO# 列表推导式生成随机颜色
# 高亮度的还是少一点的好
def rgb_number():return tuple([random.randint(0, 200) for _ in range(3)])def create_captcha(img_type="RGB", img_size=(310, 38)):# 白板对象# 图片类型,图片大小,图片颜色# img_obj = Image.new(img_type, img_size, rgb_number())img_obj = Image.new(img_type, img_size, color=(241, 241, 241))  # 白板# 画笔对象img_draw = ImageDraw.Draw(img_obj)# 指定字体和大小img_font = ImageFont.truetype('static/font/汉仪晴空体简.ttf', 30)captcha = ''for i in range(4):choices_list = list(string.digits + string.ascii_letters)temp_captcha = random.choice(choices_list)# 开始绘制# 位置、字符、颜色、字体img_draw.text((i * 30 + 10, 2), temp_captcha, rgb_number(), img_font)captcha += temp_captcha# 添加噪点for _ in range(100):x = random.randint(0, img_size[0] - 1)y = random.randint(0, img_size[1] - 1)img_draw.point((x, y), fill=rgb_number())# 文件对象的内存缓冲区,可以用来读写二进制数据io_obj = BytesIO()# 将图像对象img_obj保存为PNG格式,并将保存后的数据写入到之前创建的BytesIO对象io_obj中。img_obj.save(io_obj, 'png')# 从BytesIO对象io_obj中获取保存的图像数据,并将其赋值给变量img_dataimg_data = io_obj.getvalue()# 返回验证码和图片数据return captcha, img_data

(2.2)验证码前端刷新方法

  • 视图层
    • 指定验证码图片大小
    • 将验证码添加到session中用于校验
    • 返回HttpResponse()对象
def get_captcha(request):# 获取验证码和图片code, img_data = create_captcha(img_size=(122, 36))# 将验证码保存在session中用于验证request.session['captcha'] = codereturn HttpResponse(img_data)
  • 前端
    • src为视图层的路由映射
    • style指定大小
    • onclick绑定事件
      • 由于在当前路由后添加?携带其他信息仍能找到指定路由
      • 所以在每次点击之后在其后面添加时间就可以完整刷新的功能
<img src="{% url 'get_captcha' %}" style="width: 100%; height: 38px" id="captcha"onclick="this.src = '{% url 'get_captcha' %}' + '?t='+ new Date().getTime();">

【三】修改头像

(1)效果显示、简单介绍

  • 使用的是Bootstrap3的模态框

  • 具有登录渲染当前头像的功能

  • 亮点:

    • 后端保存图像的方法写了两种

在这里插入图片描述

(2)修改头像代码梳理

(2.1)使用request修改登录人的头像

  • 首先说弊端,只能修改登录人的头像
  • 优势:简单,自动保存图片,图片名称处理(上传相同的头像保存不同的文件名)
  • 代码逻辑
    1. 首先获取头像数据
    2. 然后使用request.user进行头像的修改
    3. 最后一定要执行save方法保存
@csrf_exempt
@login_required
def set_avatar(request):if request.is_ajax():if request.FILES:# 获取头像avatar = request.FILES.get('avatar')# 使用保存更改user_obj = request.useruser_obj.avatar = avataruser_obj.save()return json_response(message='头像修改成功')return json_response(code=2001, error="请添加新的头像")return json_response(code=2002, error='非Ajax请求')

(2.2)手动保存头像

  • 弊端很明显,麻烦
  • 代码逻辑
    1. 同样的首先获取头像数据
    2. 然后指定文件保存位置的位置
      • 存在的问题就是文件名可能重复
      • 最好自己在手动对文件名进行处理
    3. 手动保存
    4. 再次拼接保存在数据库中的位置
    5. 最后update更新
@csrf_exempt
@login_required
def set_avatar(request):if request.is_ajax():if request.FILES:# 获取头像avatar = request.FILES.get('avatar')# 需要手动拼接路径,模型层的up_load不起作用,甚至需要图片名字手动加参数才可以不重名file_path = os.path.join('media', 'avatar', avatar.name)# 保存文件with open(file_path, 'wb') as f:# 保存图片是个易错点for line in avatar.chunks():f.write(line)# 拼接保存在数据库中的路径path = os.path.join('avatar', avatar.name)UserInfo.objects.filter(username='iron').update(avatar=path)return json_response(message='头像修改成功')return json_response(code=2001, error="请添加新的头像")return json_response(code=2002, error='非Ajax请求')

【四】广告后台管理

(1)效果显示、简单介绍

  • 左侧所有广告的轮播图,使用的是layui的轮播图功能
  • 中间使用form表单显示所有的广告内容,form表单提供功能
    1. 编辑广告功能,使用的模态框
    2. 删除广告功能,使用ajax的局部刷新
    3. 右侧预览功能,使用ajax的局部刷新功能
    4. 底部使用了分页器进行分页显示
  • 右侧可以查看指定广告的渲染样式
    在这里插入图片描述

(2)广告编辑功能

  • 我选择使用模态框
    • 及点击不同的广告
    • 模态框显示不同的原始广告信息
    • 所以这个有个局部渲染的要求
    • 需要用到ajax
  • 广告提交
    • 可以使用form表单提交
    • 也可以使用ajax进行提交(选择这个)
  • 代码逻辑(分别发送两次ajax请求)
    1. 获取当前广告ID
    2. 向后端发送ajax请求
    3. 拿到原始数据
    4. 将原始数据渲染到模态框的表单中
      • 要点:还需要保存这篇文章的ID的表单中
      • 用于修改广告信息的ID查找
    5. 等待修改信息
    6. 再次发送ajax请求
    7. 将新的内容发送给后端进行处理
{#编辑广告第一步#}
{#编辑广告第一步#}
$(".set-adv").click(function (event) {event.preventDefault(){#获取当前广告ID#}let id = $(this).attr('value')$.ajax({url: "{% url 'set_adv_first' %}",type: "post",data: {"id": id},success: function (response) {if (response.code === 2000) {console.log(response)$('input[name="set_adv_mobile"]').attr('value', response.mobile);$('input[name="set_adv_title"]').attr('value', response.title);$('input[name="set_adv_desc"]').attr('value', response.desc);$('#set-adv-img').attr('src', response.img);// 在指定的 input 标签后面插入一个新的 input 标签$('input[name="set_adv_mobile"]').after($('<input>').attr({type: 'hidden', // 设置为隐藏类型name: 'now_id', // 设置 input 的 name 属性为 now_idvalue: response.now_id // 设置 input 的 value 属性为 now_id 的值}))if (response.is_background_img) {{#修改前端显示效果#}$('#set_adv_background').next().addClass('layui-form-onswitch'){#修改后端可以接收到的值#}$("#set_adv_background").click()}} else {alert(response.error)}}})
}){#编辑广告第二步#}
$("#set-adv-button").click((event) => {event.preventDefault(){#创建formData#}let formData = new FormData(){#获取form数据#}$.each($("#set-avd-form").serializeArray(), (_, dataDict) => {formData.append(dataDict.name, dataDict.value)}){#获取广告数据#}let advData = $("#setSelectAdv")[0].files[0];formData.append('set_adv_img', advData)console.log(formData){#发送ajax#}$.ajax({url: "{% url 'set_adv_second' %}",type: "post",data: formData,processData: false,contentType: false,success: (response) => {console.log(response)if (response.code === 2000) {{#成功提示并跳转#}Swal.fire({title: response.message,icon: "success",customClass: {popup: 'swal2-custom',icon: 'swal2-icon-custom'}}).then(() => {window.location.reload()});} else {console.log(response.code)Swal.fire({icon: "error",title: response.error,customClass: {popup: 'swal2-custom',icon: 'swal2-icon-custom'}});}}})
})

【五】广告个数动态加载

(1)效果显示、简单介绍

  • 右侧的广告
    • 通过循环遍历出来
    • 根据页面中间的内容多少,进行最大存放广告数量的显示
    • 比如
      • 现在页面中间只用5条数据,那么右侧就只显示能存放的2-3个广告
      • 如果页面中间有上百条数据,也就是说页面可以向下混动很多很多,那么右侧的广告也就随之展现更多的

在这里插入图片描述

(2)逻辑梳理

  1. 页面中的广告信息默认是不显示的
    • display属性写成none
  2. 在页面加载完以后再根据页面高度对广告进行展示
  3. 首先在页面加载以后得到页面的总高度
  4. 然后根据广告的高度进行整除向下取整
  5. 以防个数超出已有的广告数量
  6. 对个数进行处理
  7. 最后个根据计算得到的个数进行切分slice显示show
{#右侧广告开始#}
<div class="col-md-2 right-content">{% block right-content %}{% for adv_obj in adv_queryset %}<div class="advertisement" style="display: none;">{% adv_show adv_obj.pk %}</div>{% endfor %}{% endblock %}
</div>
{#右侧广告结束#}
<script>$(document).ready(() => {{#页面总高度#}let totalDocumentHeight = $(document).height();// 对高度进行400px的整除取整数let numAdsToShow = Math.floor(totalDocumentHeight / 400);// 确保广告数量不会少于0或超过广告对象的总数let advCount = {{ adv_queryset|length }};numAdsToShow = Math.min(numAdsToShow, advCount);// 根据计算出的数量显示广告$('.advertisement').slice(0, numAdsToShow).show();
</script>

【六】点赞点踩

(1)效果显示、简单介绍

  • 首先说明这个样式是来自于博客园的,逻辑代码是自己写的
  • 亮点是
    • 点赞点踩都是绑定的一个前端方法
      • votePost
    • 前端进行三元表达式运算
    • 发送数据给后端进行逻辑处理

请添加图片描述

(2)逻辑代码介绍

  • 这个方法是不能写在$(document).ready()中
  • 因为需要是全局定义域的方法,才可以被页面中直接调用
  • 写在外面可以在页面的任何地方被调用,包括在HTML元素的onclick属性中,或者在页面的其他JavaScript脚本中。
  1. 首先对点赞还是点踩进行三元表达式运算
    • 还可以简写
    • 但是无论怎么简写发送给后端的都是字符串数据
    • 后端需要loads或者字符串判断
  2. 将操作发送给后端进行逻辑处理
    • 后端的处理逻辑有多种
    • 可以操作后了就不能点赞点踩
    • 可以作者不能改自己点赞点踩
    • 可以撤消操作等
  3. 拿到后端处理后的数据
    • 成功进行个数的渲染
    • 失败显示错误信息
<script>// 点赞功能function votePost(article_id, flag) {{#三元表达式 和C的一样 和Python的不一样#}{#flag = true ? flag === 'Digg' : false#}{#简写#}flag = flag === 'Digg'{#获取提示信息的div#}let divEle = $("#message-error"){#用于后续修改点赞点踩数量#}let upEle = $("#digg_count")let downEle = $("#bury_count")$.ajax({url: "{% url 'up_down' %}",type: "post",data: {"flag": flag,{#右边注意需要是字符串格式#}{#{% csrf_token %}写在页面中即可,没有要求说写在表单里#}"csrfmiddlewaretoken": "{{ csrf_token }}","article_id": article_id,},success: function (response) {if (response.code === 2000) {{#渲染信息#}divEle.text(response.message){#修改点赞点踩#}upEle.text(response.up_num)downEle.text(response.down_num)} else {{#失败处理#}{#html自动转义#}divEle.html(response.error)}}})}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/293819.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++教学——从入门到精通 5.单精度实数float

众所周知&#xff0c;三角形的面积公式是(底*高)/2 那就来做个三角形面积计算器吧 到吗如下 #include"bits/stdc.h" using namespace std; int main(){int a,b;cin>>a>>b;cout<<(a*b)/2; } 这不对呀&#xff0c;明明是7.5而他却是7&#xff0c;…

商城业务-检索服务

文章目录 前言一、搭建页面环境1.1 静态界面搭建1.2 Nginx 动静分离1.3 Windows 上传文件1.4 引入 thymeleaf 依赖1.5 Nginx 反向代理1.4 Nginx 配置1.5 gateway 网关配置 二、调整页面跳转2.1 引入依赖2.2 页面跳转 三、检索查询参数模型分析抽取3.1 检索业务分析3.2 检索语句…

【上海大学计算机组成原理实验报告】二、数据传送实验

一、实验目的 了解在模型机中算术、逻辑运算单元的控制方法。学习机器语言程序的运行过程。通过人工译码&#xff0c;加深对译码器基本工作原理的理解。 二、实验原理 根据实验指导书的相关内容&#xff0c;本次实验所要用的CP226实验仪在手动方式下&#xff0c;运算功能通过…

记录何凯明在MIT的第一堂课:神经网络发展史

https://www.youtube.com/watch?vZ5qJ9IxSuKo 目录 表征学习 主要特点&#xff1a; 方法和技术&#xff1a; LeNet 全连接层​ 主要特点&#xff1a; 主要特点&#xff1a; 网络结构&#xff1a; AlexNet 主要特点&#xff1a; 网络结构&#xff1a; Sigmoid Re…

碳素光线疗法与宠物健康

碳素光线与宠物健康 生息在地球上的所有动物、在自然太阳光奇妙的作用下、生长发育。太阳光的能量使它们不断进化、繁衍种族。现在、生物能够生存、全仰仗于太阳的光线。太阳光线中、包含有动物健康所需要的极为重要的波长。因此、和户外饲养的动物相比、在室内喂养的观赏动物、…

全套医院手术麻醉系统源码 人工智能麻醉系统源码 医疗管理系统源码

全套医院手术麻醉系统源码 人工智能麻醉系统源码 医疗管理系统源码 手术麻醉临床信息系统有着完善的临床业务功能&#xff0c;能够涵盖整个围术期的工作&#xff0c;能够采集、汇总、存储、处理、展现所有的临床诊疗资料。通过该系统的实施&#xff0c;能够规范麻醉科的工作流…

实现offsetof宏以及交换一个整数二进制奇偶位的宏

目录 1. offsetof宏2. 交换奇偶位 1. offsetof宏 我们想用宏来实现offsetof函数,首先要了解这个函数的用法。 1.1 offsetof函数的介绍及用法 &#xff08;1&#xff09;功能&#xff1a;用来计算结构体中一个成员在该结构体中的相对起始位置的偏移量&#xff0c;单位是字节。 …

ClamAV:Linux服务器杀毒扫描工具

Clam AntiVirus&#xff08;ClamAV&#xff09;是免费而且开放源代码的防毒软件&#xff0c;软件与病毒码的更新皆由社群免费发布。ClamAV在命令行下运行&#xff0c;它不将杀毒作为主要功能&#xff0c;默认只能查出系统内的病毒&#xff0c;但是无法清除。需要用户自行对病毒…

异常,Lambda表达式

文章目录 异常介绍存在形式程序中异常发生后的第一反应体系JVM的默认处理方案处理方式声明 throws概述格式抛出 throw格式注意意义 throws和throw的区别 捕获 try,catch介绍格式执行方式多异常捕获处理意义 如何选择用哪个 Throwable类介绍常用方法 自定义异常概述实现步骤范例…

手写Spring框架(上)浅出

手写Spring框架 准备工作Spring启动和扫描逻辑实现依赖注入的实现Aware回调模拟实现和初始化机制模拟实现BeanPostProcessor (Bean的后置处理器) 模拟实现Spring AOP 模拟实现 准备工作 准备一个空的工程创建spring的容器类&#xff0c;它是Spring IOC理念的实现&#xff0c;负…

Yolo 自制数据集dect训练改进

上一文请看 Yolo自制detect训练-CSDN博客 简介 如下图&#xff1a; 首先看一下每个图的含义 loss loss分为cls_loss, box_loss, obj_loss三部分。 cls_loss用于监督类别分类&#xff0c;计算锚框与对应的标定分类是否正确。 box_loss用于监督检测框的回归&#xff0c;预测框…

算法——距离计算

距离计算常用的算法包括欧氏距离、曼哈顿距离、切比雪夫距离、闵可夫斯基距离、余弦相似度等。这些算法在数据挖掘、机器学习和模式识别等领域中被广泛应用。 1.欧氏距离 欧式距离也称欧几里得距离&#xff0c;是最常见的距离度量&#xff0c;衡量的是多维空间中两个点之间的…

SpringMvc项目创建过程

1、新建空项目 名字和路径自定义&#xff0c;Maven项目&#xff0c;不建议勾选Add sample code 2、创建web模块 选中当前项目 修改路径&#xff0c;注意是在main包下 选择当前项目 3、编写pom.xml文件 在文件中加入以下内容&#xff0c;packaging标签表明了maven打包类型。 &…

Mysql的高级语句3

目录 一、子查询 注意&#xff1a;子语句可以与主语句所查询的表相同&#xff0c;但是也可以是不同表。 1、select in 1.1 相同表查询 1.2 多表查询 2、not in 取反&#xff0c;就是将子查询结果&#xff0c;进行取反处理 3、insert into in 4、update…

【智能算法】黄金正弦算法(GSA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2017年&#xff0c;Tanyildizi等人受到正弦函数单位圆内扫描启发&#xff0c;提出了黄金正弦算法&#xff08;Golden Sine Algorithm, GSA&#xff09;。 2.算法原理 2.1算法思想 GSA来源于正弦函…

阿里云服务器安装SSL证书不起作用的解决方案

阿里云服务器安装SSL证书不起作用的解决方案 在阿里云安装SSL证书后&#xff0c;访问无效&#xff0c;各种检查证书安装没有问题。忽然想到阿里云默认连80端口都没开启&#xff0c;443端口应该也没开启。 登录阿里云控制台 - 云服务器 ECS - 网络与安全 - 安全组 - 管理规则 - …

http模块 服务器端如何响应(获取)静态资源?

一、静态资源与动态资源介绍&#xff1a; &#xff08;1&#xff09;静态资源 内容长时间不改变的资源。eg&#xff1a;图片、视频、css js html文件、字体文件... &#xff08;2&#xff09;动态资源 内容经常更新的资源。eg&#xff1a;百度首页、淘宝搜索列表... 二、服…

栈————顺序栈和链式栈

目录 栈 顺序栈 1、初始化顺序栈 2、判栈空 3、进栈 4、出栈 5、读栈顶元素 6、遍历 链式栈 1、初始化链式栈 2、断链式栈是否为空判 3、入栈(插入) ​编辑​编辑 4、出栈(删除) 5、读取栈顶元素 6、输出链式栈中各个节点的值&#xff08;遍历&#xff09; 栈 …

【Linux C | 多线程编程】线程的连接、分离,资源销毁情况

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-04-01 1…

浅谈iOS开发中的自动引用计数ARC

1.ARC是什么 我们知道&#xff0c;在C语言中&#xff0c;创建对象时必须手动分配和释放适量的内存。然而&#xff0c;在 Swift 中&#xff0c;当不再需要类实例时&#xff0c;ARC 会自动释放这些实例的内存。 Swift 使用 ARC 来跟踪和管理应用程序的内存&#xff0c;其主要是由…