Web框架开发-BBS(表、登录、注册、文件上传)

 

 

 

 

 

 

一、博客系统表关系

 

 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
models.py

 

  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")
views.py

 

 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
validCode.py

 

 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>
login.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>
register.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")
views.py

 

  

posted @ 2018-09-28 17:04  芳姐  阅读(1508)  评论(0编辑  收藏  举报