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

tags: Django

Django 从0开始创建一个项目

创建Django工程及配置

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

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

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

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'app01',
  9. 'app02',
  10. 'app03',
  11. ]
  • 配置模板路径:'DIRS': [os.path.join(BASE_DIR, 'templates')],

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

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

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

Django的目录结构:

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

路由系统:

URL-函数 的对应关系

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

具体实现

  • 第一步是在urls中导入视图函数from app01 import views

    设置URL:

  1. urlpatterns = [
  2. url(r'^admin/', admin.site.urls),
  3. url(r'^index/', views.index),
  4. url(r'^edit/(\w+)/', views.edit), # 通过正则匹配路径
  5. ]
  • 编写视图函数:

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

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

总结:

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

正则匹配

  • 按照位置传值(有先后顺序)
  1. url(r'^edit/(\w+)/(\w+)/', views.edit),
  2. def edit(request, a1, a2):
  3. print(a1, a2) # 接收函数URL的参数
  4. return HttpResponse("ok")
  • 按照名称(关键字)(?P\w+)

    • 注意是在正则表达式的括号里面传参数
    • 可以没有顺序,这个过程相当于找到相应的参数名进行赋值
  1. url(r'^edit/(?P<a1>\w+)/(?P<a2>\w+)/', views.edit),
  2. def edit(request, a1, a2):
  3. return HttpResponse("ok")

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

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

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

    • 推荐用终止符$

      ^edit$

    • 伪静态(SEO)

      url(r'^edit/(\w+)'.html$, views.edit),

  • 404页面,默认页面

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

    url(r'^', views.index),

    前面的正则是不加内容的,后面写函数名

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

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

引入include

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

url 关系命名

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

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

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

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

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

根据名字反生成URL

name reverse

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

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

应用:

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

注意的是'm1' 要加引号

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

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

  1. <ul>
  2. {% for i in user_list %}
  3. <!-- <li>{{ i }}| <a href="/edit/{{ i }}/">编辑</a></li> -->
  4. <li>{{ i }}| <a href="{% url "n2" i %}/">编辑</a></li>
  5. {% endfor %}
  6. </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转换成小写,然后返回函数并执行

  1. if request.method.lower() in self.http_method_names:
  2. handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
  3. else:
  4. handler = self.http_method_not_allowed
  5. 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 获取全部的内容

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

login的前端

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

自己重写dispath方法

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

关键点:

1 super继承

2 返回值

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

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

参考文章

在models中使用反射

修改类的__str__

1

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

2

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

结果:

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

Django的ORM操作

http请求

URL-视图(模板+数据)

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

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

Django默认

ORM 操作表

Django自己有ORM框架,类-表,对象-行

其他的框架自己用pymysql和SqlAchemy

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

1 创建数据库

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

  1. DATABASES = {
  2. 'default': {
  3. 'ENGINE': 'django.db.backends.mysql',
  4. 'NAME':'dataname', # 数据库名
  5. 'USER': 'root',
  6. 'PASSWORD': '',
  7. 'HOST': 'localhost',
  8. 'PORT': 3306,
  9. }
  10. }

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

在工程的__init__中添加

  1. import pymysql
  2. pymysql.install_as_MySQLdb()

ORM操作数据行

在models中创建类

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

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

注册app

在settings中的添加

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'app01',
  9. 'app02',
  10. 'app03',
  11. ]

创建表的命令

  • python3 manage.py makemigrations
  • python3 manage.py migrate
  1. D:\mysite01>python3 manage.py makemigrations
  2. Migrations for 'app01':
  3. app01\migrations\0001_initial.py
  4. - Create model UserInfo
  5. D:\mysite01>python3 manage.py migrate
  6. Operations to perform:
  7. Apply all migrations: admin, app01, auth, contenttypes, sessions
  8. Running migrations:
  9. Applying contenttypes.0001_initial... OK
  10. Applying auth.0001_initial... OK
  11. Applying admin.0001_initial... OK
  12. Applying admin.0002_logentry_remove_auto_add... OK
  13. Applying app01.0001_initial... OK
  14. Applying contenttypes.0002_remove_content_type_name... OK
  15. Applying auth.0002_alter_permission_name_max_length... OK
  16. Applying auth.0003_alter_user_email_max_length... OK
  17. Applying auth.0004_alter_user_username_opts... OK
  18. Applying auth.0005_alter_user_last_login_null... OK
  19. Applying auth.0006_require_contenttypes_0002... OK
  20. Applying auth.0007_alter_validators_add_error_messages... OK
  21. Applying auth.0008_alter_user_username_max_length... OK
  22. Applying sessions.0001_initial... OK

