day20--注册功能及首页

1. 补充label标签
1. label标签是用来和获取用户输入的那些标签搭配使用的
input
文本类
checkbox
radio
file
select
textarea
2. 两种搭配方式--------关联后,点击名称即可获取后面标签的焦点
         1. 通过for属性建立关联,关联的是id值
 <label for="id_username">用户名</label>
 <input type="text" class="form-control" id="id_username" name="username" placeholder="用户名">
         2. 直接用label标签包输入框
 <label >用户名<input type="text" class="form-control"  name="username" placeholder="用户名"></label>
2.ajax上传文件:--局部刷新
enctype="multipart/form-data"二进制上传
ajax上传文件,可以不用写form表单,
1.但是提交不能写submit,写button即可,否则会刷新整个界面
注意固定写法
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    $("#b1").click(function () {
        // 先生成一个FormData对象
        // 将要提交的数据 append 到FormData对象中
        var fd = new FormData();
        fd.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
        fd.append("avatar", $("#i1")[0].files[0]);
        $.ajax({
            url: "/upload/",
            type: "post",
            data: fd,
            contentType: false,  // 不让jQuery去设置提交数据的类型
            processData: false,  // 不让jQuery去处理提交的数据
            success: function (res) {
                console.log(res)
            }
        })
    });
</script>
ajax上传文件示例

3.创建用户两种方式
# 我自己去数据库创建一条用户数据
# UserInfo.objects.create(password="ooxx")
#
# # 调用auth内置的create_user方法创建用户,它会帮我做密码的加密处理
# UserInfo.objects.create_user(password="ooxx")

4.注册功能

对一个字段做校验:正则或函数
局部钩子--对一个字段
全局钩子--对多个字段进行校验
from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from fault_reporting import models
import re


