zoukankan      html  css  js  c++  java
  • Django 从0开始创建一个项目


    title: Django 从0开始创建一个项目
    tags: Django

    Django 从0开始创建一个项目

    创建Django工程及配置

    • 创建工程:django-admin starproject 项目名

    • 创建APP:Python3 manage.py startapp app名称

      • 可以创建多个app,每个app代表不同的业务,开发的时候互不影响
      • URL通过路由分发实现跳转
    • 注册APP:在后面加上app的名称

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
        'app02',
        'app03',
    ]
    
    • 配置模板路径:'DIRS': [os.path.join(BASE_DIR, 'templates')],

    • 配置静态文件路径:STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), )

    • 注释配置文件的一行: 'django.middleware.csrf.CsrfViewMiddleware',

      • 这个不注释POST请求拿不到数据

    Django的目录结构:

    |--mysite01
    |---|app01
        |----------|migrations
        |          |admin.py
        |          |apps.py
        |          |models.py
        |          |tests.py
        |          |views.py     
        |mysite01
        |--------|__init__.py
        |        |settings.py
        |        |urls.py
        |        |wsgi.py
        |
        |templates
        |
        |manage.py
    
    - migrations 存放有关数据库的文件,保存数据库的修改信息
    - admin Django自己的后台管理
    - models 通过ORM用类创建数据库和表
    - tests 单元测试
    - views 视图函数,业务处理,可以继续进行分类,此时就是views文件夹
    - apps app的配置文件
    - /mysite01/mysite01/__init__.py 配置数据库,默认是sqllite,这里配置成mysql,通过pymysql连接数据库
        import pymysql
        pymysql.install_as_MySQLdb()
    -urls 路由系统
    - wsgi web服务
    

    路由系统:

    URL-函数 的对应关系

    • /login/ 一一对应 静态路由
    • /add-user/(d+) 支持正则 动态路由
    • /add-user/(d+).html 伪静态

    具体实现

    • 第一步是在urls中导入视图函数from app01 import views
      设置URL:
        
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
        url(r'^edit/(w+)/', views.edit), # 通过正则匹配路径
    ]
    
    • 编写视图函数:

    把URL变美观 ,视图函数要有参数接收def edit(request,arg):

    from django.shortcuts import render, HttpResponse, redirect
    
    
    def index(request):
        user_list = [
            'aaa', 'bbb', 'ccc',
        ]
        return render(request, 'index.html', {'user_list': user_list})
    
    
    def edit(request, a1):
        print(a1)   # 接收函数URL的参数
        return HttpResponse("ok")
    
    • 编写index.html,关键是以/结尾
    <ul>
        {% for i in user_list %}
          <li>{{ i }}| <a href="/edit/{{ i }}/">编辑</a></li>
        {% endfor %}
      </ul>
    

    总结:

    • 在函数中通过参数a1接收url
    • 点击的标签上添加路径结尾要用/
    • url(r'^edit/(w+)/', views.edit),通常这里是以/结尾的

    正则匹配

    • 按照位置传值(有先后顺序)
    url(r'^edit/(w+)/(w+)/', views.edit),
    
    def edit(request, a1, a2):
        print(a1, a2)   # 接收函数URL的参数
        return HttpResponse("ok")
    
    • 按照名称(关键字)(?Pw+)
      • 注意是在正则表达式的括号里面传参数
      • 可以没有顺序,这个过程相当于找到相应的参数名进行赋值
    url(r'^edit/(?P<a1>w+)/(?P<a2>w+)/', views.edit),
    
    def edit(request, a1, a2):
        return HttpResponse("ok")
    

    注意:这两种是不能混合使用的,必须是统一的形式,这样才能用 *args, **kwargs.

    要主要下面的情况是,*args用来接收按位置传值,**kwargs用来接收按关键字传值的

    def edit(request, *args, **kwargs):
        return HttpResponse("ok")
    
    • 规定路由的结尾

      • 推荐用终止符$
        ^edit$

      • 伪静态(SEO)
        url(r'^edit/(w+)'.html$, views.edit),

    • 404页面,默认页面

      用户输错的时候返回404页面,或者是默认的主页

      url(r'^', views.index),
      前面的正则是不加内容的,后面写函数名

    路由分发(涉及多个app的时候)

    在处理不同业务的时候,多个app

    引入include

    • mysite下面的总的路由
    from django.conf.urls import url, include  # 在这里引入include
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^app01/', include('app01.urls')), # 先匹配app01,然后找app01下面的url
        url(r'^app02/', include('app02.urls')),
    ]
    
    • app01的路由
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^index/', views.index),
    ]
    
    • app02子路由
    from django.conf.urls import url
    from django.contrib import admin
    from app02 import views
    
    urlpatterns = [
        url(r'^index/', views.index),
    ]
    

    url 关系命名

    通过刚给URL设置别名,可以通过别名反向获取URL

    url(r'^index,views.index,name =n1)

    在index函数中就可以通过'n1'获取路径

    from django.urls import reverse
    v = reverse('n1')
        print(v)
    

    还可以自己定义,返回的路径名

    根据名字反生成URL
    name reverse

    URL的后缀可以自己任意定义

    • 通过位置参数传值
    url(r'^index/(w+)/', views.index, name='n1'),
    
    def index(request, a1): # 这里需要接受参数
        user_list = [
            'aaa', 'bbb', 'ccc',
        ]
        v = reverse('n1', args=(1,))  # 这里是等号,里面的参数可以是任意值
        print(v)
        return render(request, 'index.html', {'user_list': user_list})
    
    
    • 通过关键字
    url(r'^index/(?P<a1>w+)/', views.index, name='n1'),
    
    def index(request, a1): # 接收参数
        user_list = [
            'aaa', 'bbb', 'ccc',
        ]
        # v = reverse('n1', args=(1,))
        v = reverse('n1', kwargs={'a1': 123}) # 这里是按照关键字,形式是字典
        print(v)
        return render(request, 'index.html', {'user_list': user_list})
    
    

    应用:

      {% url “m1” %}
      {% url “m1” "m2" %} 
    
    • 在模板中的form表单中不用action写具体的路径,直接获取路径
    url(r'^login/', views.login, name='m1'),
    
    def login(request):
        return render(request, 'login.html')
    

    注意的是'm1' 要加引号

    <form method="POST" action="{% url "m1" %}">
        <input type="text">
    </form>
    
    • 在跳转路径的时候
    url(r'^index/', views.index, name='n1'),
    url(r'^edit/(w+)/', views.edit, name='n2'),
    
    

    下面的url "n2"接收URL ,i是拼接的路径,后面还可以添加 用空格分割

    <ul>
        {% for i in user_list %}
                <!-- <li>{{ i }}| <a href="/edit/{{ i }}/">编辑</a></li> -->
                <li>{{ i }}| <a href="{% url "n2" i %}/">编辑</a></li>
    
        {% endfor %}
    </ul>
    

    别名是用于权限管理

    • 前端处理 在模板中通过别名反向获取
    • Python处理

    视图函数 CBV(class based view) FBV(function based view)

    CBV是URL对应类,FBV是URL对应函数

    from表单提交
    get 查
    post 创建

    View 下面的常用方法,实现增删改查可以进入View中查看 除post get外都是ajax的方法
    """
    get 查
    post 创建
    put 更新
    delete 删除
    """

    通过Class来获取get和post的数据,具体的实现方法是继承了View类中的dispath中的handle方法,handle通过把获取的GET/POST转换成小写,然后返回函数并执行

    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)
    

    具体实现

    url

    CBV用类的方法as_view(),返回值是一个函数,在这里是get/post
    url(r'^login.html$',views.Login.as_view()),

    注意下面注释中的三点
    1 导入View

    2 继承View

    3 request 获取全部的内容

    from django.views import View # 需要导入
    class Login(View):   # 继承View
        """
        get     查
        post    创建
        put     更新
        delete  删除
        """
    
        def get(self, request):  # 还要有参数request
            return render(request, 'login.html')
    
        def post(self, request):
            user = request.POST.get('user')  # 从前端的post发送的内容中获取数据
            print(user)
            return HttpResponse('login.post')
    

    login的前端

    <form method="POST" action="/login.html">
            <input type="text" name="user">
            <input type="submit" value="提交">
    </form>
    

    自己重写dispath方法

    内部是通过反射getattr具体是dispatch函数

    关键点:
    1 super继承

    2 返回值

    3 前后加上相应的操作(批量操作),实现了装饰器的功能

    class Login(View):
        
        def dispath(self,request,*args,**kwargs):
            print("before")
            obj = super(Login, self).dispath(request,*args,**kwargs)  # 通过super继承父类的方法
            print('after')
            return obj  # 返回值就是执行相应的函数
        
        def get(self, request):
            return render(request, 'login.html')
    
        def post(self, request):
            user = request.POST.get('user')
            print(user)
            return HttpResponse('login.post')
    

    参考文章

    在models中使用反射

    修改类的__str__

    1

    class UserType(models.Model):
        """
        用户类型
        """
        title = models.CharField(max_length=32)
        def __str__(self):
            return "%s-%s" %(self.id,self.title)  # 直接通过点就可以
    
    v= models.UserType.objects.all().first()
    v= models.UserType.objects.all()
    print(v)  
    

    2

    class UserInfo(models.Model):
        """
        用户表
        """
        name = models.CharField(max_length=16)
        age = models.IntegerField()
        ut = models.ForeignKey('UserType')
        def __str__(self):
            return "%s-%s-%s-%s" %(self.id,self.name,self.age,self.ut)
    
    obj = models.UserType.objects.all().first()  # 这样获得是对象 all()获得是Queryset对象
        result = obj.userinfo_set.all()  #   
        print(result)
        "<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>"
        for i in result:
            print(i)
    

    结果:

    1-用户1-19-1-普通用户
    3-蛋子-19-1-普通用户
    4-钢弹-19-1-普通用户
    
    

    Django的ORM操作

    http请求
    URL-视图(模板+数据)

    ORM利用pymysql第三方连接数据库

    Django默认的是MySQLDB,需要修改成pymysql
    Django默认

    ORM 操作表

    Django自己有ORM框架,类-表,对象-行
    其他的框架自己用pymysql和SqlAchemy

    • 创建表
    • 修改表(SQLAchemery不能修改表)
    • 删除表

    1 创建数据库

    2 django默认的数据库是SQLlite,修改配置文件,设置连接的数据库为MySQL

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME':'dataname',  # 数据库名
            'USER': 'root',
            'PASSWORD': '',
            'HOST': 'localhost',
            'PORT': 3306,
            }
    }
    

    3 替换MySQLDB,通过pymysql连接数据库

    在工程的__init__中添加

    import pymysql
    pymysql.install_as_MySQLdb()    
    

    ORM操作数据行

    在models中创建类

    创建user_info表,默认id自动生成,注意数据长度

    from django.db import models
    
    class UserInfo(models.Model):
        nid = models.BigAutoField(primary_key=True)  # 不写默认生成id列
        user = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    

    注册app

    在settings中的添加

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
        'app02',
        'app03',
    ]
    

    创建表的命令

    • python3 manage.py makemigrations
    • python3 manage.py migrate
    D:mysite01>python3 manage.py makemigrations
    Migrations for 'app01':
      app01migrations001_initial.py
        - Create model UserInfo
    
    D:mysite01>python3 manage.py migrate
    Operations to perform:
      Apply all migrations: admin, app01, auth, contenttypes, sessions
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying app01.0001_initial... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying sessions.0001_initial... OK
    
    

    最后生成的表的名字是app01_userifo

    修改表的列名

    在类中直接修改,然后执行创建表的命令。
    数据库的修改的内容都保存在migrations文件中,修改前会先读取,然后就行修改

    输入y确认修改

    D:mysite01>python3 manage.py makemigrations
    Did you rename userinfo.password to userinfo.pwd (a CharField)? [y/N] y
    Migrations for 'app01':
      app01migrations004_auto_20170624_2021.py
        - Rename field password on userinfo to pwd
    
    
    D:mysite01>python3 manage.py migrate
    Operations to perform:
      Apply all migrations: admin, app01, auth, contenttypes, sessions
    Running migrations:
      Applying app01.0004_auto_20170624_2021... OK
    
    

    数据表增加

    注意的是是否为空,有两种方案

    • 设置为空 age = models.IntegerField(null=True)

    • 设置默认值age = models.IntegerField(default=1)

    创建外键关系

    新建usergroup表,然后在userinfo表中增加一列外键关系表

    ug = models.ForeignKey('UserGroup',null=True)

    • 设置默认为空
    • 最终生成的外键的名字是ug_id

    数据行增删改查操作

    增加一行数据
    from app01 import models
    
    def index(request):
        models.UserGroup.objects.create(title="技术部") 
        return HttpResponse("...")
    
    导入多条数据

    外键用ug_id,添加前要有外键的数据

     models.UserInfo.objects.create(user='abc', pwd='123', age=18, ug_id=1)
    
    查看数据
    group_list = models.UserGroup.objects.all()
    print(group_list)
    
    QuerySet [<UserGroup: UserGroup object>, <UserGroup: UserGroup object>]
    

    得到的结果是一个QuerySet对象,可以看做一个列表,列表中的每一个对象代表一行数据

    • 在后台查看数据
    def index(request):
    
        group_list = models.UserGroup.objects.all()
        print(group_list)
        for row in group_list:
            print(row.id, row.title)
        return HttpResponse("...")
    
    • 在前端模板中查看数据
      <ul>
        {% for row in user_list %}
          <li>{{ row.nid }} | {{row.user }} | {{ row.pwd }} | {{ row.age }}</li>
        {% endfor %}
      </ul>
    

    结果:
    1 | abc | 123 | 18
    2 | abc | 123 | 18

    查看数据的范围filter

    使用了双下划线

    user_list = models.UserInfo.objects.filter(nid=1)
    user_list = models.UserInfo.objects.filter(nid__gt=1) # nid 大于1的数据
    user_list = models.UserInfo.objects.filter(nid__lt=2) # nid 小于2的数据
    

    删除数据

    注意有外键的不能删除
    models.UserInfo.objects.filter(nid=3).delete()

    更新数据
    models.UserGroup.objects.filter(id=2).update(title="新的部门")

    连表操作

    和SQLAchemy类似

    对象可以跨表

    在循环的时候跨表
    拿一个的时候是obj

    all 是QerySet[obj,obj]
    filterQerySet[obj,obj]

    正向操作

    1 all()使用点
    通过UserInfo 的ut(外键)连表UserType

        v = models.UserInfo.objects.all().first()  # 用first进行试验
        print(v.ut.id,v.ut.title)  # 使用点能点出方法
    

    2 values() 使用双下划线进行跨表

    返回值是字典

    v2 = models.UserInfo.objects.values('id','name','age','ut__id','ut__title')
        for i in v2:
            print(i)
    
        """
        {'id': 1, 'name': '用户1', 'age': 19, 'ut__id': 1, 'ut__title': '普通用户'}
        {'id': 2, 'name': '用户2', 'age': 19, 'ut__id': 2, 'ut__title': '超级用户'}
        {'id': 3, 'name': '蛋子', 'age': 19, 'ut__id': 1, 'ut__title': '普通用户'}
        {'id': 4, 'name': '钢弹', 'age': 19, 'ut__id': 1, 'ut__title': '普通用户'}
        {'id': 5, 'name': '钢珠', 'age': 19, 'ut__id': 3, 'ut__title': '白金用户'}
        """
    

    3 value_list()

    values_lis也是用双下划线

    返回值是元组

    v2 = models.UserInfo.objects.values_list('id','name','age','ut__id','ut__title')
        for i in v2:
            print(i)
    
    (1, '用户1', 19, 1, '普通用户')
    (2, '用户2', 19, 2, '超级用户')
    (3, '蛋子', 19, 1, '普通用户')
    (4, '钢弹', 19, 1, '普通用户')
    (5, '钢珠', 19, 3, '白金用户')
    

    反向操作

    1 小写的表名_set

    下面是通过all().first()获取第一个对象。只能通过对象进行反向操作userinfo_set.all()

        obj = models.UserType.objects.all().first()  # 这样获得是对象 all()获得是Queryset对象
        result = obj.userinfo_set.all()  # 只能是通过对象进行操作 
        print(result)
        "<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>"
        for i in result:
            print(i)
    
    下面是通过反射获得的:
    1-用户1-19-1-普通用户
    3-蛋子-19-1-普通用户
    4-钢弹-19-1-普通用户
    

    2 values

    返回的是字典

    v = models.UserType.objects.values('id','title','userinfo')
        for i in v:
            print(i)
    

    结果:

    {'id': 1, 'title': '普通用户', 'userinfo': 1}
    {'id': 1, 'title': '普通用户', 'userinfo': 3}
    {'id': 1, 'title': '普通用户', 'userinfo': 4}
    {'id': 2, 'title': '超级用户', 'userinfo': 2}
    {'id': 3, 'title': '白金用户', 'userinfo': 5}
    
    v = models.UserType.objects.values('id', 'title', 'userinfo__id','userinfo__name','userinfo__age')
        for i in v:
            print(i)
    

    结果:

    {'id': 1, 'title': '普通用户', 'userinfo__id': 1, 'userinfo__name': '用户1', 'userinfo__age': 19}
    {'id': 1, 'title': '普通用户', 'userinfo__id': 3, 'userinfo__name': '蛋子', 'userinfo__age': 19}
    {'id': 1, 'title': '普通用户', 'userinfo__id': 4, 'userinfo__name': '钢弹', 'userinfo__age': 19}
    {'id': 2, 'title': '超级用户', 'userinfo__id': 2, 'userinfo__name': '用户2', 'userinfo__age': 19}
    {'id': 3, 'title': '白金用户', 'userinfo__id': 5, 'userinfo__name': '钢珠', 'userinfo__age': 19}
    

    3 values_list

    values_list返回的是元组对象

    用filter进行跨表

    正向操作

    v=models.UserInfo.objects.filter(ut__title='普通用户').values('id','name','ut__title')
        # print(v)
        for i in v:
            print(i)
    

    结果:

    
        {'id': 1, 'name': '用户1', 'ut__title': '普通用户'}
        {'id': 3, 'name': '蛋子', 'ut__title': '普通用户'}
        {'id': 4, 'name': '钢弹', 'ut__title': '普通用户'}
    
    

    反向操作

    A.onjects.filter(b__id=xx 或 b__age=xx 或 b__name=)
    下面测试的是age=19的用户

    v=models.UserType.objects.filter(userinfo__age=19).values('id','title','userinfo__name')
        print(v)
        for i in v:
            print(i)
    

    结果:

    {'id': 1, 'title': '普通用户', 'userinfo__name': '用户1'}
    {'id': 2, 'title': '超级用户', 'userinfo__name': '用户2'}
    {'id': 1, 'title': '普通用户', 'userinfo__name': '蛋子'}
    {'id': 1, 'title': '普通用户', 'userinfo__name': '钢弹'}
    {'id': 3, 'title': '白金用户', 'userinfo__name': '钢珠'}
    

    Django分页

    分页的目的是:在数据量太大分批获取数据并在页面上进行展示

    简单的操作就是通过切片获取

     user_list = models.UserInfo.objects.all()[1:10]
     user_list = models.UserInfo.objects.all()[10:20]
    

    Django自带分页

    适合做上下页,只能在Django中用

    分页操作实现

    首先导入对象Paginator

    from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage

    在浏览器中通过GET发送当前的页码,后面加上?page=1

    http://127.0.0.1:8000/index.html?page=1

    python后台代码

    def index(request):
        """
        Djangon内置的分页,实现的功能是上下页
        :param request:
        :return:
        """
        # 通过GET方式获取当前页码
        current_page = request.GET.get('page')
        user_list = models.UserInfo.objects.all()  # 获取全部的用户数据
        # user_list = models.UserInfo.objects.all().count() # 获取具体的数据量
        # print(user_list)
        # user_list = models.UserInfo.objects.all()[0:10]  # 通过切片的方式获取数据
        paginator = Paginator(user_list, 10)  # (第一参数object_list,第二个参数per_age)
        # 下面是paginator的方法
        # per_page: 每页显示条目数量
        # count:    数据总个数
        # num_pages:总页数
        # page_range:总页数的索引范围,如: (1,10),(1,200)
        # page:     返回值是一个对象
    
        posts = paginator.page(current_page)  # 传入的是页码的值
        # 下面是posts的方法
        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表
        # number                当前页
        # paginator             paginator对象
        return render(request, 'index.html', {'posts': posts})
    

    前端代码,通过posts拿到分页后的数据,上下页之前先判断是否有上一页或者下一页,之后拼接路径。

    <h1>django内置的分页</h1>
        <ul>
            {% for row in posts.object_list %} {# object_list是分页之后的数据列表 #}
                <li>{{ row.name }}</li>
            {% endfor %}
        </ul>
        <div>
            {% if posts.has_previous %}
                <a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
            {% endif %}
            {% if posts.has_next %} {# 判断有下一页的时候 #}
                <a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
            {% endif %}
        </div>
    

    关于URL中的问题

    在URL中只能接收的是int型的数字,如果传入的是字母,会报错PageNotAnInteger at /index.html,在后台进行异常处理,捕捉异常之后的操作是返回到第一页。

    在URL中传入的是负数的话,报错EmptyPage at /index.html,处理同样是返回到第一页

    已经在前面导入了异常处理的
    from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage

    try:
        posts = paginator.page(current_page)  # 传入的是页码的值
        # except PageNotAnInteger as e:
        #     posts = paginator.page(1)
        # except EmptyPage as e:
        #     posts = paginator.page(1)
    except Exception as e:
        posts = paginator.page(1)
    

    Django的页码

    Django的页码在数据量很大的时候,会显示所有的分页的页码,比如有300条数据,每页显示10条数据,就会有30个页码。所以需要进行自己开发

    在index的上下页中间添加,post下有paginator方法,paginator下有page_range 方法

    <div>
            {% if posts.has_previous %}
                <a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
            {% endif %}
       
            {% for num in posts.paginator.page_range %} {# post下有paginator,paginator下有page_range #}
                <a href="/index.html?page={{ num }}">{{ num }}</a>
            {% endfor %}
               
            {% if posts.has_next %} {# 判断有下一页的时候 #}
                <a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
            {% endif %}
    </div>
    

    总结:
    Django的分页适用于上下翻页的情况,不适合中间的页码

    自定义分页

    可以在任何地方使用,以后封装成一个类

    最原始的实现

    def custom(request):
        # 用户当前要访问的页码
        current_page = request.GET.get('page')
        current_page = int(current_page)
    
        # 每页显示的个数
        per_page = 10
        # 1 1:10  最后一个取不到
        # 2 10:20
        # 3 20:30
        start = (current_page - 1) * per_page
        end = current_page * per_page
        user_list = models.UserInfo.objects.all()[start:end]
        return render(request, 'custom.html', {"user_list": user_list})
    

    把页码的计算封装成类

    注意类中的参数传值的时候要一一对应

    class PageInfo(object):
        def __init__(self, current_page, all_count, per_page, ):
            try:
                self.current_page = int(current_page)
            except Exception as e:
                current_page = 1  # url 不是
            self.per_page = per_page
            a, b = divmod(all_count, per_page)  # 通过divmod进行分页,有余数的再加一页
            if b:
                a += 1
            self.all_page = a  # all_page 是总的页码
    
        def start(self):
            return (self.current_page - 1) * self.per_page
    
        def end(self):
            return self.current_page * self.per_page
    
        def pager(self):
            # v = "<a href='/custom.html?page=1'>1</a>" # 双引号中中用单引号
            # return v
    
            # 显示所有的页码
            page_list = []
            for i in range(1, self.all_page + 1):
                if i == self.current_page:
                    # 判断是当前页的时候,加上背景色
                    # temp = "<a style='padding=5px display=inl' href='/custom.html?page=%s'>%s</a>" %(i,i)  # 选中的加背景色
                    temp = "<a style='display: inline-block;padding: 5px;margin: 5px;background-color: red' href='/custom.html?page=%s'>%s</a>" % (
                    i, i)
                else:
                    temp = "<a style='display: inline-block;padding: 5px;margin: 5px' href='/custom.html?page=%s'>%s</a>" % (
                    i, i)
                page_list.append(temp)
            return ''.join(page_list)  # 把列表中的值取出并拼接成字符串
    
    
    # 自定义分页
    def custom(request):
        # 用户当前要访问的页码
        # current_page = request.GET.get('page')
        # page_info = PageInfo(current_page,10)
        all_count = models.UserInfo.objects.all().count()
        page_info = PageInfo(request.GET.get('page'), all_count, 10)
        user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()]  # 对象继承类的方法
        return render(request, 'custom.html', {"user_list": user_list, 'page_info': page_info})
    

    继续优化成页码的显示方式

    这种是定义了固定的显示页面数11(当前页和前后5页),现在的问题是两端的极限值的问题

    左边必须是当前页>=6
    右边的问题是会查不到数据后还显示页码

    class PageInfo(object):
        def __init__(self, current_page, all_count, per_page, show_page=11):
            try:
                self.current_page = int(current_page)
            except Exception as e:
                current_page = 1  # url 不是
            self.per_page = per_page
            a, b = divmod(all_count, per_page)  # 通过divmod进行分页,有余数的再加一页
            if b:
                a += 1
            self.all_page = a  # all_page 是总的页码
            self.show_page = show_page
    
        def start(self):
            return (self.current_page - 1) * self.per_page
    
        def end(self):
            return self.current_page * self.per_page
    
        def pager(self):
            # v = "<a href='/custom.html?page=1'>1</a>" # 双引号中中用单引号
            # return v
    
            half = int((self.show_page-1)/2)
            begin = self.current_page - half
            stop =self.current_page +half +1
            # 显示所有的页码
            page_list = []
            for i in range(begin,stop):
                if i == self.current_page:
                    # 判断是当前页的时候,加上背景色
                    # temp = "<a style='padding=5px display=inl' href='/custom.html?page=%s'>%s</a>" %(i,i)  # 选中的加背景色
                    temp = "<a style='display: inline-block;padding: 5px;margin: 5px;background-color: red' href='/custom.html?page=%s'>%s</a>" % (
                    i, i)
                else:
                    temp = "<a style='display: inline-block;padding: 5px;margin: 5px' href='/custom.html?page=%s'>%s</a>" % (
                    i, i)
                page_list.append(temp)
            return ''.join(page_list)  # 把列表中的值取出并拼接成字符串
    

    优化右边的极限

  • 相关阅读:
    不注意的小问题
    Hibernate、Spring和Struts工作原理及使用理由
    正则表达式贪婪与非贪婪模式
    Springmvc构造RESTful详细讲解
    正则表达式贪婪与非贪婪模式1
    BOJ二叉排序树的后序遍历
    qsort()应用大全
    辗转相除法求最大公约数(C语言)
    九度题目1014:排名 (结构体多级排序)
    BOJ第三题:二叉树前序遍历
  • 原文地址:https://www.cnblogs.com/Python666/p/7071284.html
Copyright © 2011-2022 走看看