最后生成的表的名字是app01_userifo

修改表的列名

在类中直接修改,然后执行创建表的命令。

数据库的修改的内容都保存在migrations文件中,修改前会先读取,然后就行修改

输入y确认修改

  1. D:\mysite01>python3 manage.py makemigrations
  2. Did you rename userinfo.password to userinfo.pwd (a CharField)? [y/N] y
  3. Migrations for 'app01':
  4. app01\migrations\0004_auto_20170624_2021.py
  5. - Rename field password on userinfo to pwd
  6. D:\mysite01>python3 manage.py migrate
  7. Operations to perform:
  8. Apply all migrations: admin, app01, auth, contenttypes, sessions
  9. Running migrations:
  10. 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

数据行增删改查操作

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

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

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

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

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

结果:

1 | abc | 123 | 18

2 | abc | 123 | 18

查看数据的范围filter

使用了双下划线

  1. user_list = models.UserInfo.objects.filter(nid=1)
  2. user_list = models.UserInfo.objects.filter(nid__gt=1) # nid 大于1的数据
  3. 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

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

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

返回值是字典

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

3 value_list()

values_lis也是用双下划线

返回值是元组

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

反向操作

1 小写的表名_set

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

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

2 values

返回的是字典

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

结果:

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

结果:

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

3 values_list

values_list返回的是元组对象

用filter进行跨表

正向操作

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

结果:


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

反向操作

A.onjects.filter(b__id=xx 或 b__age=xx 或 b__name=)

下面测试的是age=19的用户

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

结果:

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

