批量插入数据


        bulk_create
         # 1.往书籍表中插入数据 1000
            # for i in range(1000):  # 这种插入方式 效率极低
            #     models.Book.objects.create(title='第%s本书'%i)
            book_list = []
            for i in range(100000):  # 时间还是很短  两者差距很大
                book_list.append(models.Book(title='第%s本书'%i))
            models.Book.objects.bulk_create(book_list)  # 批量插入数据
            # 2.将刚刚插入的数据查询出来展示到前端
            book_queryset = models.Book.objects.all()
            return render(request,'index.html',locals())
        

自定义分页器

'''
思路:
    首先一个大概思路是在后端把逻辑写完之后,再在前端把数据展示出来。

    1.从前端(用户点击按钮,get请求),获取用户想要访问的页面数(拿到的是字符串,需要转成int类型,后面做运算)
    2.规定每页展示的数据条数
    3.规定展示的起始页和终止页
    4.统计数据的总条数(从数据库拿到全部数据,count一下)
    5.通过一定的数学计算,判断数据要多少页才能展示完(取余数)

    6.所有计算完成后,对数据对象列表进行切片操作,然后发到前端进行展示。


'''
#view.py

def index(request):
# 1.获取用户想要访问的页码数
    current_page = request.GET.get('page',1)  # 如果没有page参数 默认就展示第一页
    # 转成整型
    current_page = int(current_page)
    # 2.每页展示10条数据
    per_page_num = 10

    # 3.定义起始位置和终止位置
    start_page = (current_page - 1) * per_page_num
    end_page = current_page * per_page_num

    # 4.统计数据的总条数
    book_queryset = models.Book.objects.all()
    all_count = book_queryset.count()

    # 5.求数据到底需要多少页才能展示完
    page_num, more = divmod(all_count,per_page_num)  # divmod(100,10)
    if more:
        page_num += 1
    # page_num就觉得了 需要多少个页码
    page_html = ''
    xxx = current_page  # xxx就是用户点击的数字
    if current_page < 6:
         current_page = 6
    for i in range(current_page-5,current_page+6):
        if xxx == i:
            page_html += '<li class="active"><a href="?page=%s">%s</a></li>'%(i,i)
        else:
            page_html += '<li><a href="?page=%s">%s</a></li>' % (i, i)

    book_queryset = book_queryset[start_page:end_page]
    return render(request,'index.html',locals())

django封装好的分页器


## 前端代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</head>
<body>

{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}

</body>
</html>




## 后端代码
from app01.utils.mypage import Pagination
# 使用封装好的分页器代码
def login(request):
    book_queryset = models.Book.objects.all()
    current_page = request.GET.get('page',1)
    all_count = book_queryset.count()
    # 1.实例化产生对象
    page_obj = Pagination(current_page=current_page,all_count=all_count)
    # 2.对真实数据进行切片操作
    page_queryset = book_queryset[page_obj.start:page_obj.end]
    return render(request,'login.html',locals())

创建多对多表关系的三种方式

    创建多对多表关系的三种方式
        1.全自动(推荐使用**)
            好处在于 django orm会自动帮你创建第三张关系表
            但是它只会帮你创建两个表的关系字段 不会再额外添加字段
            虽然方便 但是第三张表的扩展性较差  无法随意的添加额外的字段
            class Book(models.Model):
                ...
                authors = models.ManyToManyField(to='Author')

            class Author(models.Models):
                ...

        2.纯手动(不推荐)
            好处在于第三张表可以任意的添加额外的字段
            不足之处在于orm查询的时候  很多方法都不支持    查询的时候非常麻烦
            class Book(models.Model):
                ...

            class Author(models.Models):
                ...

            class Book2Author(models.Model):
                book_id = models.ForeignKey(to='Book')
                author_id = models.ForeignKey(to='Author')
                create_time = models.DateField(auto_now_add=True)
                ...

        3.半自动(推荐使用******)
            手动建表 但是你会告诉orm 第三张表是你自己建的
            orm只需要给我提供方便的查询方法
            第三种虽然可以使用orm查询方法
            但是不支持使用
                add()
                set()
                remove()
                clear()



            class Book(models.Model):
                ...
                authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book','author'))
                # 注意to 里面放的是表名,表示和谁连接, through表示 是通过哪张表连接的
                # through_fields表示 通过什么字段进行连接的,并且第一个写的必须是,
                # 通过哪个字段查询到当前字段的。


            class Author(models.Model):
                ...
                books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author', 'book'))

            class Book2Author(models.Model):
                book = models.ForeignKey(to='Book')
                author = models.ForeignKey(to='Author')
                create_time = models.DateField(auto_now_add=True)
                ...
            # 1.半自动 一定要加两个额外的参数
                through='Book2Author', through_fields=('book','author')
            # 2.后面字段的顺序
                由第三张表通过哪个字段查询单表 就把哪个字段放前面

        """
        在设计项目的时候 一定要给自己留后路 防止后续的迭代更新

        """