# 1. 正则的校验规则
# 2. 自定义函数
def check_email(value):  # 1@1.com
    ret = re.match(r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$', value)
    if not ret:
        # 邮箱格式匹配不上
        raise ValidationError("邮箱格式不正确")
    else:
        return value


# 注册的form类
class RegisterForm(forms.Form):

    username = forms.CharField(min_length=2, label="用户名")
    password = forms.CharField(
        label="密码",
        min_length=6,
        widget=forms.widgets.PasswordInput()
    )
    re_password = forms.CharField(
        label="确认密码",
        min_length=6,
        widget=forms.widgets.PasswordInput(attrs={"class": "form-control"})
    )
    phone = forms.CharField(
        label="手机号",
        min_length=11,
        max_length=11,
        validators=[RegexValidator(r'^1[3-9]\d{9}$', "手机号码格式不正确")],
    )
    email = forms.CharField(
        label="邮箱",
        validators=[check_email, ]
    )

    def clean_username(self):
        # 做用户名不能重复的校验
        username = self.cleaned_data.get("username")
        # 去数据库查重
        is_exist = models.UserInfo.objects.filter(username=username)
        if is_exist:
            # 用户名已经被注册
            raise ValidationError("用户名已被注册")
        else:
            return username

    # 全局钩子,用来多多字段的比较
    def clean(self):
        pwd = self.cleaned_data.get("password")
        re_pwd = self.cleaned_data.get("re_password")

        if re_pwd != pwd:
            # 两次填写的密码不一致
            self.add_error("re_password", "两次密码不一致")
            raise ValidationError("两次密码不一致")
        else:
            return self.cleaned_data

    def __init__(self, *args, **kwargs):
        super(RegisterForm, self).__init__(*args, **kwargs)
        # 循环给每个字段加 class: form-control
        for field in iter(self.fields):
            self.fields[field].widget.attrs.update({
                'class': 'form-control'
            })
forms

定义一个init 自定义表单样式 class
widget=forms.widgets.TextInput(attrs={"class": "form-control"})
  def __init__(self, *args, **kwargs):
        super(RegisterForm, self).__init__(*args, **kwargs)
        # 循环给每个字段加 class: form-control
        for field in iter(self.fields):
            self.fields[field].widget.attrs.update({
                'class': 'form-control'
            })

kv相同时,键值对可以简写
bt中校验状态
jq选择器字符串拼接
显示、删除错误提示
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form class="register-form">
                {% csrf_token %}
                {% for field in form_obj %}
                <div class="form-group">
                    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                    {{ field }}
                    <span class="help-block"></span>
                </div>
                {% endfor %}
                <div class="form-group">
                    <label for="id_avatar">头像
                        <img src="/static/images/default.png" id="avatar-img" style="width: 80px;height: 80px">
                    </label>

                    <input type="file" id="id_avatar" accept="image/*" class="form-control" style="display: none">

                </div>
                <button type="button" class="btn btn-default" id="submit-btn">注册</button>
            </form>
        </div>
    </div>

</div>

<script src="/static/plugins/jquery-3.3.1.min.js"></script>
<script>
    $("#submit-btn").click(function () {
        // 因为注册功能有头像文件 数据,所以要用FormData对象提交数据
        var fd = new FormData();
        fd.append("username", $("#id_username").val());
        fd.append("password", $("#id_password").val());
        fd.append("re_password", $("#id_re_password").val());
        fd.append("phone", $("#id_phone").val());
        fd.append("email", $("#id_email").val());
        fd.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
        // avatar头像
        fd.append("avatar", $("#id_avatar")[0].files[0]);
        $.ajax({
            url: "/register/",
            type: "post",
            data: fd,
            contentType: false,  // 不让jQuery去设置提交数据的类型
            processData: false,  // 不让jQuery去处理提交的数据
            success:function (res) {
                if (res.code === 1){
                    // 有错误
                    $.each(res.error, function (k, v) {
                        // 遍历所有字段的错误提示,将错误提示信息展示在页面上对应的位置
                        console.log(k, v[0]);
                        $("#id_" + k).next().text(v[0]).parent().addClass("has-error");
                    })
                }else {
                    // 没有错误默认跳转到登录页面
                    location.href = res.url
                }
            }
        })
    });

    // 给input标签绑定获取焦点就删除错误提示的动作
    $(".register-form input").focus(function () {
        $(this).next().text("").parent().removeClass("has-error");
    });

    // 头像预览功能
    $("#id_avatar").change(function () {
        // 取到用户选中的头像文件
        var fileObj = this.files[0];
        // 新建一个FileReader对象,从本地磁盘加载文件数据
        var fr = new FileReader();
        fr.readAsDataURL(fileObj);
        // 读取文件是需要时间的
        fr.onload = function () {
            // 找到头像预览的img标签,把它的src属性设置成我读取的用户选中的图片
            $("#avatar-img").attr("src", fr.result)
        }
    });
</script>
</body>
</html>
View Code

注意:1.但是提交不能写submit
2.is_valid
3.返回正确界面 res.url
4.跳转错误界面,对应的错误提示
class RegisterView(views.View):
    def get(self, request):
        # 实例化一个form对象
        form_obj = forms.RegisterForm()
        return render(request, "register.html", locals())

    def post(self, request):
        res = {"code": 0}
        print(request.POST)
        # 对用户提交过来的数据做有效性校验
        form_obj = forms.RegisterForm(request.POST)
        if form_obj.is_valid():
            # 数据没问题
            # 去数据库创建一条用户记录
            # form_obj.cleaned_data    --> 所有经过校验的数据
            # 创建用户
            # 先从form表单的cleaned_data里把确认密码字段的数据移除, 因为UserInfo表里不需要这个字段
            form_obj.cleaned_data.pop("re_password")
            # 头像数据 ,文件对象
            avatar_obj = request.FILES.get("avatar")
            # 头像文件可以自己写代码保存在服务端,然后将保存文件的路径传到数据库中保存
            models.UserInfo.objects.create_user(**form_obj.cleaned_data, avatar=avatar_obj)
            res["url"] = "/login/"
        else:
            # 数据有问题
            res["code"] = 1
            res["error"] = form_obj.errors

        return JsonResponse(res)
RegisterView

头像上传:
1.框的显示
2.头像预览功能
3.提交
filefiled 文件类型字段会自动做文件接收操作,重名会自动判断,直接传文件对象即可
注册ok
   // 头像预览功能
    $("#id_avatar").change(function () {
        // 取到用户选中的头像文件
        var fileObj = this.files[0];
        // 新建一个FileReader对象,从本地磁盘加载文件数据
        var fr = new FileReader();
        fr.readAsDataURL(fileObj);
        // 读取文件是需要时间的
        fr.onload = function () {
            // 找到头像预览的img标签,把它的src属性设置成我读取的用户选中的图片
            $("#avatar-img").attr("src", fr.result)
        }
    });
from django.conf.urls import url, include
from django.contrib import admin
from fault_reporting import views
from django.views.static import serve
from django.conf import settings
from fault_reporting import urls as fault_report_urls

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^login/$', views.LoginView.as_view()),
    url(r'^index/$', views.index),
    url(r'^ooxx/', views.pcgetcaptcha),

    # day20 ↓
    url(r'^register/$', views.RegisterView.as_view()),
    url(r'^logout/$', views.logout),

    # 故障总结主页面
    url(r'^fault-report/', include(fault_report_urls)),  # 以fault-report开头的所有路由都交给二级路由去处理
    # 给用户上传的那些文件的路径做一个对应关系
    url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
]
urls.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

AUTH_USER_MODEL = "fault_reporting.UserInfo"

# 所有用户上传的文件
# 告诉Django项目将用户上传的文件保存在服务器端的哪个目录下
# MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_ROOT = os.path.join(BASE_DIR, "upload")

