一、博客系统表关系
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
# Create your models here.
class UserInfo(AbstractUser):
"""
用户信息
"""
nid = models.AutoField(primary_key=True)
telephone = models.CharField(max_length=11, null=True, unique=True)
avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png")
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE)
def __str__(self):
return self.username
class Blog(models.Model):
"""
博客信息表(站点表)
"""
nid = models.AutoField(primary_key=True)
title = models.CharField(verbose_name='个人博客标题', max_length=64)
site_name = models.CharField(verbose_name='站点名称', max_length=64)
theme = models.CharField(verbose_name='博客主题', max_length=32)
def __str__(self):
return self.title
class Category(models.Model):
"""
博主个人文章分类表
"""
nid = models.AutoField(primary_key=True)
title = models.CharField(verbose_name='分类标题', max_length=32)
blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE)
def __str__(self):
return self.title
class Tag(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(verbose_name='标签名称', max_length=32)
blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE)
def __str__(self):
return self.title
class Article(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=50, verbose_name='文章标题')
desc = models.CharField(max_length=255, verbose_name='文章描述')
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
content = models.TextField()
comment_count = models.IntegerField(default=0)
up_count = models.IntegerField(default=0)
down_count = models.IntegerField(default=0)
user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
category = models.ForeignKey(to='Category', to_field='nid', null=True, on_delete=models.CASCADE)
tags = models.ManyToManyField(
to="Tag",
through='Article2Tag',
through_fields=('article', 'tag'),
)
def __str__(self):
return self.title
class Article2Tag(models.Model):
nid = models.AutoField(primary_key=True)
article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid', on_delete=models.CASCADE)
tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid', on_delete=models.CASCADE)
class Meta:
unique_together = [
('article', 'tag'),
]
def __str__(self):
v = self.article.title + "---" + self.tag.title
return v
class ArticleUpDown(models.Model):
"""
点赞表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE)
article = models.ForeignKey("Article", null=True, on_delete=models.CASCADE)
is_up = models.BooleanField(default=True)
class Meta:
unique_together = [
('article', 'user')
]
class Comment(models.Model):
"""
评论表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid', on_delete=models.CASCADE)
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
content = models.CharField(verbose_name='评论时间', max_length=255)
parent_comment = models.ForeignKey("self", null=True, on_delete=models.CASCADE)
def __str__(self):
return self.content
同步数据库:
python manage.py makemigrations
python manage.py migrate
二、基于Ajax和用户登录验证
登录页面
验证码获取:
方式一:
def get_valid_code_img(request):
# 方式1:
with open("lufei.jpg","rb") as f:
data=f.read()
return HttpResponse(data)
方式二:
from PIL import Image
img = Image.new("RGB", (270, 40),color=get_random_color())
with open("validCode.png", "wb") as f:
img.save(f,"png")
with open("validCode.png", "rb") as f:
data = f.read()
return HttpResponse(data)
方式三:
from PIL import Image
from io import BytesIO
img = Image.new("RGB", (270, 40), color=get_random_color())
f = BytesIO()
img.save(f, "png")
data=f.getvalue()
return HttpResponse(data)
方式四:
img = Image.new("RGB", (270, 40), color=get_random_color())
draw = ImageDraw.Draw(img)
kumo_font = ImageFont.truetype("static/font/KumoFont.ttf", size=20)
valid_code_str = ""
for i in range(5):
random_num = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(95, 122))
random_upper_alpha = chr(random.randint(65, 90))
random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])
draw.text((20 + i * 50, 15), random_char, get_random_color(), font=kumo_font)
# 保存验证码字符串
valid_code_str += random_char
# width = 270
# height = 40
# for i in range(5):
# x1 = random.randint(0, width)
# x2 = random.randint(0, width)
# y1 = random.randint(0, height)
# y2 = random.randint(0, height)
# draw.line((x1, y1, x2, y2), fill=get_random_color())
#
# for i in range(10):
# draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
# x = random.randint(0, width)
# y = random.randint(0, height)
# draw.arc((x, y, x+4, y+4), 0, 90, fill=get_random_color())
print("valid_code_str", valid_code_str)
request.session["valid_code_str"] = valid_code_str
f = BytesIO()
img.save(f, "png")
data = f.getvalue()
return data
验证码正确,并登录之后
<li><a href="#"><span id="user_icon"
class="glyphicon glyphicon-user"></span>{{ request.user.username }} </a> </li>
登录验证
<script src="/static/jquery-3.3.1.js"></script>
<script>
// 刷新验证码
$("#valid_code_img").click(function () {
$(this)[0].src += "?"
});
// 登录验证
$(".login_btn").click(function () {
$.ajax({
url: "",
type: "post",
data: {
user: $("#user").val(),
pwd: $("#pwd").val(),
valid_code: $("#valid_code").val(),
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
},
success: function (data) {
console.log(data);
if (data.user){
if (location.search){
location.href = location.search.slice(6)
}
else {
location.href = "/index/"
}
}
else {
$(".error").text(data.msg).css({"color": "red", "margin-left": "10px"});
setTimeout(function () {
$(".error").text("");
}, 1000)
}
}
})
})
完整的示例:
1 from django.contrib.auth.models import AbstractUser 2 from django.db import models 3 4 # Create your models here. 5 6 7 class UserInfo(AbstractUser): 8 """ 9 用户信息 10 """ 11 nid = models.AutoField(primary_key=True) 12 telephone = models.CharField(max_length=11, null=True, unique=True) 13 avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png") 14 create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) 15 16 blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE) 17 18 def __str__(self): 19 return self.username 20 21 22 class Blog(models.Model): 23 """ 24 博客信息表(站点表) 25 """ 26 nid = models.AutoField(primary_key=True) 27 title = models.CharField(verbose_name='个人博客标题', max_length=64) 28 site_name = models.CharField(verbose_name='站点名称', max_length=64) 29 theme = models.CharField(verbose_name='博客主题', max_length=32) 30 31 def __str__(self): 32 return self.title 33 34 35 class Category(models.Model): 36 """ 37 博主个人文章分类表 38 """ 39 nid = models.AutoField(primary_key=True) 40 title = models.CharField(verbose_name='分类标题', max_length=32) 41 blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE) 42 43 def __str__(self): 44 return self.title 45 46 47 class Tag(models.Model): 48 nid = models.AutoField(primary_key=True) 49 title = models.CharField(verbose_name='标签名称', max_length=32) 50 blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE) 51 52 def __str__(self): 53 return self.title 54 55 56 class Article(models.Model): 57 nid = models.AutoField(primary_key=True) 58 title = models.CharField(max_length=50, verbose_name='文章标题') 59 desc = models.CharField(max_length=255, verbose_name='文章描述') 60 create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) 61 content = models.TextField() 62 63 comment_count = models.IntegerField(default=0) 64 up_count = models.IntegerField(default=0) 65 down_count = models.IntegerField(default=0) 66 67 user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid', on_delete=models.CASCADE) 68 category = models.ForeignKey(to='Category', to_field='nid', null=True, on_delete=models.CASCADE) 69 tags = models.ManyToManyField( 70 to="Tag", 71 through='Article2Tag', 72 through_fields=('article', 'tag'), 73 ) 74 75 def __str__(self): 76 return self.title 77 78 79 class Article2Tag(models.Model): 80 nid = models.AutoField(primary_key=True) 81 article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid', on_delete=models.CASCADE) 82 tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid', on_delete=models.CASCADE) 83 84 class Meta: 85 unique_together = [ 86 ('article', 'tag'), 87 ] 88 89 def __str__(self): 90 v = self.article.title + "---" + self.tag.title 91 return v 92 93 94 class ArticleUpDown(models.Model): 95 """ 96 点赞表 97 """ 98 nid = models.AutoField(primary_key=True) 99 user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE) 100 article = models.ForeignKey("Article", null=True, on_delete=models.CASCADE) 101 is_up = models.BooleanField(default=True) 102 103 class Meta: 104 unique_together = [ 105 ('article', 'user') 106 ] 107 108 109 class Comment(models.Model): 110 """ 111 评论表 112 """ 113 nid = models.AutoField(primary_key=True) 114 user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid', on_delete=models.CASCADE) 115 article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid', on_delete=models.CASCADE) 116 create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) 117 content = models.CharField(verbose_name='评论时间', max_length=255) 118 119 parent_comment = models.ForeignKey("self", null=True, on_delete=models.CASCADE) 120 121 def __str__(self): 122 return self.content
1 from django.contrib import auth 2 from django.http import JsonResponse, HttpResponse 3 from django.shortcuts import render 4 5 # Create your views here. 6 from blog import models 7 from blog.Myforms import UserForm 8 from blog.models import UserInfo 9 from blog.utils import validCode 10 11 12 def login(request): 13 """ 14 登录视图函数 15 get请求响应页面 16 post(Ajax)请求响应字典 17 :param request: 18 :return 19 """ 20 if request.method == "POST": 21 response = {"user": None, "msg": None} 22 user = request.POST.get("user") 23 pwd = request.POST.get("pwd") 24 valid_code = request.POST.get("valid_code") 25 26 valid_code_str = request.session.get("valid_code_str") 27 if valid_code.upper() == valid_code_str.upper(): 28 user = auth.authenticate(username=user, password=pwd) 29 if user: 30 auth.login(request, user) 31 response["user"] = user.username 32 else: 33 response["msg"] = "用户名或密码错误" 34 35 else: 36 response["msg"] = "验证码错误!" 37 38 return JsonResponse(response) 39 return render(request, "login.html") 40 41 42 def index(request): 43 """ 44 系统首页 45 :param request: 46 :return: 47 """ 48 article_list = models.Article.objects.all() 49 return render(request, "index.html", {"article_list": article_list}) 50 51 52 def get_valid_code_img(request): 53 """ 54 基于PIL模块动态生成响应状态码图片 55 :param request: 56 :return: 57 """ 58 img_data = validCode.get_valid_code_img(request) 59 return HttpResponse(img_data) 60 61 62 def register(request): 63 """ 64 注册视图函数: 65 get请求响应注册页面 66 POst(Ajax)请求,校验字段,响应字典 67 :param request: 68 :return: 69 """ 70 if request.is_ajax(): 71 print(request.POST) 72 form = UserForm(request.POST) 73 74 response = {"user": None, "msg": None} 75 if form.is_valid(): 76 response["user"] = form.cleaned_data.get("user") 77 78 # 生成一条用户记录 79 user = form.cleaned_data.get("user") 80 print("user", user) 81 pwd = form.cleaned_data.get("pwd") 82 email = form.cleaned_data.get("email") 83 avatar_obj = request.FILES.get("avater") 84 85 extra = {} 86 if avatar_obj: 87 extra["avatar"] = avatar_obj 88 UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra) 89 90 else: 91 print(form.cleaned_data) 92 print(form.errors) 93 response["msg"] = form.errors 94 95 return JsonResponse(response) 96 97 form = UserForm() 98 return render(request, "register.html", {"form": form}) 99 100 101 return render(request, "register.html")
1 # -*- encoding: utf-8 -*- 2 # @Time : 2018-09-24 20:52 3 # @Author : mike.liu 4 # @File : validCode.py 5 import random 6 from io import BytesIO 7 8 from PIL import Image, ImageDraw, ImageFont 9 10 11 def get_random_color(): 12 return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) 13 14 15 def get_valid_code_img(request): 16 # 方式1: 17 # with open("lufei.jpg", "rb") as f: 18 # data = f.read() 19 20 # 方式2: # pip install pillow 21 22 # from PIL import Image 23 # img = Image.new("RGB", (270, 40),color=get_random_color()) 24 # 25 # with open("validCode.png", "wb") as f: 26 # img.save(f,"png") 27 # 28 # with open("validCode.png", "rb") as f: 29 # data = f.read() 30 31 # 方式3: 32 33 # from PIL import Image 34 # from io import BytesIO 35 # 36 # img = Image.new("RGB", (270, 40), color=get_random_color()) 37 # f = BytesIO() 38 # img.save(f, "png") 39 # data=f.getvalue() 40 41 # 方式4: 42 43 img = Image.new("RGB", (270, 40), color=get_random_color()) 44 45 draw = ImageDraw.Draw(img) 46 47 kumo_font = ImageFont.truetype("static/font/KumoFont.ttf", size=20) 48 49 valid_code_str = "" 50 for i in range(5): 51 random_num = str(random.randint(0, 9)) 52 random_low_alpha = chr(random.randint(95, 122)) 53 random_upper_alpha = chr(random.randint(65, 90)) 54 random_char = random.choice([random_num, random_low_alpha, random_upper_alpha]) 55 draw.text((20 + i * 50, 15), random_char, get_random_color(), font=kumo_font) 56 57 # 保存验证码字符串 58 valid_code_str += random_char 59 60 # width = 270 61 # height = 40 62 # for i in range(5): 63 # x1 = random.randint(0, width) 64 # x2 = random.randint(0, width) 65 # y1 = random.randint(0, height) 66 # y2 = random.randint(0, height) 67 # draw.line((x1, y1, x2, y2), fill=get_random_color()) 68 # 69 # for i in range(10): 70 # draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) 71 # x = random.randint(0, width) 72 # y = random.randint(0, height) 73 # draw.arc((x, y, x+4, y+4), 0, 90, fill=get_random_color()) 74 75 print("valid_code_str", valid_code_str) 76 request.session["valid_code_str"] = valid_code_str 77 78 f = BytesIO() 79 img.save(f, "png") 80 data = f.getvalue() 81 82 return data
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>登录页面</title> 6 <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> 7 </head> 8 <body> 9 <h3>登录页面</h3> 10 <div class="container"> 11 <div class="row"> 12 <div class="col-md-push-6 col-lg-offset-3"> 13 <form> 14 {% csrf_token %} 15 <div class="form-group"> 16 <label for="user">用户名</label> 17 <input type="text" id="user" class="form-control"> 18 </div> 19 <div class="form-group"> 20 <label for="pwd">密码</label> 21 <input type="password" id="pwd" class="form-control"> 22 </div> 23 24 <div class="form-group"> 25 <label for="pwd">验证码</label> 26 <div class="row"> 27 <div class="col-md-6"> 28 <input type="text" class="form-control" id="valid_code"> 29 </div> 30 <div class="col-md-6"> 31 <img width="270" height="36" id="valid_code_img" src="/get_validCode_img/" alt=""> 32 </div> 33 </div> 34 </div> 35 <input type="button" class="btn btn-default login_btn" value="登录"><span class="error"></span> 36 <a href="/register/" class="btn btn-success pull-right">注册</a> 37 </form> 38 </div> 39 </div> 40 </div> 41 <script src="/static/jquery-3.3.1.js"></script> 42 <script> 43 // 刷新验证码 44 $("#valid_code_img").click(function () { 45 $(this)[0].src += "?" 46 47 }); 48 49 // 登录验证 50 $(".login_btn").click(function () { 51 52 $.ajax({ 53 url: "", 54 type: "post", 55 data: { 56 user: $("#user").val(), 57 pwd: $("#pwd").val(), 58 valid_code: $("#valid_code").val(), 59 csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(), 60 }, 61 success: function (data) { 62 console.log(data); 63 64 if (data.user){ 65 if (location.search){ 66 location.href = location.search.slice(6) 67 } 68 else { 69 location.href = "/index/" 70 } 71 } 72 else { 73 $(".error").text(data.msg).css({"color": "red", "margin-left": "10px"}); 74 setTimeout(function () { 75 $(".error").text(""); 76 77 }, 1000) 78 } 79 80 } 81 }) 82 83 }) 84 </script> 85 86 </body> 87 </html>
三、form表单、Ajax文件上传
基于form表单提交数据:
[27/Sep/2018 12:27:42] "GET /upload/ HTTP/1.1" 200 487
<QueryDict: {'csrfmiddlewaretoken': ['0XhktJJdewNa5wfoRonIbGzlltmBMCASk8wG0IVb7EyR0XBQRcksDfEde3OEkrvB'], 'user': ['']}>
<MultiValueDict: {'avatar': [<InMemoryUploadedFile: 106.jpeg (image/jpeg)>]}>
[27/Sep/2018 12:29:03] "POST /upload/ HTTP/1.1" 200 2
基于Ajax提交数据:
<QueryDict: {'user': ['mike'], 'csrfmiddlewaretoken': ['jmCZMYoTXSx01aIFnQtmaBFRCz33vMlgDxRljXARQ0iHWB47nEq6CaKJv9v63BgZ']}>
<MultiValueDict: {'avatar': [<InMemoryUploadedFile: 100.jpeg (image/jpeg)>]}>
[28/Sep/2018 00:22:46] "POST /upload/ HTTP/1.1" 200 2
四、form表单的注册页面
图片预览:
头像默认图片
.avatar_img {
width:60px;
height:60px;
margin-left: 20px;
}
#avatar {
display: none;
}
<div class="form-group">
<label for="avatar">
头像
<img class="avatar_img" src="../static/blog/img/default.png" alt="">
</label>
<input type="file" id="avatar" name="avatar">
</div>
图像预览
// 头像预览
$("#avatar").change(function () {
// 获取用户选中的文件对象
var file_obj = $(this)[0].files[0];
// 获取文件对象的路径
var reader = new FileReader();
reader.readAsDataURL(file_obj);
// 修改img的src属性, src= 文件对象的路径
reader.onload = function () {
$(".avatar_img").attr("src", reader.result)
};
});
注意:
为什么 src="/static/img/default.png" 可访问到 ?
因为: settings 配置了 STATIC_URL = '/static/'
Ajax注册:
class UserForm(forms.Form):
user = forms.CharField(max_length=32,
error_messages={"required": "该字段不能为空!"},
label="用户名",
widget=widgets.TextInput(attrs={"class": "form-control"},)
)
pwd = forms.CharField(max_length=32,
error_messages={"required": "该字段不能为空!"},
label="密码",
widget=widgets.PasswordInput(attrs={"class": "form-control"},)
)
re_pwd = forms.CharField(max_length=32,
error_messages={"required": "该字段不能为空!"},
label="确认密码",
widget=widgets.PasswordInput(attrs={"class": "form-control"},)
)
email = forms.EmailField(max_length=32,
error_messages={"required": "该字段不能为空!"},
label="邮箱",
widget=widgets.EmailInput(attrs={"class": "form-control"},)
)
# 局部钩子
def clean_user(self):
val = self.cleaned_data.get("user")
user = UserInfo.objects.filter(username=val).first()
if not user:
return val
else:
raise ValidationError("该用户已注册!")
# 校验局部钩子的时候,没有办法拿到所有的数据
# 任何校验两个字段?全局钩子
# 全局钩子得到任何一个干净的数据
def clean(self):
pwd = self.cleaned_data.get("pwd")
re_pwd = self.cleaned_data.get("re_pwd")
if pwd and re_pwd:
if pwd == re_pwd:
return self.cleaned_data
else:
raise ValidationError("两次密码不一致!")
else:
return self.cleaned_data
def register(request):
"""
注册视图函数:
get请求响应注册页面
POst(Ajax)请求,校验字段,响应字典
:param request:
:return:
"""
if request.is_ajax():
print(request.POST)
form = UserForm(request.POST)
response = {"user": None, "msg": None}
if form.is_valid():
response["user"] = form.cleaned_data.get("user")
# 生成一条用户记录
user = form.cleaned_data.get("user")
print("user", user)
pwd = form.cleaned_data.get("pwd")
email = form.cleaned_data.get("email")
avatar_obj = request.FILES.get("avater")
extra = {}
if avatar_obj:
extra["avatar"] = avatar_obj
UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
else:
print(form.cleaned_data)
print(form.errors)
response["msg"] = form.errors
return JsonResponse(response)
form = UserForm()
return render(request, "register.html", {"form": form})
return render(request, "register.html")
// 基于ajax提交数据
$(".reg_btn").click(function () {
// console.log($("#form").serializeArrray());
var formdata = new FormData();
var request_data = $("#form").serializeArray();
$.each(request_data, function (index, data) {
formdata.append(data.name, data.value)
});
formdata.append("avatar", $("#avatar")[0].files[0]);
$.ajax({
url:"",
type: "post",
contentType: false,
processData: false,
data: formdata,
success: function (data) {
if(data.user){
// 注册成功
location.href="/login/"
}
else {
// 注册失败
//console.log(data.msg)
// 清空错误信息
$("span.error").html("");
$(".form-group").removeClass("has-error");
// 展示本次提交的错误信息
$.each(data.msg, function (field, error_list) {
console.log(field, error_list);
if (field=="__all__"){
$("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error");
}
$("#id_" + field).next().html(error_list[0]);
$("#id_" + field).parent().addClass("has-error");
})
}
}
})
})
注意:
1、局部钩子 与 全局钩子
def clean_user(self): pass 局部钩子只能校验某一个字段
def clean(self): 可以校验两个不同的字段,全局钩子,能得到任何一个干净的数据
局部钩子得源码:
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
全局钩子得源码:
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data
2、上传文件
var formdata = new FormData();
var request_data = $("#form").serializeArray();
$.each(request_data, function (index, data) {
formdata.append(data.name, data.value)
});
formdata.append("avatar", $("#avatar")[0].files[0]); // 文件对象
$.ajax({
url:"",
type: "post",
contentType: false,
processData: false,
data: formdata,
success: function (data) {
3、Ajax的局部刷新:
注册失败:
1、清空错误信息
$("span.error").html("");
$(".form-group").removeClass("has-error");
2、加载错误信息
// 展示本次提交的错误信息
$.each(data.msg, function (field, error_list) {
console.log(field, error_list);
// 全局的错误信息
if (field=="__all__"){
$("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error");
}
$("#id_" + field).next().html(error_list[0]);
$("#id_" + field).parent().addClass("has-error");
})
4、上传文件的存放地址:media配置
前端:
formdata.append("avatar", $("#avatar")[0].files[0]); // 文件对象
后台:
extra = {}
if avatar_obj:
extra["avatar"] = avatar_obj
UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
知识点:
静态文件/static/css..js..img.. 用户可直接URL访问得到
因为:settings配置STATIC_URL = '/static/'
用户文件:
settings里面配置:
# 与用户上传相关的配置
MEDIA_ROOT=os.path.join(BASE_DIR,"media")
MEDIA_URL="/media/"
路由配置:urls.py
# media配置:
re_path(r"media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT})
media配置之后:
用户可以直接访问
数据库的文件保存还是相对路径:
示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册页面</title> <link rel="stylesheet" href="../static/bootstrap-3.3.7/css/bootstrap.css"> <script src="../static/jquery-3.3.1.js"></script> <style> .avatar_img { width:60px; height:60px; margin-left: 20px; } #avatar { display: none; } .error { color: red; } </style> </head> <body> <h3>注册页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form id="form"> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="{{ field.auto_id }}">{{ field.label }}</label> {{ field }} <span class="error pull-right"></span> </div> {% endfor %} <div class="form-group"> <label for="avatar"> 头像 <img class="avatar_img" src="/static/blog/img/default.png" alt=""> </label> <input type="file" id="avatar" name="avatar"> </div> <input type="button" class="btn btn-default reg_btn" value="提交"> <span class="error"></span> </form> </div> </div> </div> <script> // 头像预览 $("#avatar").change(function () { // 获取用户选中的文件对象 var file_obj = $(this)[0].files[0]; // 获取文件对象的路径 var reader = new FileReader(); reader.readAsDataURL(file_obj); // 修改img的src属性, src= 文件对象的路径 reader.onload = function () { $(".avatar_img").attr("src", reader.result) }; }); // 基于ajax提交数据 $(".reg_btn").click(function () { // console.log($("#form").serializeArrray()); var formdata = new FormData(); var request_data = $("#form").serializeArray(); $.each(request_data, function (index, data) { formdata.append(data.name, data.value) }); formdata.append("avatar", $("#avatar")[0].files[0]); // 文件对象 $.ajax({ url:"", type: "post", contentType: false, processData: false, data: formdata, success: function (data) { if(data.user){ // 注册成功 location.href="/login/" } else { // 注册失败 //console.log(data.msg) // 清空错误信息 $("span.error").html(""); $(".form-group").removeClass("has-error"); // 展示本次提交的错误信息 $.each(data.msg, function (field, error_list) { console.log(field, error_list); // 全局的错误信息 if (field=="__all__"){ $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error"); } $("#id_" + field).next().html(error_list[0]); $("#id_" + field).parent().addClass("has-error"); }) } } }) }) </script> </body> </html>
1 def register(request): 2 """ 3 注册视图函数: 4 get请求响应注册页面 5 POst(Ajax)请求,校验字段,响应字典 6 :param request: 7 :return: 8 """ 9 if request.is_ajax(): 10 print(request.POST) 11 form = UserForm(request.POST) 12 13 response = {"user": None, "msg": None} 14 if form.is_valid(): 15 response["user"] = form.cleaned_data.get("user") 16 17 # 生成一条用户记录 18 user = form.cleaned_data.get("user") 19 print("user", user) 20 pwd = form.cleaned_data.get("pwd") 21 email = form.cleaned_data.get("email") 22 avatar_obj = request.FILES.get("avatar") 23 24 extra = {} 25 if avatar_obj: 26 extra["avatar"] = avatar_obj 27 UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra) 28 29 else: 30 print(form.cleaned_data) 31 print(form.errors) 32 response["msg"] = form.errors 33 34 return JsonResponse(response) 35 36 form = UserForm() 37 return render(request, "register.html", {"form": form}) 38 39 40 return render(request, "register.html")