• 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 {
                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

      

  • 相关阅读:
    命令拷屏之网络工具
    PHP 设计模式 笔记与总结(1)命名空间 与 类的自动载入
    Java实现 计蒜客 1251 仙岛求药
    Java实现 计蒜客 1251 仙岛求药
    Java实现 计蒜客 1251 仙岛求药
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 LeetCode 143 重排链表
    Java实现 LeetCode 143 重排链表
  • 原文地址:https://www.cnblogs.com/mike-liu/p/9703325.html
Copyright © 2020-2023  润新知