白日依山尽,黄河入海流。欲穷千里目,更上一层楼。 -- 唐·王之涣

django 实现分页

1、函数视图分页

1
2
3
4
5
6
7
8
9
10
11
12
from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Post

def index(request):
posts = Post.objects.all()
paginator = Paginator(posts, 15)
# 默认一般都是使用page参数
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'blog/index.html', {'page_obj': page_obj})

2、类视图分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.views.generic import ListView
from .models import Post

class IndexListView(ListView):
# 关联模型
model = Post
# 模板名称,默认推导为 index_list.html
template_name = 'blogv3/index.html'
# 模板中的对象名称,默认为 object_list
context_object_name = 'posts'
# 限制请求方法
http_method_names = ['get']
# 设置分页
paginate_by = 15

# 可以通过get_context_data获取到分页信息,当然前提是设置了 paginate_by
# def get_context_data(self, *args, **kwargs):
# context = super().get_context_data(*args, **kwargs)
# print(context)
# return context

上述调试中获取的到context内容为

1
2
3
4
5
6
7
8
{
'paginator': <django.core.paginator.Paginator object at 0x104ff4160>,
'page_obj': <Page 1 of 4>,
'is_paginated': True,
'object_list': <QuerySet [... ...]>,
'view': <blogv3.views.IndexListView object at 0x104ff43a0>
}

说明:

  • paginator Django的分页对象
  • page_obj 当前页参数, 实际在template中判断的时候使用的就是该对象
  • is_paginated 是否分页
  • object_list 对象名称,context_object_name 定义了posts ,两者效果等效
  • view 视图名称

template中配置实际分页信息

1
2
3
4
5
6
7
8
9
10
11
12
<div class="container navigation">
{% if page_obj.has_previous %}
<a class="navigate pull-left" href="?page={{ page_obj.previous_page_number }}"><i class="fa fa-caret-left"></i> <<< 更 新</a>
{% endif %}

<!-- 当然有时候这里也可以显示当前页码 -->
<span>Current Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }} </span>

{% if page_obj.has_next %}
<a class="navigate pull-right" href="?page={{ page_obj.next_page_number }}">更 多 >>> <i class="fa fa-caret-right"></i></a>
{% endif %}
</div>

附加:

Paginator常用的属性和方法

  • count 总共有多少条记录
  • num_pages 总共有多少页
  • page_range 页面的区间

Page 常用属性和方法

  • has_next
  • has_previous
  • next_page_number
  • previous_page_number
  • number 当前页
  • start_index 当前页的第一条记录的索引值
  • end_index 当前页的最后一条记录的索引值

