我们的丰收款主题完结了吗?
今天即使达成铁人赛的2/3赛程,在先前的篇幅已完整将每一个功能都实作出来了,原本在思考剩下的1/3是否要结束丰收款的主题,抓紧时间启动另一个Shioaji的证券主题。不过想说既然头都洗了,不如就趁这个机会,再强化一些使用Django来实作电商UI端的情境范例,所以接下来就是再把几个使用情境写一写,让整个串接的运作更有感。Shioaji就再往後摆,看後面有剩下的时间的话再来浅谈几篇了,虽然其实我蛮想试试程序交易这个议题。(好想有平行时空另一个我再写Shioaji的主题呀)
所以接下来是会以Django Web的几个页面实作情境,带到串接我们之前实作完成的永丰API Python程序码,也让有兴趣想多了解Django的实作的朋友有机会将「丰收款API + Python + Web技术」三个愿望,一次满足。
首先,为了让UI可以简单快速套用自适应效果以及有美美好用的UI元件,我会使用Bootstrap作为UI Framework。当然若你们有更顺手的UI元件也可以随意选用。在Django中,有专门的Bootstrap套件可直接安装,而不需要直接复制Bootstrap的Javascript与CSS等档案进来。有django-bootstrap
套件的好处是在Django Template中使用JS或CSS的引用时,是会更贴近Python套件的用法,而非操作硬生生的档案引用的作法。
首先,先使用pip进行django-bootstrap套件安装。
> pip install django-bootstrap-v5
我们因为最後要将程序上到实际的Heroku PaaS环境中,记得要再重新产生一次requirement.txt
。这个是为了在做布署时,让Heroku Server知道需要连带安装的套件。
记得先退到Python Project的root folder去。
还记得语法吗? 使用pip freeze将结果导出成档案,指定到根目录下的requirements.txt
(记得结尾有s)
> pip freeze > requirements.txt
以我的例子,在requirements.txt
中,多出了刚刚安装的django-bootstrap-v5==1.0.5
asgiref==3.4.1
beautifulsoup4==4.10.0
certifi==2021.5.30
charset-normalizer==2.0.6
crypto==1.4.1
decorator==5.1.0
dj-database-url==0.5.0
dj-static==0.0.6
Django==3.2.7
django-bootstrap-v5==1.0.5
gunicorn==20.1.0
idna==3.2
importlib-metadata==3.10.1
Naked==0.1.31
psycopg2==2.9.1
pycryptodome==3.10.4
pytz==2021.1
PyYAML==5.4.1
requests==2.26.0
shellescape==3.8.1
soupsieve==2.2.1
sqlparse==0.4.2
static3==0.7.0
urllib3==1.26.7
zipp==3.6.0
记得,在mysite底下的settings.py中,要在INSTALLED_APPS
中加上bootstrap5
,才会生效喔!
例如:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap5',
'order',
'greetings',
]
还记得我们刚使用Django时,写了一个greetings的丑丑测试页面(index),现在我们在下面再加上一个test页面,来测试一下刚刚的Bootstrap套件。
不知道要怎麽使用Bootstrap的话,可以使用这个页面模板产生器网站:
https://generator.ws/demo/
选一个你喜欢的模版後即可简单下载,我们就把这个内容拿来做成我们要测试的Django Template页。
我们要使用Django的Template,才能强化View的呈现,总不能每次都只能硬刻HTML语法然後用HttpResponse传回去吧。
在我们的Django App下,例如这次是在greetings
下建立一个templates
目录,接着,在底下再建一个greetings
目录,然後才把你要的Template HTML放在底下。
有些人会把页面直接摆在templates的目录底下,而没有多建一个与App名称相同的目录,这样基本上若你App之间没有使用相同名称的话虽不会错,但不建议这样使用。若不同的Django App使用了相同的View页面名称,会有抓取顺序错误的可能。
因此我们建立一个test.html
,放置位置在:mysite/greetings/templates/greetings/test.html
内容如下:
{% load bootstrap5 %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome to KummyShop</title>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
{% bootstrap_css %}
<link rel="icon" href="favicon.ico">
</head>
<body>
<section class="bg-light pt-5 pb-5">
<div class="container pb-5">
<div class="row justify-content-center d-flex">
<div class="col-xs-12 col-md-10 align-self-center">
<h1 class="display-4 text-center mb-3 mt-5">{{ title }}</h1>
<p class="lead text-center">{{ desc }}</p>
<div class="justify-content-center d-flex mt-3 mb-1">
<a class="btn btn-primary btn-lg mt-md-3 me-2" href="#"
role="button">{{ buttons.0 }}</a>
<a class="btn btn-outline-secondary btn-lg mt-md-3 ml-md-3"
href="#" role="button">{{ buttons.1 }}</a>
</div>
</div>
</div>
</div>
</section>
{% bootstrap_javascript %}
</body>
</html>
上面落落长,重点几个:
{% load bootstrap5 %}
,在meta加入{% bootstrap_css %}
,在body结束前加入{% bootstrap_javascript %}
{{ title }}
,底下p段落加上{{ desc }}
,两个button加上{{ buttons.0 }}
与{{ buttons.1 }}
前面是为了产生bootstrap5所需要的javascript与css档,後面则是我们从View届时会准备传入相关的变数,要拿来显示用。
於是我们可以在View中撰写test页所需要的资料,不过通常顺序一般规画是反过来的,照理说会先实作View中要准备什麽资料,然後才在Template里去挖洞填入。但因为刚刚先行介绍了Template後,不想跳来跳去的,但我相信聪明的读者一定可以理解。(好不负责任呀…)
我们在greetings的view.py
中,新增这段:
from django.shortcuts import render
def test(request):
context = {
"title": "库米狗屋 ● Kummy Shop",
"desc": "这里应有尽有,只是都缺货中,欢迎使用永丰银行信用卡唷!",
"buttons": ["加入会员", "我先逛逛"]
}
return render(request, 'greetings/test.html', context)
这里我们使用和先前直接回传HttpResponse
型别回去稍有不同,我们使用了render
的方式回传,把绑定Template机制的所需资料以简化的方式丢回去即可,你只需要准备好context所需要的资料,把request、template位置、context放进参数中。
如果是使用HttpResponse的方式,你还需要先将Template先用loader载入,再用loader去render()出来,上面这个作法是较为精简快速的作法,虽然如果有用到进阶一点的使用方式会有些许功能作不到。完整作法可至Django官网都看的到,这边主题不是以Django细部讲解为主,因此点到为止罗。
迫不及待了吧,之前的页面因为目的不同,为了实作串接永丰API的验证正确性为目的,都丑丑的,即将焕然一新了!
我们可以按右键看一下HTML原始码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome to KummyShop</title>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" rel="stylesheet">
<link rel="icon" href="favicon.ico">
</head>
<body>
<section class="bg-light pt-5 pb-5">
<div class="container pb-5">
<div class="row justify-content-center d-flex">
<div class="col-xs-12 col-md-10 align-self-center">
<h1 class="display-4 text-center mb-3 mt-5">库米狗屋 ● Kummy Shop</h1>
<p class="lead text-center">这里应有尽有,只是都缺货中,欢迎使用永丰银行信用卡唷!</p>
<div class="justify-content-center d-flex mt-3 mb-1">
<a class="btn btn-primary btn-lg mt-md-3 me-2" href="#"
role="button">加入会员</a>
<a class="btn btn-outline-secondary btn-lg mt-md-3 ml-md-3"
href="#" role="button">我先逛逛</a>
</div>
</div>
</div>
</div>
</section>
<script crossorigin="anonymous" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
其中,可以比对一下原先插入bootstrap相关的位置
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" rel="stylesheet">
<script crossorigin="anonymous" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
接下来实作情境页面,当然不会去实作商品页与购物车的部份(写完又30天了),所以我们会直接从「结帐页面」开始写起,把有串到永丰API的情境页实作出来。
明天继续!
<<: Day20 - 在 XState 与 Side Effect 互动吧~ action API
Everybody has a different definition of the good ...
昨天是用继承Thread来执行多执行序,今天介绍另外一种方法,实作Runnable介面一样可以执行多...
前言 今天要延续昨天的NumPy语法练习 内容会分成两大部分 将会涵盖如何提取、更新、删除阵列里的...
上一篇我们的基因体时代-AI, Data和生物资讯 Day17-分析定序档案格式SAM, BAM的工...
那今天终於要来开始打code了!! 就从最基本的 Hello World开始吧 每一款程序语言最基本...