form校验组件

'''
#注意:
    校验数据通常是前后端都有校验
    前端可有可无但是后端必须有


# 需求:
    注册功能
        用户输入的用户名中,不能包含'我',这个字段,如果包含了,就提示用户  输入的内容不符合规范
        用户输入密码,不能小于3位,如果小于3位,那么提示用户 密码长度不够
'''

'''
根据上面的需求,可以有以下思路:
 1.搭建前端页面                              ==>       渲染页面
 2.获取前端用户提交的数据校验                  ===>       检验数据
 3.对数据的校验的结果 展示到前端页面给用户查看    ==>        展示错误信息
'''




##############
##自己写的版本##
##############


#前端代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</head>

##核心代码(input框,加一个行内标签,用于标识错误信息(红色style修饰一下),这两个放在一行)
<body>
<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        <span style="color: red"></span>
    </p>
    <p>password:
        <input type="text" name="password">
        <span style="color: red"></span>
    </p>
    <input type="submit">
</form>
</body>
</html>


#后端代码
def register(request):
    ##因为要将对象中的信息发给前端(展示错误信息),而在初始页面错误信息不应该显示,所以要在全局设置一个值为空的字典,这样,开始是Get请求,前端拿到back_dic.username就是空
    back_dic = {'username': '', 'password': ''}
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '我'in username:
            #提示信息
            back_dic['password'] = '输入的内容不符合规范'
        if len(password) < 3:
            back_dic["username"] = '密码不能少于三位'
    return render(request, 'reg.html', locals())






####################
##form组件的初次使用##
####################
'''
首先讲一下,form组件可以帮你完成,渲染页面、校验数据以及展示错误信息
'''

#1.自己先写一个类,继承forms.Form,主要是设计自己的表单样式,方便后期进行使用管理

from django import forms

class MyRegForm(forms.Form):
    username = forms.CharField(min_length=3, max_length=8)
    password = forms.CharField(min_length=3, max_length=8)
    email = forms.EmailField()



        #如何渲染页面


        ##前端核心代码

        <p>三种渲染前端页面的方式,都是用户名,密码和邮箱</p>

        <p>第一种渲染前端页面的方式:封装程度太高了 标签样式及参数不方便调整 可扩展性差(不推荐使用)
        {{ form_obj.as_p }} #p标签包裹
        {{ form_obj.as_ul }} #li标签包裹
        </p>

        <p>第二种渲染页面的方式:扩展性较高 不足之处在于 需要你手写的代码量比较多(不推荐使用)</p>
        <p>
            # 可以通过后端设置label标签,对前端进行个性化展示
            {{ form_obj.username.label }}{{ form_obj.username }}
        </p>
        <p>
            {{ form_obj.password.label }}{{ form_obj.password }}
        </p>
        <p>
            {{ form_obj.email.label }}{{ form_obj.email }}
        </p>

        <p>第三种渲染前端页面的方式:代码量和扩展性都很高(推荐使用)</p>
        <form action="" method="post" novalidate>
        # 这个参数是取消前端帮我们校验的信息
            {% for foo in form_obj %}
            <p>
                {{ foo.label }}:{{ foo }}
                <span style="color: red">{{ foo.errors.0 }}</span> # foo.errors得到的是错误信息的列表,这里面取第1个,就是把字符串打印出来,注意:queryset对象取值都是点出来的。
            </p>
            {% endfor %}
            <input type="submit">
        </form>



        #如何校验数据

            from app01 import views
            # 1.给自定义的类传一个字典
            obj = views.MyRegForm({'username':'jason','password':'12','email':'123'})
            # 2.判断数据是否全部合法
            obj.is_valid()  # 只有数据全部符合要求(大小,格式符合规定)才会是True
            Out[4]: False
            # 3.查看符合校验规则的数据并打印出来
            obj.cleaned_data
            Out[5]: {'username': 'jason'}
            # 4.将不符合规定的数据及其错误信息打印出来
            obj.errors
            Out[6]:
            {
                'password': ['Ensure this value has at least 3 characters (it has 2).'],
                'email': ['Enter a valid email address.']
             }

            # 5.校验数据的时候 默认情况下类里面所有的字段都必须传值
            obj = views.MyRegForm({'username':'jason','password':'123'})
            obj.is_valid()
            Out[12]: False
            obj.errors
            Out[13]: {'email': ['This field is required.']}
            # 6.默认情况下可以多传 但是绝对不能少传
            obj = views.MyRegForm({'username':'jason','password':'1233',
                                   'email':'[email protected]','xxx':'ooo'})
            obj.is_valid()
            Out[15]: True






