BBS项目

BBS表关系:

静态文件配置与auth默认表配置

# 静态文件配置
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
# auth默认表
AUTH_USER_MODEL = 'app01.UserInfo'

注册:

form主键

 1 from django import forms
 2 from django.forms import widgets
 3 from app01 import models
 4 
 5 
 6 # 定义form主件
 7 class MyForm(forms.Form):
 8     username = forms.CharField(max_length=8, min_length=3, label='用户名:',
 9                                error_messages={'required': '用户名不能为空', 'max_length': '用户名最大为8位',
10                                                'min_length': '用户名最小为3位'},
11                                widget=widgets.TextInput(attrs={'class': 'form-control'}))
12     password = forms.CharField(max_length=8, min_length=3, label='密码:',
13                                error_messages={'required': '密码不能为空', 'max_length': '密码最大为8位', 'min_length': '密码最小为3位'},
14                                widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
15     re_password = forms.CharField(max_length=8, min_length=3, label='确认密码:',
16                                   error_messages={'required': '确认密码不能为空', 'max_length': '确认密码最大为8位',
17                                                   'min_length': '确认密码最小为3位'},
18                                   widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
19     email = forms.EmailField(label='邮箱', error_messages={'required': '邮箱不能为空:',
20                                                          'invalid': '邮箱格式错误'},
21                              widget=widgets.EmailInput(attrs={'class': 'form-control'}))
22 
23     # 定义局部钩子 校验用户名是否存在
24 
25     def clean_username(self):
26         username = self.cleaned_data.get('username')
27         user_obj = models.UserInfo.objects.filter(username=username).first()
28         if user_obj:
29             self.add_error('username', '用户名已经存在')
30         return username
31 
32     # 局部钩子函数是检验一个字段的 而全局钩子函数的话是校验多个字段的 比如说 只校验用户名是否存在这个就是要用到钩子函数
33     # ↓↓↓↓↓↓↓↓
34     # 而两个字段以上或多个 比如说 密码 确认密码 校验 密码是否一致
35     # 定义全局钩子  校验密码是否一致
36     def clean(self):
37         password = self.cleaned_data.get('password')
38         re_password = self.cleaned_data.get('re_password')
39         if password == re_password:
40             return self.cleaned_data
41         self.add_error('re_password', '两次密码不一致')
form主键

model

from django.contrib.auth.models import AbstractUser


# 重写原Django的user表给其添加一些自己的字段
class UserInfo(AbstractUser):
    phone = models.BigIntegerField(null=True)  # 电话号码
    # 该字段会将接受到文件自动存放到avatar文件夹下,只存该文件的路径 比如:avatar/default.png
    create_time = models.DateField(null=True, auto_now_add=True)  # 用户创建时间
    avatar = models.FileField(upload_to='avatar/', default='/avatar/default.png/')  # 头像
    blog = models.OneToOneField(to='Blog', null=True)  # 一对一关联字段  相当于就是一张表拆分出去的表


# 个人站点
class Blog(models.Model):
    title = models.CharField(max_length=32)  # 标题
    content = models.CharField(max_length=32)  # 内容
    theme = models.CharField(max_length=255)  # 主题 样式


# 标签
class Tag(models.Model):
    name = models.CharField(max_length=32)  # 标签名称
    blog = models.ForeignKey(to='Blog', null=True)


# 分类
class Category(models.Model):
    name = models.CharField(max_length=32)  # 分类名称
    blog = models.ForeignKey(to='Blog', null=True)


class Article2Tags(models.Model):
    article = models.ForeignKey(to='Article')
    tag = models.ForeignKey(to='Tag')


# 文章
class Article(models.Model):
    title = models.CharField(max_length=64)  # 标题
    desc = models.CharField(max_length=255)  # 简介 描述
    content = models.TextField()  # 文章内容
    create_time = models.DateField(auto_now_add=True)  # 文章的创建时间
    # 查询优化
    comment_num = models.IntegerField()  # 评论数
    up_num = models.IntegerField()  # 点赞数
    down_num = models.IntegerField()  # 点踩数
    blog = models.ForeignKey(to='Blog', null=True)  # 个人站点与文章一对多字段
    category = models.ForeignKey(to='Category', null=True)  # 分类与文章的一对多字段
    tags = models.ManyToManyField(to='Tag', through='Article2Tags', through_fields=('article', 'tag'))


# 点赞 点踩表
class UpAndDown(models.Model):
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    is_up = models.IntegerField()  # 0点赞 1点踩


# 评论
class Comment(models.Model):
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    content = models.CharField(max_length=255)  # 评论内容
    create_time = models.DateField(auto_now_add=True, null=True)  # 评论的创建时间
    parent = models.ForeignKey(to='self', null=True)  # 自关联 用self
model

前端页面

 1 <div class="container">
 2     <div class="row">
 3         <div class="col-md-6 col-md-offset-3 col-sm-6 ">
 4             <h1>注册界面</h1>
 5             <form id="id_form">
 6                 {% csrf_token %}
 7                 {% for foo in myform %}
 8                     <div class="form-group">
 9                         <label for="{{ foo.auto_id }}">{{ foo.label }}</label>
10                         {{ foo }}
11                         <span class="errors pull-right" style="color: red"></span>
12                     </div>
13 
14                 {% endfor %}
15 
16             </form>
17             <div class="form-group">
18                 <label for="id_file">请选择头像:
19                     <img src="/static/img/default.png" alt="avatar" title="用户头像"
20                          id="id_img">
21                 </label>
22                 <input type="file" name="myfile" id="id_file">
23             </div>
24             <input type="submit" name="" id="id_register" value="注册" class="btn btn-primary pull-right">
25         </div>
26 
27     </div>
28 </div>
29 <script>
30     $('#id_file').change(function () {
31         // 获取用户上传的文件
32         let file = this.files[0];
33         {#alert(file)#}
34         // 生成内置对象
35         let fileReder = new FileReader();
36         // 将获取到的文件传给内置对象
37         fileReder.readAsDataURL(file);
38         // 这一步操作就是让上传的图片先加载完成 然后在把新图片覆盖旧图片
39         fileReder.onload = function () {
40             $('#id_img').attr('src', fileReder.result) // 获取img标签替换src属性   fileReder.result就是一张图片的路径
41         };
42 
43     });
44     $('#id_register').on('click', function () {
45         // 由于是有图片 所以送fromdata发送数据 实例化一个fromdata对象
46         let fromdata = new FormData();
47         $.each($('#id_form').serializeArray(), function (index, obj) {
48             fromdata.append(obj.name, obj.value)
49         });
50         fromdata.append('myfile', $('#id_file')[0].files[0]);
51         $.ajax({
52             url: '/register/',
53             type: 'post',
54             data: fromdata, // {'username':'zk','password':'123','re_password,'123','email':'123@qq.com'}
55             processData: false,
56             contentType: false,
57             success: function (data) {
58                 if (data.code == 100) {
59                     location.href = data.url
60 
61                 } else {
62                     $.each(data.msg, function (index, obj) {
63                         console.log(index, obj);
64                         // index,obj 打印出来的结果就是 index==标签里面name的名字 obj 等于后端传过来的msg
65                         let targetId = '#id_' + index;  // 这里拼接就是 拼接出一个#id_username的形式 方便找到标签
66                         {#$(targetId).next().html(obj[0].parent().addClass('has-error'))#}
67                         // 这里找到input标签然后取他下面一个标签 并且把值赋给span的文本 然后找到当前的父标签给他增加样式 input框就标红了
68                         $(targetId).next().html(obj[0]).parent().addClass('has-error')
69 
70                     })
71                 }
72             }
73         })
74     });
75     $('input').focus(function () {
76         $(this).next().html('').parent().removeClass('has-error')
77     })
78 
79 </script>
前端

路由

url(r'^register/', views.register, name='register'),

 登录

前端

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <h1 class="text-center">登录</h1>
            {% csrf_token %}
            <div class="form-group">
                <label for="id_username">
                </label>
                用户名:<input type="text" name="" id="id_username" class="form-control">
            </div>
            <div class="form-group">
                <label for="id_password">
                </label>
                密码:<input type="password" name="" id="id_password" class="form-control">
            </div>
            <div class="row">
                <div class="col-sm-6">
                    <div class="form-group">
                        <label for="id_code">
                        </label>
                        验证码:<input type="text" name="" id="id_code" class="form-control">
                    </div>
                </div>
                <div class="col-sm-6">
                    <div class="form-group">
                        <img src="/get_code/" alt="" id="id_img" width="260px" height="35px" style="margin-top: 20px"
                             title="点击刷新验证码">
                    </div>

                </div>
                <span style="margin-left: 20px;color: red" id="id_span"></span>
            </div>
            <div class="form-group">
                <input type="submit" name="" id="id_login" class="btn btn-primary" value="登录">
            </div>
        </div>
    </div>
</div>
<script>
    $('#id_img').click(function () {
        let imge = $(this).attr('src');
        $(this).attr('src', imge += '?')
    });
    $('#id_login').on('click', function () {
        $.ajax({
            url: '/login/',
            type: 'post',
            data: {
                'username': $('#id_username').val(),
                'password': $('#id_password').val(),
                'code': $('#id_code').val(),
                'csrfmiddlewaretoken': '{{ csrf_token  }}'
            },
            success: function (data) {
                if (data.code == 100) {
                    location.href = data.url
                }
                else if (data.code == 101) {

                    $('#id_span').html(data.error)
                }
                else {
                    $('#id_span').html(data.msg)

                }
            }
        })
    })
</script>
前端与随机生成验证码

后端

from PIL import Image, ImageDraw, ImageFont
# 登录功能
def login(request):
    back_dic = {'code': 100, 'msg': '', 'error': '', 'url': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        code = request.POST.get('code')
        if code.lower() == request.session.get('code').lower():
            user_obj = auth.authenticate(username=username, password=password)
            if user_obj:
                auth.login(request, user_obj)
                back_dic['msg'] = '登录成功'
                back_dic['url'] = '/index/'
            else:
                back_dic['code'] = 101
                back_dic['error'] = '用户名密码错误'
        else:
            back_dic['code'] = 102
            back_dic['msg'] = '验证码错误'
        return JsonResponse(back_dic)
    return render(request, 'login.html')

# 随机产生RGB
def get_img_rgb():
    return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
登录与随机生成图片

补充

def get_code(request):
    # with open(r'D:\python\CodePath\BBS\avatar\timg.gif','rb')as f:
    #     data = f.read()
    img_obj = Image.new('RGB', (260, 35), color=get_img_rgb())
    # 生成一个画笔对象
    img_draw = ImageDraw.Draw(img_obj)
    # 生成一个字体对象
    img_font = ImageFont.truetype('static/font/lj.ttf', 30)
    code = ''
    # 循环产生几个验证码
    for i in range(5):
        # 随机生成0,9的数字
        random_int = str(random.randint(0, 9))
        # 随机生成小写的英文字母
        random_lower = str(chr(random.randint(97, 122)))
        # 随机生成大写的英文字母
        random_upper = str(chr(random.randint(65, 90)))
        # 选择一个字母
        temp_code = random.choice([random_int, random_lower, random_upper])
        # 写入图片中 text第一个参数是X轴Y轴坐标,第二个参数是文字,第三个参数是颜色 第四个参数是字体
        img_draw.text((30 + i * 45, 0), temp_code, get_img_rgb(), img_font)
        code += temp_code
    # 把拿到的验证码放入session表中方便后面的校验
    request.session['code'] = code
    bio = BytesIO()
    img_obj.save(bio, 'png')
    return HttpResponse(bio.getvalue())
随机成功图片

注销

url

    url(r'^logout/', views.logout,name='logout'),

后端

def logout(request):
    auth.logout(request)
    return redirect('/index/')

修改密码

后端

def edit_password(request):
    back_dic = {'code': 101, 'error': ''}
    if request.method == 'POST':
        old_password = request.POST.get('id_old_password')
        new_password = request.POST.get('id_new_password')
        re_password = request.POST.get('id_re_password')
        res = request.user.check_password(old_password)
        if res:
            if new_password == re_password:
                request.user.set_password(new_password)
                request.user.save()
                back_dic['error'] = '修改成功'
                back_dic['url'] = '/login/'
            else:
                back_dic['code'] = 102
                back_dic['error'] = '两次密码不一致'
        else:
            back_dic['code'] = 103
            back_dic['error'] = '旧密码与原密码不一致'
        return JsonResponse(back_dic)
    return render(request, 'edit_password.html', locals())
View Code

前端

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <h1 class="text-center">修改密码</h1>
            {% csrf_token %}
            <div class="form-group">
                <label for="id_username">
                </label>
                用户名:<input type="text" name="" id="id_username" class="form-control" value="{{ request.user.username }}"
                           readonly>
            </div>
            <div class="form-group">
                <label for="id_old_password">
                </label>
                旧密码:<input type="password" name="" id="id_old_password" class="form-control"/>
                <span style="color: red" id="old_span"></span>
            </div>

            <div class="form-group">
                <label for="id_new_password">
                </label>
                新密码:<input type="password" name="" id="id_new_password" class="form-control">
            </div>
            <div class="form-group">
                <label for="id_re_password">
                </label>
                确认密码:<input type="password" name="" id="id_re_password" class="form-control">
                <span style="color: red" id="new_span"></span>
            </div>
            <div class="row">
                <span style="margin-left: 20px;color: red" id="id_span"></span>
            </div>
            <div class="form-group">
                <input type="submit" name="" id="id_login" class="btn btn-primary" value="修改密码">
            </div>
        </div>

    </div>
</div>

<script>
    $('#id_login').on('click', function () {
        $.ajax({
            url: '/edit_password/',
            type: 'post',
            data: {
                'id_old_password': $('#id_old_password').val(),
                'id_new_password': $('#id_new_password').val(),
                'id_re_password': $('#id_re_password').val(),
                'csrfmiddlewaretoken': '{{ csrf_token }}'
            },
            success: function (data) {
                if (data.code == 101) {
                    location.href = data.url
                } else if (data.code == 102) {
                    $('#new_span').html(data.error)
                } else {
                    $('#old_span').html(data.error)
                }
            }
        })
    })
</script>
修改密码

主页面

 <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">博客园系统</a>
            </div>

            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="#">文章 <span class="sr-only">(current)</span></a></li>
                    <li><a href="#">随笔</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if request.user.is_authenticated %}
                        <li><a href="#">{{ request.user.username }}</a></li>
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
                               aria-haspopup="true"
                               aria-expanded="false">更多操作 <span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="{% url 'edit_password' %}">修改密码</a></li>
                                <li><a href="#">修改头像</a></li>
                                <li><a href="{% url 'logout' %}">注销</a></li>
                            </ul>
                        </li>

                    {% else %}

                        <li><a href="{% url 'login' %}">登录</a></li>
                        <li><a href="{% url 'register' %}">注册</a></li>
                    {% endif %}
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
</div>
index主页面

 

posted @ 2019-06-20 22:01  zack赵康  阅读(99)  评论(0)    收藏  举报