返回验证码图片
后端:返回Http对象,content_type设置为image
# 验证码测试视图函数
def get_captcha(request):
img, code = generate_captcha() # 生成验证码
request.session['captcha_code'] = code # 将验证码保存到session中
buf = BytesIO() # 创建一个BytesIO对象,用于存储验证码图片
img.save(buf, 'png') # 将验证码图片保存到BytesIO对象中
return HttpResponse(buf.getvalue(),content_type="image/png") # 返回验证码图片的二进制数据
前端:设置imageUrl变量,img自动访问资源
<img :src="imageUrl" v-on:click=imgSrc(this) alt="验证码图片" style="width: 100px; margin-left: 40px;" />
但是没办法点击刷新验证码
重新绑定函数完成。
@click="imgSrc"
const imgSrc = () => {
imageUrl.value = imageUrl.value + '?' + new Date().getTime()
api.get_session().then((res) => {
console.log(res)
})
}
前端请求cookie丢失
原文链接:Django+vue 解决cookie跨域不携带问题(本地)以及上线后 - 春游去动物园 - 博客园
1排除了跨域问题,后端已经解决了跨域
后端通过
pip install django-cors-headers
sessting.py设置
SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 会话cookie可以在用户浏览器中保持有效期。 False---session 在一段时间不活动后过期。True:关闭浏览器,则Cookie失效。
SESSION_COOKIE_SAMESITE = None
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CSRF_COOKIE_SAMESITE = None
CSRF_COOKIE_SECURE = False
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
'Cookie',
)
解决了跨域问题
前端通过代理域名,二次封装axios请求完成
vue.config.js
devServer: { //开启代理服务器
proxy:{
"/api": { // /api是自行设置的请求前缀,按照这个来匹配请求,有这个字段的请求,就会走到代理来。
target: "http://127.0.0.1:8081", // 需要代理的域名,目标域名,会替换掉匹配字段之前的路径
ws: false, // 是否启用websockets
changeOrigin: true, //是否跨域
pathRewrite: { //重写匹配的字段,如果不需要放在请求路径上,可以重写为""
"^/api": ""
}
},
}
},
request.js
const instance = axios.create({
timeout:5000,
baseURL:'/api', // 设置通用请求的地址前缀
withCredentials : true
})
可以传递cookie。
但是session无法获取,大概猜到原因,依然是跨域问题,在vue的api封装解决了跨域,但是session的设置是根据img的src路径直接访问,依然存在跨域问题,所以重点在于解决前端使用跨域解决获取验证码图片的操作
很难受,没怎么用心学VUE,在前端访问后端接口的时候后端传回图片的二进制数据流,但是前端一直无法显示,cors跨域问题已经解决,明白只要通过二次封装的axios请求就可以通过后端设置session。但是前端一直无法显示,尝试了无数方法,最后发现我的responetype设置到别的接口了,难怪一直没生效
vue3前端将二进制流文件显示
# index.js文件中请求函数
get_capt() {
return axios.get(base.baseUrl + base.captcha ,{responseType: 'blob'})
},
//使用的时候
// 生成验证码图片
const imgSrc = () => {
api.get_capt().then((res) => {
console.log(res)
const blob = new Blob([res.data]);
let url = window.URL.createObjectURL(blob); //根据返回的流文件创建url;url指向流
imageUrl.value = url; // 创建一个指向 blob 对象的 URL
console.log(imageUrl.value)
})
}
登录设置cookie状态
前端访问登录页面,登录后,后端向前端设置cookie。
前端直接访问主页面,后端通过cookie判断时候存在登录状态的cookie,如果没有就返回信息,让前端跳转到登录页面。如果有的话就根据cookie返回登录的用户信息
菜单部分设置采用后端传递前端的方式
数据库设计t_meau表中设计为自关联表,通过后端序列化后进行返回给前端,前端读取页面并显示
自关联序列化序列化,没招数了,多表关联都能用,自关联只能学着写了。自己摸索的
class Children2MeausSerializer(serializers.ModelSerializer):
class Meta:
model = meaus
fields = ['id', 'name', 'level', 'path']
class ChildrenMeausSerializer(serializers.ModelSerializer):
children = Children2MeausSerializer(many=True, read_only=True)
class Meta:
model = meaus
fields = ['id', 'name', 'level', 'path', 'children']
class MeausSerializer(serializers.ModelSerializer):
# 通过related_name='children'指定子级数据的反向查询字段名为children
children = ChildrenMeausSerializer(many=True, read_only=True)
class Meta:
model = meaus
fields = ['id', 'name', 'level', 'path', 'children']
上传用户头像并更改
通过el-upload,先判断传递图片是否符合要求,之后对传递的图片进行处理,并且保存为全局变量(需要对整个用户信息进行更新)获取到了图片信息之后通过请求后端接口将用户图像的图片信息传递过去。从后端拿到图片的地址在返回给前端。后端通过接收到图片的信息后将图片的上传到七牛云中进行云端储存,并且将储存的云端地址保存到mysql数据库当中。后端返回的时候将数据库的地址返回给前端,前端接收到数据地址进行赋值给表单或者弹窗中的图片地址,从而显示出图片
vue3的全局变量使用
// main.vue
const { proxy } = getCurrentInstance()
let user_img= proxy.$user_img
// main.js
const app = createApp(App)
app.config.globalProperties.$user_img = '用户的头像地址';
app.use(router).provide("$axios",axios).mount('#app')
重新捋一下
用户选择好图片之后,点击上传,发送上传请求给后端。后端接收到上传的文件流,将文件流发送到七牛云平台进行保存,返回一个图片的链接地址。后端将接收到的链接地址保存更新数据库并返回给前端页面进行展示。直接更改前端的src路径。
卡了我一天时间
解决方式:
通过element-plus的el-upload组件进行上传头像,起初认为action自动发送的请求会出现跨域问题,所以一直想要更新源码进行发送请求,最后实践得知不会出现跨域问题,因为我的后端需要cookie进行身份辨别,所以添加了:with-credentials="true"
<el-dialog class="avatarDialog" :showClose="false" center v-model="avatarDialogVisible" title="更新头像">
<el-upload
ref="upload"
class="avatar-uploader"
:show-file-list="false"
action='http://localhost:8081/user/upload_img/'
:with-credentials="true"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:auto-upload = 'true'
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<el-icon v-else class="avatar-uploader-icon">
<Plus />
</el-icon>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="file_out">关闭</el-button>
</span>
</template>
</el-dialog>
后端就可以接收到前端发送的请求
@csrf_exempt
def upload_img(request):
if request.method == 'POST':
try:
user_id = request.COOKIES.get('user_id')
user = Users.objects.get(pk=user_id)
except KeyError:
return JsonResponse({"data":False,"msg":"登录过期,请重新登录"}, status=200)
# json_data = json.loads(request.body)
user_img = request.FILES['file'].file # 获取用户上传的头像图片文件流
file_name = upload_file(settings.AK, settings.SK, user_img)
user.img = f'{settings.BUCKET_URL}/{file_name}'
user.save() # 将头像地址保存到数据库中
print(f'文件地址:{settings.BUCKET_URL}/{file_name}')
return JsonResponse({'data':'调用了接口',"user_img":user.img},status=200)
通过封装好的upload_file函数,将文件流上传到七牛云保存,并返回相应的地址,将地址更新到数据库当中,减少了数据库的储存量,返回给前端图片的路径地址。在通过scr属性进行显示
用户发布社区动态功能
1.使用类视图
2.关联表问题,解决model无法引入的问题。关联表通过app名称.model名称字段进行关联,避免了外部导入的方式
3.类视图csrf问题,查阅官方文档,大概就是通过method_decorator可以将方法装饰器指定到所需要的函数上,然后dispatch就是将类中所有的方法挂载csrf_exempt函数装饰器
@method_decorator(csrf_exempt, name='dispatch')
class CommunityView(View):
def post(self, request):
title = request.POST.get('title')
content = request.POST.get('content')
return HttpResponse('ok')
三表关联序列化
实际场景:在评论表中绑定了多对一关联了动态表和用户表,需要在前端访问接口时返回一个树状的json,返回动态表和评论表的关联json还是挺容易的,但是还要在评论的json后在序列化上去一个用户的序列化。返回这样的结构
{
"id": 1,
"title": "\u6d4b\u8bd51",
"image1": "Fhw7c70Z-vlHh8VAv0my_5ANPb9J",
"image2": "FslN6_3fQJERkaX5sK_199yc4d5f",
"image3": null,
"content": "\u6d4b\u8bd51",
"create_time": "2024-11-06T13:57:35.799846Z",
"giveLike": 0,
"comments_Com": [
{
"id": 5,
"content": "112233",
"create_time": "2024-11-07T07:31:00.964444Z",
"user": {
"id": 18,
"user": "\u8d75\u5b50\u9f99",
"password": "123",
"name": "123",
"age": 18,
"sex": "1",
"College": "1",
"img": "smgi3az6c.hn-bkt.clouddn.com/FslN6_3fQJERkaX5sK_199yc4d5f"
}
},
但是创建model时是这样的方式
# 评论表
class Comments(models.Model):
content = models.TextField()
create_time = models.DateTimeField(auto_now_add=True,null=True)
# 外键,关联社区表,评论了哪个动态
community = models.ForeignKey(Communitys,on_delete=models.CASCADE, related_name='comments_Com')
# 外键,关联用户表,谁评论的
user = models.ForeignKey('user_app.Users', on_delete=models.CASCADE, related_name='comments_uid')
class Meta:
db_table = 't_comments'
所以单纯的嵌套序列化满足不了我的需求
查阅资料后发现有一个深度函数depth函数
原文链接:DRF之序列化器嵌套_drf序列化器嵌套-优快云博客
class ComentsSerializer(serializers.ModelSerializer):
class Meta:
model = Comments
fields = ('id', 'content', 'create_time', 'user')
depth = 1
class CommunitySerializerComents(serializers.ModelSerializer):
comments_Com = ComentsSerializer(many=True, read_only=True)
class Meta:
model = Communitys
fields = ('id', 'title', 'image1','image2','image3','content','create_time','giveLike','comments_Com')
最后解决了问题
分页返回的处理
使用django.core.paginator的Paginator进行分页
@method_decorator(csrf_exempt, name='dispatch')
class user_CommunityListView(View):
def get(self, request):
# queryset = Communitys.objects.filter(user_id=request.COOKIES.get('user_id'))
queryset = Communitys.objects.filter(user_id=18)
items_per_page = 1 # 每页显示的项目数
paginator = Paginator(queryset, items_per_page) # 创建分页器对象
page_number = request.GET.get('page', 1) # 获取当前请求的页码,默认为1
page_obj = paginator.get_page(page_number) # 获取当前页码对应的页面对象
res = CommunitySerializerComents(page_obj,many=True).data
return JsonResponse(res, safe=False)
还有另一种处理方式就是通过drf框架的分类器不过需要继承相关的视图函数才可以
官方文档:Pagination - Django REST 框架
时间格式处理
前端处理方式
<p>发布时间:{{formatter.format(new Date(data.create_time)) }}</p>
const options = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
};
const formatter = new Intl.DateTimeFormat('zh-CN', options); // 使用中文(中国)格式
后端处理方式,通过将字段重新序列化
class ComentsSerializer(serializers.ModelSerializer):
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M')
class Meta:
model = Comments
fields = ('id', 'content', 'create_time', 'user')
depth = 1
又遇到了新问题,数据库同步时报错
(1062, "Duplicate entry '18' for key 't_comments.t_comments_user_id_d277b813_uniq'")
以下是我的模型文件
class Communitys(models.Model):
title = models.CharField(max_length=20)
# 直接保存图片储存爆炸,使用云端储存,mysql储存路径
image1 = models.CharField(max_length=128, null=True)
image2 = models.CharField(max_length=128, null=True)
image3 = models.CharField(max_length=128, null=True)
content = models.TextField(null=True)
create_time = models.DateTimeField(auto_now_add=True)
giveLike = models.IntegerField(default=0)
# 外键,关联用户表,谁发布的
user_id = models.ForeignKey('user_app.Users', on_delete=models.CASCADE, related_name='communitys_uid',default=None,unique=False)
class Meta:
db_table = 't_community'
def __str__(self):
return self.title
# 评论表
class Comments(models.Model):
content = models.TextField()
create_time = models.DateTimeField(null=True)
# 外键,关联社区表,评论了哪个动态
community = models.ForeignKey(Communitys,on_delete=models.CASCADE, related_name='comments_Com')
# 外键,关联用户表,谁评论的
user = models.ForeignKey('user_app.Users', on_delete=models.CASCADE, related_name='comments_uid',unique=False)
class Meta:
db_table = 't_comments'
class Users(models.Model):
SEX_CHOICES = (('1', '男'),('2', '女'))
College_CHOICES = (('1', '经济与管理学院'), ('2', '文化与法律学院'), ('3', '艺术与传媒学院')
, ('4', '教育学院'), ('5', '外国语学院'), ('6', '马克思主义学院')
, ('7', '体育学院'), ('8', '大数据与人工智能学院'), ('9', '电子与机械工程学院')
, ('10', '材料与包装工程学院'), ('11', '食品与生物工程学院'), ('12', '海洋学院')
, ('13', '继续教育学院'))
user = models.CharField(max_length=34) # 账号
password = models.CharField(max_length=34) # 密码
name = models.CharField(max_length=34, default='未知用户') # 昵称
age = models.IntegerField(null=True) # 年龄
sex = models.CharField(max_length=1,choices=SEX_CHOICES, null=True) # 性别
College = models.CharField(max_length=2,choices=College_CHOICES, null=True) # 学院
img = models.CharField(max_length=128, null=True) # 头像
class Meta:
db_table = "t_users"
但是当我想要和评论comments模型一样在创建一个upvote模型时遇到了问题
class upvote(models.Model):
community = models.ForeignKey('community_app.Communitys', on_delete=models.CASCADE, null=True)
user_upvote = models.ForeignKey(Users,on_delete=models.CASCADE,null=True,unique=False)
likeStatus = models.IntegerField(default=0,null=False)
class Meta:
db_table = "t_upvote"
解决办法:
查阅资料显示:错误是关于数据库中的唯一性约束(unique constraint)被违反了。
我确定我的表结构并没有手动更改,只有创建和删除数据,能想到的可能就是同步数据库的时候没有django正确的设置。
查阅了t_comments表的DDL发现连user_id都没有正确的创建关联关系
CREATE TABLE `t_comments` (
`id` bigint NOT NULL AUTO_INCREMENT,
`content` longtext NOT NULL,
`community_id` bigint NOT NULL,
`user_id` bigint NOT NULL,
`create_time` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `t_comments_community_id_8ad73b26` (`community_id`),
CONSTRAINT `t_comments_community_id_8ad73b26_fk_t_community_id` FOREIGN KEY (`community_id`) REFERENCES `t_community` (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 26 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci
尝试了将t_comments表中的数据全部进行删除,毕竟都说我那个数据重复了,就可以正确同步了
由于好奇为什么没有正确同步过去user_id的绑定,同步后马上查阅了新表的外键约束

确实是正确设置了我的外键关联关系,迷茫了,有看到相关解释再回来回答
密码加密(django自带的)
使用django自带的加密和加密功能
from django.contrib.auth.hashers import make_password, check_password
2313

被折叠的 条评论
为什么被折叠?