Paginator 练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
(django_exercise_book) [ 22-04-02 11:08 ] [ colinspace ] python manage.py shell
Python 3.9.6 (default, Jul 16 2021, 13:41:17)
[Clang 12.0.5 (clang-1205.0.22.11)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.core.paginator import Paginator
>>> obj_list = ['apple', 'orange', 'banana', 'tomato', 'pear' ]
>>> paginator = Paginator(obj_list, 2)
>>> paginator
<django.core.paginator.Paginator object at 0x106cf8130>
>>> paginator.
paginator.ELLIPSIS paginator.get_page( paginator.page(
paginator.allow_empty_first_page paginator.num_pages paginator.page_range
paginator.count paginator.object_list paginator.per_page
paginator.get_elided_page_range( paginator.orphans paginator.validate_number(
>>> paginator.count
5
>>> paginator.num_pages
3
>>> paginator.per_page
2
>>> paginator.page_range
range(1, 4)
>>> paginator.object_list
['apple', 'orange', 'banana', 'tomato', 'pear']
>>>
>>>
>>> page1 = paginator.page(2)
>>> page2 = paginator.page(2)
>>>
>>> page2
<Page 2 of 3>
>>> page2.
page2.count( page2.has_other_pages( page2.next_page_number( page2.paginator
page2.end_index( page2.has_previous( page2.number page2.previous_page_number(
page2.has_next( page2.index( page2.object_list page2.start_index(
>>> page2.has_previous()
True
>>> page2.has_next()
True
>>> page2.number
2
>>> page2.has_other_pages()
True
>>> page2.next_page_number()
3
>>> page2.previous_page_number()
1
>>> page2.start_index()
3
>>> page2.end_index()
4
>>>

参考:
https://docs.djangoproject.com/en/3.2/topics/pagination/

Django接入Celery实现任务管理

Django接入Celery实现任务管理,并且启用flower进行任务的可视化查看。另外任务的结果除了保存在Redis中之外,我们也可以选在保存在MySQL等持久化数据库,方便后续做统计分析,结果查询等等操作
阅读更多

django 发布应用

Django deploy application

当Django 的application开发完成之后,我们希望能将其作为模块分发出去供别人共享使用

How to write application

安装好Django之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
## create project
django-admin.py startproject mypro

## create app named `todo` (todo list)
cd mypro
python manage.py startapp todo

## configure app(todo) connect with project `mypro`
vim mypro/settings.py

INSTALLED_APPS = [
'django.contrib.admin',
...,
'todo',
]

vim mypro/urls.py
from django.conf.urls import url, include

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^todo/', include('todo.urls', namespace='todo')),
]

How to write setup.py

  • 创建一个父目录

    mkdir -pv /opt/django-todo

  • copy 刚才新增的 application todo 到 该目录下

    cp -r todo /opt/django-todo/

    一般开发完成application之后,在todo 下面会生成__pycache__migrations, 一般会保留migrations 作为应用的初始化; 或者删除不打包到Python package中,安装应用之后可以使用python manage.py makemigrations todo
    python manage.py migrate todo 来初始化;
    __pycache__ 可以删除不做打包

  • 新增README.MD 和 setup.py

    README.MD 作为项目的详细说明,这里省略,详细可以参考:todo README
    setup.py 是打包安装脚本,详细脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import os
from setuptools import find_packages, setup

with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
README = readme.read()

# 使 setup.py 能在任何地方运行
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))

setup(
name='colinws-todo',
version='0.3',
# packages=find_packages(),
packages=['todo'],
include_package_data=True,
license='MIT License',
description='A simple Django Todo List application',
long_description=README,
url='https://blog.colinspace.com/',
author='Colin.Liu',
author_email='colinservice@126.com',
platforms = 'Linux,Unix',
keywords = 'Colin,colinws,todo, todo list, django',
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Framework :: Django :: 1.11',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
)
  • 编译打包、安装、注册、上传

    python setup.py sdist
    python setup.py register
    python setup.py upload

Python发布package到pypi配置

新增~/.pypirc 而不是 ~/.pypi

刚才报错Server response (410): Project pre-registration is no longer required or supported, so continue dire 就是配置文件命名成了 ~/.pypi

1
2
3
4
5
6
7
[distutils]
index-servers = pypi

[pypi]
repository: https://upload.pypi.org/legacy/
username: colin5063
password: xxxxxx

第三方安装

you can install via pip

pip install colinws-todo

or you can git clone this repository and use setup.py

git clone https://github.com/opscolin/Django-todo.git
cd Django-todo
python setup.py install

Quick start

  • Add "todo" to your INSTALLED_APPS setting like this:

    INSTALLED_APPS = [ ... 'todo',]
    
  • Include the todo URLconf in your project urls.pylike this:

    url(r'^todo/', include('todo.urls')),
    
  • Run below command to create todo models migrations.:

    python manage.py makemigrations todo
    
  • Run below command to create todo real models.:

    python manage.py migrate todo
    
  • Start the development server and visit http://127.0.0.1:8000/admin/ to create a todo (you’ll need the Admin app enabled).

  • Visit http://127.0.0.1:8000/todo/ to participate in the todo list.


Refer