# 告诉Django项目用户通过什么前缀来访问刚才定义的那个目录
MEDIA_URL = "/media/"


LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}
settings.py

下午:

1.设计表结构,及界面书写
确定表名称 内容

一个父评论可以对应多个子评论
class Comment(models.Model):
    """
    评论
    """
    fault_report = models.ForeignKey(to="FaultReport", verbose_name="故障总结")
    user = models.ForeignKey(to="UserInfo")
    content = models.CharField(max_length=255)  # 评论内容
    create_time = models.DateTimeField(auto_now_add=True)
    # 自己关联自己的情况
    parent_comment = models.ForeignKey(to="self", null=True, blank=True)

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "评论"
        verbose_name_plural = verbose_name
Comment表

自定义多对多的表

在admin页面,快速添加数据


图标网址:http://fontawesome.dashgame.com/
查询:一对多,多对多
禁用缓存:ie10中 settings--network---勾选disabled cache

聚合和分组查询:在settings.py中配置
models中建表可不写id
使用sql语句分组查询,聚合查询--两个例子
内连接:只连接匹配的行
外链接之左连接:优先显示左表全部记录

1. ORM分组和聚合查询
annotate()
annotate()前面查的是什么就按照什么分组
.values("dept").annotate()就表示按照dept分组

2. 时间格式化函数
1. MySQL
DATE_FORMAT(字段, '格式')
2. sqlite
strftime('格式', 字段)
3. Django ORM执行原生SQL语句
1. 使用extra()执行部分sql语句
2. 类似pymysql执行方式
4. 二级路由
1. 保障系统4合1

导航条--引入两个js才会有js'的动画效果;因为js依赖于jquery

写项目下的 static 路径可以访问到内容
将用户上传的文件,在settings中设置一下,url中做对应关系查看
Django项目上传文件之后怎么查看
1. 上传的文件保存在哪里?
settings.py中 MEDIA_ROOT
2. 如何查看上传的文件
/media/xx/oo.jpg
1. settings.py中设置 MEDIA_URL="/media/"(别名)
2. urls.py中设置 media开头的路径用什么视图函数处理
url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
# 所有用户上传的文件
# 告诉Django项目将用户上传的文件保存在服务器端的哪个目录下
# MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_ROOT = os.path.join(BASE_DIR, "upload")

# 告诉Django项目用户通过什么前缀来访问刚才定义的那个目录
MEDIA_URL = "/media/"
上线时:settings  debug改为false



2.用户首页和个人中心

点击跳转展示内容--四合一形式
[lob] ----lob三个字母中随机选一个
(lob|tag|arch)--lob等三个单词中选一个

注:输入不存在的日期网址---年月日
设置时间问题
day20  2018-09-02

1. 今日内容
    1. 补充label标签
        1. label标签是用来和获取用户输入的那些标签搭配使用的
            input
                文本类
                checkbox
                radio
                file
            select
            textarea
        2. 两种搭配方式
            1. 通过for属性建立关联,关联的是id值
            2. 直接用label标签包输入框
    2. 注册功能
        1. ajax上传文件
        2. js展示错误提示信息
        3. 头像预览
        4. Django项目上传文件之后怎么查看
            1. 上传的文件保存在哪里?
                settings.py中 MEDIA_ROOT
            2. 如何查看上传的文件
                /media/xx/oo.jpg
                1. settings.py中设置 MEDIA_URL="/media/"(别名)
                2. urls.py中设置 media开头的路径用什么视图函数处理
                    url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
            
    3. CMS表结构设计
        1. 外键自己关联自己
        2. ManytoMany 使用自定义的表
            1. 为什么要用自己写的第三张关系表,而不用自动生成的?
                第三张关系表有一些额外的数据需要保存的时候
    
    4. CMS首页和个人中心页面实现
        ORM 高阶用法都在 --> https://www.cnblogs.com/liwenzhou/p/8660826.html
        1. ORM分组和聚合查询 
            annotate()
            annotate()前面查的是什么就按照什么分组
            .values("dept").annotate()就表示按照dept分组
            
        2. 时间格式化函数
                1. MySQL
                    DATE_FORMAT(字段, '格式')
                2. sqlite
                    strftime('格式', 字段)
        3. Django ORM执行原生SQL语句
            1. 使用extra()执行部分sql语句
            2. 类似pymysql执行方式
        4. 二级路由
            1. 保障系统4合1
        

JS ES6语法:https://www.cnblogs.com/liwenzhou/p/9249932.html

2. 本周任务
    1. 回去复习下正则模块的知识点(re)
    2. 回去复习下 LEFT JOIN和INNER JOIN的区别? MySQL查询语句

3. 推荐
    《漫画数据库》
    
    
    作业:写上课注册及首页的例子
day20-课上老师笔记

 

posted @ 2018-09-03 22:34  yuyou123  阅读(254)  评论(0编辑  收藏  举报