• django进阶版2


    批量插入数据

    在一个表中插入很多条的数据,你应该很快就能想到用create,然而事实是这样吗?

    def index(request):
        book_list=[]
        for i in range(1000):
            #models.Book.objects.create(title=f'第{i}本书')
            book=models.Book(title=f'第{i}本书')
            book_list.append(book)
        models.Book.objects.bulk_create(book_list)
        book_query=models.Book.objects.all()
        return render(request,'index.html',locals())
    
    <body>
        {%for i in book_query%}
        <p>
            {{i.title}}
        </p>
        {%endfor%}
    </body>
    

    就像上面注释的代码是不是你的想法呢,想法可以,但实现着实困难了点,一旦数据多了,就会造成数据库的庞大压力,而使用bulk_create一步到位,用哪种方法就显而易见了-。-

    自定义分页器

    这个东西听上去是不是有点d,凡是自定义的,总感觉是比一般的高端一点,反正我是这么认为的|^ _ ^|

    这里只提供思路啊,代码就由你去实现了,fighting!

    首先我们是不是需要定义一些变量来存总页数,数据总量,每页数据量等等。。。

    current_page=request.GET.get('page',1)	#获取用户想要访问的页码数,如果没有则默认第一页
    current_page=int(current_page)	#转成整形
    per_page_num=10		#定义一下每页需要多少条数据,这里定义成10条哦
    start_page=(current_page-1)*per_page_num	#每一页的初始位置
    end_page=current_page*per_page_num	#每一页的末尾位置
    book_query=models.Book.objects.all()
    all_count=book_query.count()	#统计数据总量
    #这里需要用到一个divmod方法,来求出需要的总页数
    page_num,more=divmod(all_count,per_page_num)
    if more:
        page_num+=1
    page_html='' #这是待会要传回前端页面的标签
    x=current_page #先保存一下,以免待会数据发生变化
    if current<6:	#小于第6页,就不会再往前滑动
    	current=6
    for i in range(current_page-5,current_page+6):	#一共展示11页
    	if x=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_query=book_query[start_page:end_page]
    return render(request,'index.html',locals())
    
    {% for book_obj in book_queryset %}
        <p>{{ book_obj.title }}</p>
    {% endfor %}
    <nav aria-label="Page navigation">
      <ul class="pagination">
        <li>
          <a href="#" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        {{ page_html|safe }}
        <li>
          <a href="#" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>
    

    哎,嘴上虽然说着不写代码了,手还是很诚实的,真是没办法啊-_-

    以上就是自定义分页器的内容了,不过呢,强大的python怎么会没有一个这样的模块给我们使用呢?

    就不多bb了,直接上代码

    from app01.utils.mypage import Pagination
    def login(request):
        book_query=models.Book.objects.all()
        current_page=request.GET.get('page',1)    
        all_count=book_queryset.count()
        #实例化产生对象
        page_obj=Pagination(current_page=current_page,all_count=all_count)
        #切片操作
        page_queryset=page_queryset[page_obj.start:page_obj.end]
        return render(request,'login.html',locals())
    

    模块中封装的分页器是真他妈的香啊。。。

    创建多表关系的3种方法

    全自动

    orm一上来就自己动(手建表),这个就不用我多说了吧,大家都懂的(邪魅一笑...)

    好处在于他会帮你创建第三张表,但不能对第三张表中的字段进行二次操作,扩展性就比较差了

    class Book(models.Model):
        ...
        authors = models.ManyToManyField(to='Author')
    
    class Author(models.Models):
        ...
    

    全手动

    这个一看就感觉很麻烦了吧,而且竟然还有另外的缺点,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)
        ...
    

    半自动

    orm亲儿子,懂吧?

    推荐指数6颗星,手动建表,但是会通知orm这表是自己建的,orm提供各种方法就行了,不过有四种方法仍然不支持add,set,remove,clear,不过问题不大哈

    class Book(models.Model):
        ...
        authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book','author'))
    
    '''
    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组件

    万万没想到,从这里才开始重点,我太难了啊 T.T

    开始了啊,加入我们要设计一个注册页面,用户name不能包含dsb这串字符,密码不小于3位,这显然比较简单

    def reg(request):
        back_dic={'username':'','password':''}
        if request.method=='POST':
            username=request.POST.get('username')
            password=request.POSt.get('password')
            if 'dsb' in username:
                back_dic['username']='你输入的用户名不符合社会主义核心价值观'
            if len(password)<3:
                back_dic['password']='太短了哦,嫌弃ing'
        return render(request,'reg.html',local())
    
    <form action="" method="post">
        <p>username:
            <input type="text" name="username">
            <span style="color: red">{{ back_dic.username }}</span>
        </p>
        <p>password:<input type="text" name="password">
        <span style="color: red">{{ back_dic.password }}</span>
        </p>
        <input type="submit">
    </form>
    

    这样写起来,如果有不同的输入错误情况显然比较麻烦,所以就要用到form组件了

    首先,写一个类

    from django import forms
    
    class Myform(forms.Form):
        username=forms.CharField(min_length=3,max_length=8)
        password=forms.CharField(min_length=3,max_length=8)
        email=forms.EmailField()
    #如何校验数据
    from app01 import views
    obj=views.Myform({'username':'jason','password':'123','email':'123'})
    #判断数据是否合法
    obj.is_valid()
    #查看符合条件的数据
    obj.cleaned_data
    #查看不符合条件的数据
    obj.errors
    #需要注意的是,所有的参数必须传值,可以多传,不能少传
    

    如何渲染页面

    第一种方式

    封装成度太高,可扩展性差

    <p>
    {{form_obj.as_p}}
    {{form_obj.as_ul}}
    </p>
    

    第二种方式

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

    手写代码量太多,明显不方便

    第三种方式

    推荐使用

    {% for foo in form_obj %}
    <p>{{ foo.label }}{{ foo }}</p>
    {% endfor %}
    

    如何显示错误信息

    由于form组件会自动前端校验数据,但前端校验又不太安全,所以我们取消他,来后端校验

    在前端中的form表单中添加参数novalidata即可

    <!--展示错误信息   用对象点errors.0-->
    <form action="" method="post" novalidate>
        {% for foo in form_obj %}
        <p>
            {{ foo.label }}:{{ foo }}
            <span style="color: red">{{ foo.errors.0 }}</span>
        </p>
        {% endfor %}
        <input type="submit">
    </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=False
                                  )
        password = forms.CharField(min_length=3,max_length=8,label='密码',error_messages={
                                    'min_length':'密码最短三位',
                                    'max_length':'密码最长八位',
                                    'required':'密码不能为空'
                                })
        email = forms.EmailField(label='邮箱',error_messages={
                                    'required':'邮箱不能为空',
                                    'invalid':'邮箱格式不正确'
                                },required=False)
    

    forms组件钩子函数

    针对字段 你可以做额外的校验 通过钩子函数

    局部钩子

    # 当你需要对某一个字段数据进行额外的一些列校验 你可以考虑使用钩子函数
    # 针对单个字段的  使用局部钩子
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if 'dsb' in username:
            # 给username字段下面提示错误信息
            self.add_error('username','用户名不符合社会主义核心价值观')
        return username
    

    全局钩子

    def clean(self):
        password=self.cleaned_data.get('password')
        if not password == confirm_password:
            self.add_error('confirm_password','两次密码不一致')
        return self.cleaned_data
            
    

    正则校验

    from django import forms
    from django.forms import Form
    from django.core.validators import RegexValidator
    
    class MyForm(Form):
        user = forms.CharField(
            validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
        )
                
    

    改变input框的属性值

    widget= widgets.TextInput()
    widget=widgets.PasswordInput()
    如何让forms组件渲染出来的input框有form-control类属性
    widget= widgets.TextInput(attrs={'class':'form-control others'})  # 如果有多个类属性 空格隔开
    widget=widgets.PasswordInput(attrs={'class':'form-control others'})
    
  • 相关阅读:
    git使用
    Git常用命令梳理
    git fetch 更新远程代码到本地仓库
    理解RESTful架构
    漫谈五种IO模型(主讲IO多路复用)
    python 单下划线/双下划线使用总结
    闰秒导致MySQL服务器的CPU sys过高
    闰秒问题
    Java线上应用故障排查之一:高CPU占用
    ZooKeeper安装与配置
  • 原文地址:https://www.cnblogs.com/leaf-wind/p/11761674.html
Copyright © 2020-2023  润新知