新建Django项目
django-admin.exe startproject FirstDjango
cd FirstDjango
python manage.py startapp weblist
改setting里的配置
"""
Django settings for web project.
Generated by 'django-admin startproject' using Django 4.0.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-o%&42(%9p0r(8(_jn#re&7b!$_ln45s$(-7-a_*((!#h+k*s_b'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 'weblist.templatetags',
'weblist',
'rest_framework'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'web.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 'DIRS': [],
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'web.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'jiale',
'POST':3306,
'HOST':'localhost',
'USER':'root',
'PASSWORD':'123456'
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static')]
UPLOAD_FILE = os.path.join(BASE_DIR,'upload')
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
# DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
设置路由分发
主
"""web URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include
from django.views.static import serve
from web import settings
from weblist import views
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('weblist.urls')),
path('upload/<path>',serve,{'document_root':settings.UPLOAD_FILE}),
]
子
"""web URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
# from django.contrib import admin
from django.urls import path
from weblist import views
from django.views.generic import TemplateView
urlpatterns = [
# path('admin/', admin.site.urls),
path('login/', views.Login.as_view()),
path('index/', views.Index.as_view()),
path('reg/', views.Reg.as_view()),
path('goods/', views.Goods_list.as_view()),
path('del/', views.Pop_goods.as_view()),
path('edit/', views.Change_goods.as_view()),
# path('test_page/', views.test_page.as_view()),
path('Myc/', views.Myc.as_view()),
path('weibo/', views.weibo.as_view()),
# path('weibo/', views.weibo),
path('ding_url/', views.ding_url),
path('ding_back/', views.ding_back),
path('liaotian/', views.Qingyunke.as_view()),
path('get_order_code/', views.get_order_code),
path('erweima/', views.generate_qrcode),
# path('CreateCode/', views.CreateCode.as_view()),
# path('alipay_return/', views.alipay_return),
path('pay/', views.page1),
path('get_ali_object/', views.get_ali_object),
path('alipay_return/', views.alipay_return),
path('socket_test/',TemplateView.as_view(template_name='socket.html')),
path('websocket_test/',TemplateView.as_view(template_name='socket_push.html')),
path('test_socket/',views.test_socket),
path('test_websocket/',views.test_websocket),
path('vx/',views.vx.as_view()),
path('QiNiu/',views.QiNiu.as_view()),
path(r'^export/xls/$', views.export_excel, name='export_excel')
# #websocket
# path('socket_test',TemplateView.as_view(template_name='socket.html')),
# path('websocket_test',TemplateView.as_view(template_name='ocket_push.html')),
# path('test_socket',views.test_socket),
# path('test_websocket',views.test_websocket),
]
新建表
from django.db import models
# Create your models here.
# 商品表
class Goods(models.Model):
name = models.CharField(max_length=50)
price = models.DecimalField(max_digits=7, decimal_places=2)
img = models.CharField(max_length=255)
class Meta:
db_table = 'goods'
# 页面访问表
class Count(models.Model):
count = models.IntegerField(default=1)
class Meta:
db_table = 'count'
# 新闻资讯,用户表
class User(models.Model):
name = models.CharField(max_length=50)
passwd = models.CharField(max_length=255)
phone = models.CharField(max_length=11)
create_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'user'
# 一级分类表
class Onecate(models.Model):
name = models.CharField(max_length=50)
image_url = models.CharField(max_length=255)
is_commend = models.BooleanField(default=False)
is_show = models.BooleanField(default=True)
class Meta:
db_table = 'onecate'
迁移数据库迁移表
python manage.py makemigrations
python manage.py migrate
视图views
import qrcode
from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse
from openpyxl import Workbook
from rest_framework.views import APIView
from django.views.generic import View
from django.core.paginator import Paginator
from weblist.models import *
# from weblist.myserializer import *
import os, io, requests
from web import settings
import random
# 导入绘图库
from PIL import ImageDraw
# 导入绘图字体库
# from PIL import ImageFont
# 导入图片库
from PIL import Image
import urllib.parse
from web.settings import BASE_DIR,UPLOAD_FILE
# 新闻资讯注册
import re
class Reg(View):
def get(self, request):
return render(request, 'reg.html')
def post(self, request):
name = request.POST.get('name')
passwd = request.POST.get('passwd')
phone = request.POST.get('phone')
if not all([name, passwd, phone]):
mes = '请输入完整信息'
else:
user = User.objects.filter(name=name).first()
if user:
mes = '用户已存在'
else:
user = User(name=name, passwd=passwd, phone=phone)
user.save()
return redirect('/api/login')
return render(request, 'login.html', locals())
# 新闻资讯登录
class Login(APIView):
def get(self, request):
return render(request, 'login.html')
def post(self, request):
name = request.POST.get('username')
passwd = request.POST.get('password')
# print(name,passwd)
if not all([name, passwd]):
mes = '请输入完整信息'
else:
user = User.objects.filter(name=name, passwd=passwd)
print(user)
if user:
return redirect('/api/index')
else:
mes = '信息输入有误'
return render(request, 'login.html', locals())
# 新闻资讯主页
# class Index(View):
# def get(self,request):
# return render(request,'index.html')
# 添加数据
class Index(APIView):
def get(self, request):
return render(request, 'addgoods.html')
# POST接受添加数据
def post(self, request):
mes = {}
name = request.data.get('name')
price = request.data.get('price')
img = request.FILES.get('img')
# print(name,price,img)
if not all([name, price, img]):
mes['code'] = 250
mes['message'] = '全要输入~'
else:
# 写入图片
img_name = img.name
f = open(os.path.join(settings.UPLOAD_FILE, img_name), 'wb')
for i in img.chunks():
f.write(i)
f.close()
# 添加图库
goods = Goods(name=name, price=price, img='/upload/' + img_name)
goods.save()
mes['code'] = 200
mes['message'] = '添加成功'
# goods = Goods.objects.all()
# print(goods)
return redirect('/api/goods')
return render(request, 'index.html', locals())
# 展示
# class Goods_list(View):
# def get(self, request):
# page_num = request.GET.get('page', 1)
#
# name = request.GET.get('name')
# if name:
# # print(name,66)
# goods = Goods.objects.filter(name=name).all
# paginator = Paginator(goods, 1)
#
# # 2、初始化具体页码对应的page对象
# c_page = paginator.page(int(page_num))
#
# # 3、将值传入模板
# return render(request, 'goodslist.html', locals())
# else:
# # all_data = ['a']
# goods = Goods.objects.all()
# # 1、初始化paginator
# # 传入的参数(要分页的数据,每页要显示的数据条数)
# paginator = Paginator(goods, 2)
#
# # 2、初始化具体页码对应的page对象
# c_page = paginator.page(int(page_num))
#
# # 3、将值传入模板
# return render(request, 'goodslist.html', locals())
class Goods_list(View):
def get(self, request):
name = request.GET.get('name')
goods = Goods.objects.all()
if name:
goods = Goods.objects.filter(name=name)
paginator = Paginator(goods, 1)
page_num = request.GET.get('page', 1)
c_page = paginator.page(int(page_num))
return render(request, 'goodslist.html', locals())
# 删除商品
class Pop_goods(APIView):
# get获取数据删除
def get(self, request):
mes = {}
id = request.GET.get('id')
try:
goods = Goods.objects.filter(id=id).delete()
except:
goods = {}
# 返回
mes['code'] = 200
mes['message'] = '删除成功'
goods = Goods.objects.all()
# return render(request, 'goodslist.html', locals())
return redirect('/api/goods')
# 修改商品
class Change_goods(APIView):
def get(self, request):
id = request.GET.get('id')
goods = Goods.objects.filter(id=id)
return render(request, 'index.html', locals())
# 根据id获取数据
def post(self, request):
mes = {}
id = request.GET.get('id')
print(id, '获取的编辑id')
name = request.data.get('name')
price = request.data.get('price')
img = request.FILES.get('img')
# 写入图片
img_name = img.name
f = open(os.path.join(settings.UPLOAD_FILE, img_name), 'wb')
for i in img.chunks():
f.write(i)
f.close()
# 获取数据
goods = Goods.objects.filter(id=id).first()
goods.name = name
goods.price = price
goods.img = '/upload/' + img_name
goods.save()
# 返回
mes['code'] = 200
mes['message'] = '修改成功'
return redirect('/api/goods')
# 定义验证码类
class Myc(View):
# 定义随机颜色方法
def get_random_color(self):
R = random.randrange(255)
G = random.randrange(255)
B = random.randrange(255)
return (R, G, B)
# 定义随机验证码
def get(self, request):
# 定义画布大小 宽,高
img_size = (120, 50)
# 定义画笔 颜色种类,画布,背景颜色
image = Image.new("RGB", img_size, 'white')
# 定义画笔对象 图片对象,颜色类型
draw = ImageDraw.Draw(image, 'RGB')
# 定义随机字符
source = '0123456789asdfghjkl'
# 定义四个字符
# 定义好容器,用来接收随机字符串
code_str = ''
for i in range(4):
# 获取随机颜色 字体颜色
text_color = self.get_random_color()
# 获取随机字符串
tmp_num = random.randrange(len(source))
# 获取字符集
random_str = source[tmp_num]
# 将随机生成的字符串添加到容器中
code_str += random_str
# 将字符画到画布上 坐标,字符串,字符串颜色,字体
# 导入系统真实字体,字号
# my_font = ImageFont.truetype("c:\\windows\\Fonts\\arial.ttf",20)
draw.text((10 + 30 * i, 20), random_str, text_color)
# 使用io获取一个缓存区
buf = io.BytesIO()
# 将图片保存到缓存区
image.save(buf, 'png')
# 将随机码存储到session中
request.session['code'] = code_str
print(request.session['code'])
# 第二个参数声明头部信息
return HttpResponse(buf.getvalue(), 'image/png')
# AgentId
#
# 2296157160
#
# AppKey
#
# ding5rrgtlfesksj6tlq
#
# AppSecret
#
# jx0T3H_Xs3qUbpk_Bw4wEtHx0oMTAhURCdcF8OnvjI13CKw0vPJ-xUgb-gYniO8S
# #构造钉钉登录url
def ding_url(request):
appid = 'ding5rrgtlfesksj6tlq'
redirect_uri = 'http://localhost:8000/api/dingding_back/'
return redirect(
'https://oapi.dingtalk.com/connect/qrconnect?appid=' + appid + '&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=' + redirect_uri)
import time
import hmac
import base64
from hashlib import sha256
import urllib
import json
# from myapp.models import User
# 构造钉钉回调方法
def ding_back(request):
# 获取code
code = request.GET.get("code")
t = time.time()
# 时间戳
timestamp = str((int(round(t * 1000))))
appSecret = 'jx0T3H_Xs3qUbpk_Bw4wEtHx0oMTAhURCdcF8OnvjI13CKw0vPJ-xUgb-gYniO8S'
# 构造签名
signature = base64.b64encode(
hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod=sha256).digest())
# 请求接口,换取钉钉用户名
payload = {'tmp_auth_code': code}
headers = {'Content-Type': 'application/json'}
res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=' + urllib.parse.quote(
signature.decode("utf-8")) + "×tamp=" + timestamp + "&accessKey=ding5rrgtlfesksj6tlq",
data=json.dumps(payload), headers=headers)
re_dict = json.loads(res.text)
print(re_dict)
# #判断是否为第一次登录
# user = User.objects.filter(username=str(re_dict["dingding_"+'user_info']['nick'])).first()
#
# sina_id = ''
# user_id = ''
#
# if user:
# #代表曾经用过钉钉登录
# sina_id = user.username
# user_id = user.id
# else:
# #代表首次登录,入库
# user = User(username=str("dingding_"+re_dict['user_info']['nick']),password='')
# #保存入库
# user.save()
# sina_id = str(re_dict['user_info']['nick'])
# #查询用户id
# user = User.objects.filter(username=str("dingding_"+re_dict['user_info']['nick'])).first()
# user_id = user.id
return HttpResponse('666')
# 进行跳转
# return redirect("http://localhost:8080?sina_id="+str(sina_id)+"&uid="+str(user_id))
import xlwt
from django.http import HttpResponse
from django.contrib.auth.models import User
def export_excel(request):
"""导出记录的视图"""
device_li = Goods.objects.all() # 查询库里所有数据
# 设置HTTPResponse的类型
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment;filename=device_data.xls'
"""导出excel表"""
if device_li:
# 创建工作簿
ws = xlwt.Workbook(encoding='utf-8')
# 添加第一页数据表
w = ws.add_sheet('sheet1') # 新建sheet(sheet的名称为"sheet1")
# 写入表头
w.write(0, 0, u'名称')
w.write(0, 1, u'价格')
w.write(0, 2, u'id')
# 写入数据
excel_row = 1
for obj in device_li:
name = obj.name
price = obj.price
id = obj.id
w.write(excel_row, 0, name)
w.write(excel_row, 1, price)
w.write(excel_row, 2, id)
excel_row += 1
# 写出到IO
output = io.BytesIO()
ws.save(output)
# 重新定位到开始
output.seek(0)
response.write(output.getvalue())
return response
# 调用机器人接口
def qingyunk(msg):
url = "http://api.qingyunke.com/api.php?key=free&appid=0&msg=%s" % (urllib.parse.quote(msg))
html = requests.get(url)
return html.json()["content"]
msg = "翻译i love you"
# print(msg)
#
# print(qingyunk(msg))
class Qingyunke(APIView):
def get(self,request):
return render(request, 'yule.html', locals())
def post(self,request):
cont = request.data.get('cont')
url = "http://api.qingyunke.com/api.php?key=free&appid=0&msg=%s" % (urllib.parse.quote(cont))
html = requests.get(url)
data = html.json()['content']
return render(request,'yule.html',locals())
def get_order_code():
order_no = str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())))
return order_no
import uuid
def generate_qrcode(request):
data = 'hello'
img = qrcode.make(data)
buf = io.BytesIO()
img.save(buf)
image_stream = buf.getvalue()
response = HttpResponse(image_stream, content_type="image/png")
return response
#导入支付基类
from .pay import AliPay
#初始化阿里支付对象
def get_ali_object():
# 沙箱环境地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info
app_id = "2016101200671995" # APPID (沙箱应用)
# 支付完成后,支付偷偷向这里地址发送一个post请求,识别公网IP,如果是 192.168.20.13局域网IP ,支付宝找不到,def page2() 接收不到这个请求
notify_url = "http://localhost:8000/api/alipayreturn"
# 支付完成后,跳转的地址。
return_url = "http://localhost:8000/api/alipayreturn"
merchant_private_key_path = r"C:\Users\dujiale\Desktop\Jiale\web\keys\app_private_key.txt" # 应用私钥
alipay_public_key_path = r"C:\Users\dujiale\Desktop\Jiale\web\keys\alipay_public_key.txt" # 支付宝公钥
alipay = AliPay(
appid=app_id,
app_notify_url=notify_url,
return_url=return_url,
app_private_key_path=merchant_private_key_path,
alipay_public_key_path=alipay_public_key_path, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥
debug=True, # 默认False,
)
return alipay
def page1(request):
if request.method == "POST":
# 根据当前用户的配置,生成URL,并跳转。
money = float(request.POST.get('money'))
alipay = get_ali_object()
# 生成支付的url
query_params = alipay.direct_pay(
subject="抄的代码", # 商品简单描述
out_trade_no="myorder" + str(time.time()), # 用户购买的商品订单号(每次不一样) 20180301073422891
total_amount=money, # 交易金额(单位: 元 保留俩位小数)
)
pay_url = "https://openapi.alipaydev.com/gateway.do?{0}".format(query_params) # 支付宝网关地址(沙箱应用)
return redirect(pay_url)
else:
return render(request,'page3.html')
def alipay_return(request):
alipay = get_ali_object()
params = request.GET.dict()
sign = params.pop('sign', None)
status = alipay.verify(params, sign)
print('==================开始==================')
print('GET验证', status)
print('==================结束==================')
return HttpResponse('支付成功')
class vx(APIView):
pass
#七牛云token
from qiniu import Auth
class QiNiu(APIView):
def get(self,request):
q = Auth('Ad9L1wgkTmEkoqy963K88JilD9aDR2HGzSjVFucb','Q-GZz7YUdDuT4U8eFyvbc4bPIkKAciq-TnUhV1aM')
token = q.upload_token('testupdu')
print(token)
res = {}
res['uptoken'] = token
return JsonResponse(res)
def upfile(request):
return HttpResponse('上传成功')
#导入websocket装饰器
from dwebsocket.decorators import accept_websocket
#接收前端信息
@accept_websocket
def test_socket(request):
if request.is_websocket():
for message in request.websocket:
c=str(message,encoding='utf-8')
print(c)
request.websocket.send(message)
return render(request,'socket_test.html')
#主动推送消息
@accept_websocket
def test_websocket(request):
if request.is_websocket():
while 1:
time.sleep(1) ## 向前端发送时间
dit = {
'time':time.strftime('%Y.%m.%d %H:%M:%S',time.localtime(time.time()))
}
request.websocket.send(json.dumps(dit))
return render(request,'websocket_test.html')
#微博
'''
拼接url->回调获取code->利用code换取uid和access_token->适用access_token获取用户信息
oauth授权第一步 authorize接口,请求用户授权code
'''
#新浪微博登录地址组合返回(第一步)
class weibo(APIView):
def get(self,*args,**kwargs):
#微博接口地址
weibo_auth_url = "https://api.weibo.com/oauth2/authorize"
#回调网址
redirect_url = "http://127.0.0.1:8000/api/weibo"
#应用id
client_id = "137408567"
#组合url
auth_url = weibo_auth_url + "?client_id={client_id}&redirect_uri={re_url}".format(client_id=client_id,
re_url=redirect_url)
print(auth_url)
return HttpResponse('66')
页面交互jinja2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.table{
border-spacing: 0;
border-collapse: collapse;
}
.table thead tr th,td{
padding: 20px;
padding-left: 50px;
vertical-align: top;
border-top: 1px solid #ddd;
}
td,th{
display: table-cell;
}
</style>
</head>
<body>
<h3><a href="/api/Myc/">验证码</a></h3>
<h3><a href="/api/erweima/">二维码</a></h3>
<h3><a href="/api/ding_url/">扫码登录</a></h3>
<h3><a href="/api/pay">支付宝支付</a></h3>
<h3><a href="{% url 'export_excel' %}">Export all goods</a></h3>
<form action="" method="get">
<input type="text" placeholder="name" name="name">
<button type="submit">搜名字</button>
</form>
<table class="table table-striped">
<tr>
<th>id</th>
<th>name</th>
<th>price</th>
<th>img</th>
<th>del</th>
<th>edit</th>
<th>add</th>
</tr>
{#使用for循环拿到当前页面上的所有数据对象(for循环中的c_page相当于c_page.object_list)#}
{% for i in c_page %}
<tr>
<td>{{i.id}}</td>
<td>{{i.name}}</td>
<td>{{i.price}}</td>
<td><img src="{{i.img}}" width="150" height="100"></td>
<td> <a href="/api/del/?id={{i.id}}" class="delete">删除</a></td>
<td> <a href="/api/edit/?id={{i.id}}" class="edit">修改</a></td>
<td><a href="/api/index/">添加</a></td>
</tr>
{% endfor %}
</table>
{# 要实现的效果#}
{# 上一页 1 2 3 下一页#}
{# 0、实现上一页 #}
{# 若有上一页,则拿到上一页的页码超链接 #}
{% if c_page.has_previous %}
<a href="/api/goods?page={{ c_page.previous_page_number }}">上一页</a>
{# 若没有上一页,则显示为普通的字符即可 #}
{% else %}
上一页
{% endif %}
{# 1、实现中间部分 #}
{#使用循环拿到每个页面#}
{% for p_num in paginator.page_range %}
{#若是当前页,则显示为普通的一个数字#}
{% if p_num == c_page_number %}
{{ p_num }}
{# 若不是当前页面,则显示为一个超链接 #}
{% else %}
<a href="/api/goods?page={{ p_num }}">{{ p_num }}</a>
{% endif %}
{% endfor %}
{# 2、实现下一页 #}
{# 若有下一页,则拿到下一页的页码超链接 #}
{% if c_page.has_next %}
<a href="/api/goods?page={{ c_page.next_page_number }}">下一页</a>
{# 若没有下一页,则显示为普通的字符即可 #}
{% else %}
下一页
{% endif %}
</body>
</html>