django组件

内容概要

  • 多对多三种创建方式
  • django内置序列化组件(drf前身)
  • ORM批量操作数据(ORM操作优化)
  • 自定义分页器
  • form组件

多对多三种创建方式

  1. 全自动创建

    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name='书名')
        authors = models.ManyToManyField(to='Author')
    
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name='姓名')
    

    优势:自动创建第三张表, 并且提供了add、remove、set、clear以及正反向概念

    劣势第三张表无法创建更多的字段 扩展性较差

  2. 全手动

    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name='书名')
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name='姓名')
    
    
    class Book2Author(models.Field):
        book = models.ForeignKey(to=Book, on_delete=models.CASCADE)
        author = models.ForeignKey(to=Author, on_delete=models.CASCADE)
        others = models.CharField(max_length=32, verbose_name='其他')
        join_time = models.DateField(auto_now_add=True, verbose_name='绑定时间')
    

    优势:第三张表完全由自己创建,扩展性强

    劣势:编写繁琐 并且不在支持add、remove、set、clear以及正方向概念

  3. 半自动

    class Book1(models.Model):
        title = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Author1',
                                         through='Book1ToAuthor1',
                                         through_fields=('book', 'author'))  # 在哪个表就先填那个字段
    
    
    class Author1(models.Model):
        name = models.CharField(max_length=32)
    
    
    class Book1ToAuthor1(models.Model):
        book = models.ForeignKey(to=Book1, on_delete=models.CASCADE)
        author = models.ForeignKey(to=Author1, on_delete=models.CASCADE)
        join_time = models.DateField(auto_now_add=True)
    

    优势:第三张表完全由自己创建 扩展性强 正反向概念依然可见

    劣势:编写繁琐 不在支持 add、set、remove、clear

django内置序列化组件(drf前身)

前后端分离的项目 视图层只需要返回json格式的数据即可

def home_func(request):
    # 1. 查询所有的数据对象
    book_list = models.Books.objects.all()
    # 2.封装成大字段返回
    data_dict = {}
    for book_obj in book_list:
        temp_dict = {}
        temp_dict['pk'] = book_obj.pk
        temp_dict['name'] = book_obj.name
        temp_dict['price'] = book_obj.price
        data_dict[book_obj.pk] = temp_dict
    from django.http import JsonResponse
    return JsonResponse(data_dict)

序列化组件(django自带 后续学更厉害的drf)

# 导入内置序列化模块
from django.core import serializers

def home_func(request):
    # 调用该模块下的方法,第一个参数是你想以什么样的
    # 方式序列化你的数据
    book_list = models.Books.objects.all()
    res = serializers.serialize('json', book_list)
    return HttpResponse(res)

批量操作数据

def home_func(request):
    # 1. 往book表种中插入数据
    for i in range(1, 1000):
        models.Bok.objects.create(title='第%s本' % i)
    from django.core import serializers
    bok_list = models.Bok.objects.all()
    res = serializers.serialize('json', bok_list)
    return HttpResponse(res)

这只方式查了十秒还每搞完

查了八百多条数据

使用orm提供的批量插入数据

def home_func(request):
    # 1. 往book表种中插入数据
    book_obj_list = []
    for i in range(1, 1000):
        book_obj = models.Bok(title='第%s本' % i)
        book_obj_list.append(book_obj)
    # 使用orm提供的批量插入操作 1000条数据
    models.Boks.objects.bulk_create(book_obj_list)
    # 批量更新
    # models.Boks.objects.bulk_update(book_obj_list)
    book_queryset = models.Boks.objects.all()
    from django.core import serializers
    res = serializers.serialize('json', book_queryset)
    return HttpResponse(res)

基本上不到一秒全部插入完

分页器思路

推到流程

  1. queryset支持切片操作(整数)

  2. 研究各个参数之间的数学关系

    每页固定展示多少条数据、起始位置、终止位置

  3. 自定义页码参数

    ​ page = request.GET.get('page')

  4. 前端展示分页器样式

  5. 总页码问题

    divmod方法

  6. 前端页面页码个数渲染问题

    后端产生 前端渲染

实现

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'js_dir/jquery-1.12.4.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                    {% for foo in obj_queryset %}
                        <p>{{ foo.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>

                      {{ html_str|safe }}
                    <li>
                      <a href="#" aria-label="Next">
                        <span aria-hidden="true">&raquo;</span>
                      </a>
                    </li>
                  </ul>
                </nav>
            </div>
        </div>
    </div>


</body>
def home_func(request):
    """分页"""
    # 先把数据传过去
    """
    需要三个数据 
    起始的 从那条数据开始
    结束的 到那条数据结束
    展示  每页展示几行
    还需要 前端传过来的 那一页
    """
    page = request.GET.get('page')
    if not page:
        page = 1
    else:
        page = int(page)

    obj_list_len = models.Boks.objects.all().count()
    all_page, mm = divmod(obj_list_len, 15)
    if mm:
        all_page += 1
    html_str = ''
    xxx = page
    if xxx < 6:
        xxx = 6
    elif xxx > all_page-5:
        xxx = all_page-5
    for i in range(xxx-5, xxx+6):
        if page == i:
            a = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            a = '<li><a href="?page=%s">%s</a></li>' % (i, i)
        html_str += a
    lok = 15

    start = (page-1) * lok
    end = page * lok

    obj_queryset = models.Boks.objects.all()[start:end]
    return render(request, 'homePage.html', locals())

自定义分页器的使用

django自带的分页器模块但是使用起来很麻烦 所以我们自己封装一个

def home_func(request):
    from app01.utils.mypage import Pagination
    boks_queryset = models.Boks.objects.all()
    current_page = request.GET.get('page')
    page_obj = Pagination(current_page=current_page, all_count=boks_queryset.count())
    page_queryset = boks_queryset[page_obj.start: page_obj.end]
    return render(request, 'homePage.html', locals())
{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>

{% endfor %}
{{ page_obj.page_html|safe }}

分页器

class Pagination(object):                       # 显示数据         页码个数
    def __init__(self, current_page, all_count, per_page_num=11, pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)

form组件

form组件

  1. 自动校验数据
  2. 自动生成标签
  3. 自动展示信息
from django import forms


class MyForm(forms.Form):
    # 字符长度 最短为 3 最长为8
    username = forms.CharField(min_length=3, max_length=8)
    # 年龄 最小值为 0  最大值 200
    age = forms.IntegerField(min_value=0, max_value=200)
    # 必须符合邮箱格式
    email = forms.EmailField()

from app01 import views
obj = views.MyForm({'username': '123', 'age': 12, 'email': 123})
obj.is_valid()
False
obj.cleaned_data
{'username': '123', 'age': 12}
obj.errors
{'email': ['Enter a valid email address.']}
  1. 只校验类中定义的字段对应的数据 多传的根本不做任何操作
  2. 默认情况下类中定义好的字段都是必填的
posted @ 2022-12-20 23:09  可否  阅读(16)  评论(0编辑  收藏  举报