Django分页

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

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

  1. user_list = models.UserInfo.objects.all()[1:10]
  2. 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后台代码

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

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

  1. <h1>django内置的分页</h1>
  2. <ul>
  3. {% for row in posts.object_list %} {# object_list是分页之后的数据列表 #}
  4. <li>{{ row.name }}</li>
  5. {% endfor %}
  6. </ul>
  7. <div>
  8. {% if posts.has_previous %}
  9. <a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
  10. {% endif %}
  11. {% if posts.has_next %} {# 判断有下一页的时候 #}
  12. <a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
  13. {% endif %}
  14. </div>

关于URL中的问题

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

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

已经在前面导入了异常处理的

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

  1. try:
  2. posts = paginator.page(current_page) # 传入的是页码的值
  3. # except PageNotAnInteger as e:
  4. # posts = paginator.page(1)
  5. # except EmptyPage as e:
  6. # posts = paginator.page(1)
  7. except Exception as e:
  8. posts = paginator.page(1)

Django的页码

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

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

  1. <div>
  2. {% if posts.has_previous %}
  3. <a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
  4. {% endif %}
  5. {% for num in posts.paginator.page_range %} {# post下有paginator,paginator下有page_range #}
  6. <a href="/index.html?page={{ num }}">{{ num }}</a>
  7. {% endfor %}
  8. {% if posts.has_next %} {# 判断有下一页的时候 #}
  9. <a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
  10. {% endif %}
  11. </div>

总结:

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

自定义分页

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

最原始的实现

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

把页码的计算封装成类

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

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

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

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

左边必须是当前页>=6

右边的问题是会查不到数据后还显示页码

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

优化右边的极限

Django 从0开始创建一个项目的更多相关文章

  1. 如何用django框架完整的写一个项目

    实现目标及功能,增删改,并且实现搜索,分页,日期插件,删除提示,以及批量导入等功能 软件版本: python3.5 django1.11 一  用pycharm创建一个项目,名字自定义 二 编辑url ...

  2. Ionic-wechat项目边开发边学(一):环境搭建和创建一个项目

    之前学AngularJS,教程过了一遍觉得很简单,但真正写几个Demo就错误百出,一个小小的功能要折腾很久.所以这次学Ionic,准备以开发一个项目为切入点去学,那么问题来了,开发什么项目呢? 纠结了 ...

  3. Vue.js+vue-element搭建属于自己的后台管理模板:创建一个项目(四)

    Vue.js+vue-element搭建属于自己的后台管理模板:创建一个项目(四) 前言 本章主要讲解通过Vue CLI 脚手架构建工具创建一个项目,在学习Vue CLI之前我们需要先了解下webpa ...

  4. 学习将码云账号和git连接,并且创建一个项目

    一顿操作猛如虎,哈哈 参考网址:https://git-scm.com/book/zh/v1/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7 ...

  5. kraken-ejs创建一个项目【学习札记】

    Keep in Touch. 保持联络. Who’s calling? 是哪一位? You did right. 你做得对. You set me up! 你出卖我! kraken-express-e ...

  6. Cordova之如何用命令行创建一个项目(完整示例)

    原文:Cordova之如何用命令行创建一个项目(完整示例) 1. 创建cordova项目 (注意:当第一次创建或编译项目的时候,可能系统会自动下载一些东西,需要一些时间.) 在某个目录下创建cordo ...

  7. Gitlab创建一个项目(三)使用IntelliJ IDEA开发项目

    Gitlab创建一个项目 Gitlab创建一个项目(二)创建新用户以及分配项目 1.登陆到gitlab 2.点击项目名,获取http的URL 3.idea打开,选择git 4.设置项目路径以及本地保存 ...

  8. Gitlab创建一个项目(二)创建新用户以及分配项目

    Gitlab创建一个项目(一) 1.进入gitlab控制台 2.点击“新建用户” 3.点击“Edit”,创建初始密码 4.分配项目,首页进入项目 5.进入Members菜单 6.选择用户 7.赋予权限 ...

  9. Gitlab创建一个项目

    1.安装git yum install git 2.生成密钥文件:使用ssh-keygen生成密钥文件.ssh/id_rsa.pub ssh-keygen 执行过程中输入密码,以及确认密码,并可设置密 ...

随机推荐

  1. linux和windows下安装python拓展包及requirement.txt安装类库

    python拓展包安装 直接安装拓展包默认路径: Unix(Linux)默认路径:/usr/local/lib/pythonX.Y/site-packagesWindows默认路径:C:\Python ...

  2. unity3d四元数和旋转矩阵

    http://blog.csdn.net/kfqcome/article/details/10729551 一 四元数 Quaternion中存放了x,y,z,w四个数据成员,可以用下标来进行访问,对 ...

  3. uoj#399. 【CTSC2018】假面(概率期望)

    传送门 记\(p_{i,j}\)为\(i\)还剩\(j\)滴血的概率,那么\(i\)最后血量的期望就是\[E_i=\sum_{j=0}^{m_i}j\times p_{i,j}\] 然后\(p\)数组 ...

  4. 解决Idea项目启动报错:程序包javax.servlet.http不存在

    报错信息 在没有使用maven的时候,web项目从远程仓库获取下以后,起一次启动往往会报错javax.servlet.http程序包找不到,随之而来的java基础包都将不能使用,报错信息如下: 解决方 ...

  5. Glassfish 设置时区

    对于Glassfish domain 或者instance下,某个日志的时区不对,前提是系统时区争取. 可以尝试通过如下命令查看jvm 时区设置 asadmin list-jvm-options 如果 ...

  6. vue -- key的特殊作用

    v-for渲染的列表的结构采用“就地复用”的策略,也就说当数据重新排列数据时,会复用已在页面渲染好的元素,不会移动 DOM 元素来匹配数据项的顺序,这种模式是高效的,改变现有位置的结构的数据即可 eg ...

  7. js 去除字符串空白符

    var a="      123456" varb=a.replace(/(^\s*)/g, "");

  8. net core (下)

    net core (下) 第一部分: https://www.cnblogs.com/cgzl/p/8450179.html 本文是基于Windows10的. Debugging javascript ...

  9. CoreCLR源码2

    CoreCLR源码 前一篇我们看到了CoreCLR中对Object的定义,这一篇我们将会看CoreCLR中对new的定义和处理new对于.Net程序员们来说同样是耳熟能详的关键词,我们每天都会用到ne ...

  10. shell 经典

    使用新写法 这里的新写法不是指有多厉害,而是指我们可能更希望使用较新引入的一些语法,更多是偏向代码风格的,比如 尽量使用func(){}来定义函数,而不是func{} 尽量使用[[]]来代替[] 尽量 ...