######################
###form组件字段的扩充###
######################


from django import forms


class MyRegForm(forms.Form):
    username = forms.CharField(min_length=3,max_length=8,label='用户名', #前端属性名展示

                               error_messages={ #用于把原始的英语错误信息转换成中文的错误信息

                                   'min_length':'用户名最短三位',
                                   'max_length':'用户名最长八位',
                                   'required':'用户名不能为空'
                               },initial='我是初始值',required=True

                               #第一个参数设置初始值,第二个是判断是否为空,为True表示需要值,不能为空,默认是true
                              widget= widgets.TextInput(attrs={'class':'form-control others'}) #最后这个参数是给这个框加上一个 表单样式



    password = forms.CharField(min_length=3,max_length=8,label='密码',error_messages={
        'min_length':'密码最短三位',
        'max_length':'密码最长八位',
        'required':'密码不能为空'
    },widget=widgets.PasswordInput()) #这个参数相当于<input type = 'password'> 即输入的是密文形式



    email = forms.EmailField(label='邮箱',error_messages={
        'invalid':'邮箱格式不正确'
    },required=false, widget=widgets.EmailInput(attrs={'class':'form-control'}))#最后一个参数指的是邮箱格式得样式







    phone = forms.CharField(label='手机号',validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]) #固定写法,可以按正则来约束电话号码,更详细的话遇到后直接搜索  手机号输入框 正则约束


    gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=widgets.RadioSelect() #表示这个是个单选框
    )




    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=widgets.Select() #这是个下拉形式的复选框,可以选多个
    )

    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=widgets.SelectMultiple() #这是个可选多个的复选框,一次性展示出来
    )

    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput() #复选框,可以打对勾,用于确认信息
    )

    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple() #这是个可以通过打对勾,选多个的复选框
    )





###################
##forms组件钩子函数##
###################

'''
钩子函数,就是扩充一下错误信息的,把不符合输入框约束的错误都打印出来。
'''
#首先是在类中已经定义的字段,然后打出clean, 会自动提示(选择clean_username),这个是固定写法,前面的字段门槛过了之后,再进入这里进行判断

#下面这个是针对单个字段的局部钩子 检查用户名
def clean_username():
    username = self.cleaned_data.get('username')
    if '我'in username:
        # 给username字段下面提示错误信息,也是固定写法
        self.add_error('username', '用户名命名不规范')
    return username #校验完毕之后,要返回

#下面这个是针对多个字段的全局钩子  校验两次密码输入是否一致
def clean(self):
    password = self.cleaned_data.get('password')
    confirm_password = self.cleaned_data.get('confirm_password')
    if not password == confirm_password:
        self.add_error('confirm_password','两次密码不一致')   # 错误信息直接加到该对象的error里面了
    return self.cleaned_data #校验完毕,把所有正确数据返回
01-11 00:40