Hello, 各位,我回來了,大家別以為我消失了,我還是在的...
最近忙於家裡重要事情,不能定期及時更新,請包含...
忙裡挑一,我還是在後臺默默的碼了幾篇文章,前提要保證下質量,才能發出來,哈哈!不然...嘿嘿
大家搬好小板凳了,前方的真的高能,文章篇幅有點多,一步一步來...
跟著我走,簡單學起來...
1. 回顧知識
上一篇文章已經教會了大家怎麼安裝Django和簡單的配置,相信大家應該早就學會了,那麼我們在回憶一下吧,懂的同學可跳過這章節。
1.1 新增工程
django-admin startproject <自定義工程名稱>
(py369) [python@localhost Python]$ django-admin startproject devops
1.2 建立新的APP
python manage.py startapp <自定義APP名稱>
(py369) [python@localhost devops]$ python manage.py startapp hello
1.3 註冊APP
在devops->settings.y
裡面t新增:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 第一種方式
'hello.apps.HelloConfig',
# 第二種方式,直接寫hello也行
'hello',
]
1.4 編寫URL和VIEW
在devops下的主路由urls.py
:
from django.contrib import admin
from django.urls import path,include
from views import index
urlpatterns = [
path('admin/', admin.site.urls),
path('', index.index),
# 引導到hello下的路由URL(也叫子路由)
path('hello/', include('hello.urls'))
]
在hello下的子路由urls.py
:
from django.urls import path
from hello import view
app_name = 'hello'
urlpatterns = [
# 普通url引數
path('', view.index, name='index'),
hello下的view.py
程式碼:
from django.http import HttpResponse
def index(request):
return HttpResponse('hello django')
1.5 驗證結果如下:
2. 基本概念
2.1 專業術語
MTV簡寫:
-
M:model,這個是對應資料庫的,簡單理解就是對應資料庫的表。
-
T:template,這個對應的是HTML模板,前端渲染用的。
-
V:view,這個對應的是後臺python執行指令碼了。
通俗的一句話:使用者傳送http請求,匹配url
後執行view
指令碼返回模板template
,使用者看到了網頁的展示效果(渲染)
。
2.2 MTV之檢視
2.2.1 request物件
2.2.2 Respone物件
下面詳細介紹下...
2.2.3 GET請求
-
GET請求,不帶引數
網頁輸入這樣的格式,是
不帶引數
:https://192.168.8.130:8888/hello
備註:如上面演示的就是不帶引數。
-
GET請求,?+引數
比較常用的方式
?+引數
在瀏覽器輸入如下地址:
http://192.168.8.130:8888/hello/?year=2020&month=09&day=02
說明: 引數:
year
month
day
網址匹配到路由
hello/url.py
的配置規則from django.urls import path from hello import view app_name = 'hello' urlpatterns = [ # 普通引數 path('', view.index, name='index'), ]
後臺檢視
hello/view.py
程式碼配置如下:from django.http import HttpResponse def index(request): print(request.GET) return HttpResponse("year is {}, month is {}, day is {}.".format(year, month, day))
後臺列印輸出的結果如下:
備註: 是一個QueryDict
物件。<QueryDict: {'year': ['2020'], 'month': ['09'], 'day': ['02']}>
從上面已經接收到使用者的資訊了,就可以獲取相應的引數了,hello/view後臺指令碼更新如下:
from django.http import HttpResponse def index(request): #第一個引數是獲取QueryDict的year #第二引數是預設值,表示拿不到資料,用預設值 year = request.GET.get('year', '2030') month = request.GET.get('month', 'Sep') day = request.GET.get('day', '8') return HttpResponse("year is {}, month is {}, day is {}.".format(year, month, day))
網頁請求帶引數返回的結果如下:
網頁請求不帶引數返回的結果如下:
-
GET請求,位置引數
不推薦使用,位置要一一對應入座
網址匹配到路由
hello/url.py
配置規則from django.urls import re_path from hello import view app_name = 'hello' urlpatterns = [ # 位置引數 # [0-9]表示數字0-9,{4}表示取4位數字 re_path('([0-9]{4})/([0-9]{2})/([0-9]{2})/', view.index, name='index'), ]
後臺檢視
hello/view.py
指令碼配置如下:def index(request, year, month, day): return HttpResponse("year is {}, month is {}, day is {}.".format(year, month, day))
網頁輸入如下地址,請求返回的結果如下:
-
GET請求,關鍵字引數
說明:
強烈推薦,優雅的方式
.在瀏覽器輸入如下地址:
http://192.168.8.130:8888/2020/09/02
路由檢視
hello/url.py
配置規則from django.urls import re_path from hello import view app_name = 'hello' urlpatterns = [ # 關鍵字引數,(?<引數名>引數型別) re_path('(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})', view.index, name='index'), ]
後臺檢視
hello/view.py
指令碼配置如下:from django.http import HttpResponse def index(request, **kwargs): # 輸出結果:{'year': '2020', 'month': '09', 'day': '02'} print(kwargs) year = kwargs.get('year') month = kwargs.get('month') day = kwargs.get('day') return HttpResponse("year is {}, month is {}, day is {}.".format(year, month, day))
還可以換成另外一種寫法,更加靈活,但是用的也不是很多:
from django.http import HttpResponse # 不用考慮到函式引數的位置 def index(request, day, month, year): return HttpResponse("year is {}, month is {}, day is {}.".format(year, month, day))
2.2.4 POST請求
在devops/setting.py裡把csrf
關閉,不然會執行報錯:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 預設開啟防止中間人CSRF攻擊,前期先註釋掉
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
網址匹配到路由hello/urls.py
配置規則
from django.urls import path
from hello import view
app_name = 'hello'
urlpatterns = [
path('', view.index, name='index'),
]
後臺檢視hello/view.py
指令碼配置如下:
from django.http import HttpResponse, QueryDict
def index(request):
if request.method == "POST":
# POST方法
print(request.method)
# body是位元組編碼,b'year=2020&month=09&day=13'
print(request.body)
# 轉換為字典{'year': '2020', 'month': '09', 'day': '13'}
print(QueryDict(request.body).dict())
# <QueryDict: {'year': ['2020'], 'month': ['09'], 'day': ['13']}>
print(request.POST)
data = request.POST
year = data.get('year', '2030')
month = data.get('month', '9')
day = data.get('day', '8')
return HttpResponse("year is {}, month is {}, day is {}.".format(year, month, day))
模擬觸發POST流量:
[root@localhost ~]# curl -X POST http://192.168.8.130:8888/hello/ -d 'year=2020&month=09&day=13'
year is 2030, month is 9, day is 13.
看看我們後臺接收哪些資訊:
2.2.5 QueryDict介紹
在httprequest物件中,GET和POST屬性是django.http.QueryDict的例項,它是一個自定義的類似字典的類,用來處理同一個鍵帶多個值。無論使用GET,POST方式,他們最終都是通過QueryDict方法對傳入的引數進行處理。
3. MTV之模板
3.1 模板繼承
3.1.1 常規手段
-
建立模板
templates
目錄及子目錄hello
:mkdir -p devops/templates/hello
備註:每一個APP對應一個目錄。
-
路由檢視
hello/urls.py
配置規則from django.urls import path from hello import view app_name = 'hello' urlpatterns = [ path('list/', view.list, name='list'), ]
-
後臺檢視
hello/view.py
配置from django.shortcuts import render def list(request): users = [ {'username':'test01', 'age':18, 'hobby':'python'}, {'username':'test02', 'age':18, 'hobby':'java'}, {'username':'test01', 'age':18, 'hobby':'C'}, ] return render(request, 'hello/list.html', {'users':users})
說明:本次練習,還沒涉及到資料庫,所以先本地建立資料。
-
新建模板
templates/hello/list.html
配置<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>點滴技術</title> </head> <body> <p style="background-color: #77ee77">使用者列表</p> <table border="1"> <thead style="background-color: #00aced"> <tr> <td>username</td> <td>age</td> <td>hobby</td> </tr> </thead> <tbody> {% for user in users %} <tr> <td> {{ user.username }} </td> <td> {{ user.age }} </td> <td> {{ user.hobby }} </td> </tr> {% endfor %} </tbody> </table> <p style="background-color: yellow"> 版權所有©點滴技術 </p> </body> </html>
-
網頁輸入地址後,效果圖:
3.1.2 模板繼承
-
定義母板
在devops/templates
目錄下新增一個base.html
母板。<!doctype html> <html lang="en"> <head> <!-- 每個html的標籤變數,都可以自定義--> <title> {% block title %}NetDevOps{% endblock title %} </title> </head> <body> <!-- body變數,每個頁面都可以自定義內容--> {% block body %}這是body的內容{% endblock body %} <!-- 底部,每個html頁面固定樣式 --> <p style="background-color: yellow"> 版權所有©點滴技術 </p> </body> </html>
-
子頁面繼承
<!--繼承母版--> {% extends "base.html" %} <!--重寫title的內容--> {% block title %} 使用者的列表 {% endblock %} <!--重寫body的內容--> {% block body %} <table border="1"> <thead style="background-color: #00aced" > <tr> <td>username</td> <td>age</td> <td>hobby</td> </tr> </thead> <tbody> {% for user in users %} <tr> <td> {{ user.username }} </td> <td> {{ user.age }} </td> <td> {{ user.hobby }} </td> </tr> {% endfor %} </tbody> </table> {% endblock%}
備註:公共部分程式碼就不用寫出來了,減少了程式碼冗餘。
-
檢視
hello/view.py
配置from django.shortcuts import render def userlist(request): users = [ {'username':'test01', 'age':18, 'hobby':'python'}, {'username':'test02', 'age':18, 'hobby':'java'}, {'username':'test03', 'age':18, 'hobby':'C'}, ] return render(request, 'hello/userlist.html', {'users':users})
-
效果圖:
4. Template模板過濾器
4.1 Django自帶常用過濾器
-
傳入引數的長度
{% if messages|length >= 3 %} The Messages is too long. {% else %} The messages is too short. {% endif %}
-
default:預設值
{{ messages|default:"nothing" }}
備註:如果傳入的值為false,則使用預設值。
-
first/last
{{ messages|first }} {{ messages|last }}
備註:顯示列表第一個或最後一個元素。
-
join
說明:將列表轉為字串。{{ value|join:"-" }}
-
length
說明:判斷長度,返回布林值{{ messages|length}} {{ messages|length_is:"4"}}
-
static
說明:載入本地圖片、css、js樣式等資源,通常使用CDN方式。# 方法1: {% load static %} <img src="{% static "images/favicon.png" %}" alt="Hi!" /> # 方法2: {% load static %} {% static "images/favicon.png" as myphoto %} <img src="{{ myphoto }}"></img>
-
date
說明:時間格式化,返回年-月-日 時-分-秒{{ messages|date:"Y/m/d" }}{{ messages|date:"H:i:s" }}
-
safe
說明:預設情況下,django會對HTML等標籤進行自動轉義,如果要關閉自動轉義,可通過過濾器"|safe"的方式申明不用轉義。value = "<a href="https://www.python.org"> 百度連結 </a>" {{ value|safe }}
-
csrf_token
說明:用於跨站請求偽造保護<form action="" method='post'> {% csrf_token %} # 有了這個POST請求才能正常執行 <p> <input type="text" name="user"></p> <input type="submit"> </form>
-
slice
說明:切片{{ messages|slice:":2"}}
4.2 自定義模板標籤和過濾器
-
定義標籤
建立目錄及檔案:hello/templatetags/mytag.py
from django import template register = template.Library() @register.filter def test(x, y): return int(x)*2 + int(y)qq
-
模板檢視
<!--繼承母版--> {% extends "base.html" %} {% block title %}模板標籤{% endblock %} <!--重寫body的內容--> {% block body %} <!--自定義模板標籤--> {% load mytag %} <p> {{ "2"|test:"1" }}</p> {% endblock%}
5. 模型Model基礎
5.1 模型概念
簡單理解:模型對應資料庫中的表,模型中的一個類對應資料庫一張表;
5.1.1 常用欄位型別
-
字串:
CharFieLd
from django.db import models class User(): username = models.CharField(max_length=20)
-
整數:
IntegerField
int_field = models.IntegerField()
-
浮點數:
FloatField
float_field = models.FloatField()
-
自增欄位:
AutoField
id_field = models.AutoField(primary_key=True)
-
文字框:
TextField
text_field = models.TextField()
-
郵箱:
EmailField
說明:用於檢查郵箱的合法性。mail_field = models.EmailField()
-
日期:
DateField
說明:
auto_now
是被儲存時,將時間設定為當前時間,通常表示last-modified
,auto_now_add
是首次被建立時,設定為當前時間,通常表示建立時間。date = models.DateField()
-
檔案上傳:
Filefield
說明:upload_to
必選引數,指檔案的上傳存放路徑。upload_file = models.FileField(upload_to='/usr/tmp/test')
5.1.2 常用欄位引數
- null
如果null=True
將再資料庫存放一個空值NULL,預設為Flase。
該欄位是可以在資料中存放null值。 - blank
如果blank=True
,則允許該欄位為空白,預設是False,不允許為空。
該欄位是表單驗證是否允許為空或不為空的。 - unique
如果unique=True
,表示該欄位在整個表單中是唯一的,不重複的。 - primary_key
如果primary_key=True
, 表示該欄位在資料庫中是主鍵。 - default = ''
用於定義預設值。 - verbose_name
ForeignKey
、ManyToManyField
、和OneToOneField
的備註資訊需要用到這個。
6. 建模及同步
6.1 設計一個簡單的模型
hello\models.py
:
#!/usr/bin/env python3
#-*- coding:UTF-8 -*-
from django.db import models
class Devices(models.Model):
device_name = models.CharField(max_length=32, help_text='裝置名稱')
ip = models.CharField(max_length=15, help_text='管理IP地址')
vendor = models.CharField(max_length=16, help_text='廠商')
device_type = models.CharField(max_length=6, help_text='裝置型別')
model = models.CharField(max_length=32, help_text='裝置型號')
sn = models.CharField(max_length=32, help_text='序列號')
os = models.CharField(max_length=16, help_text='作業系統')
version = models.CharField(max_length=32, help_text='版本')
def __str__(self):
return self.device_name
6.2 將模型同步到資料庫
-
生成遷移指令碼
(py369) [root@localhost devops]# python manage.py makemigrations hello Migrations for 'hello': hello/migrations/0004_devices.py - Create model Devices
-
展示遷移的sql語句
(py369) [root@localhost devops]# python manage.py sqlmigrate hello 0004 BEGIN; -- -- Create model Devices -- 此處省略...
-
執行資料庫命令
(py369) [root@localhost devops]# python manage.py migrate hello Operations to perform: Apply all migrations: hello Running migrations: Applying hello.0004_devices... OK
-
檢視資料庫表
-
常用命令解釋
# 生產遷移指令碼 python manage.py makemigrations <app_name> # 轉換後的sql語句 python manage.py sqlmigrate <app_name> <number> # 執行資料庫命令 python manage.py migrate # 所有APP及對應生效的migration python manage.py showmigrations # 將某個APP的migration重置 python manage.py migrate --fake hello # 強制執行某個版本的遷移指令碼 python manage.py migrate --fake hello python manage.py migrate --fake hello 0004
7. ORM實現簡單的增刪改查
7.1 ORM概念
- ORM是對資料抽象建模並提供訪問介面的程式設計方式
- 模型中的一個類(class)表示一個表(table)
- 每一個屬性對應資料表中的一個欄位
- 呼叫資料表,就是例項化類的物件
7.2 增 | 刪 | 改 | 查
7.2.1 增加資料
(py369) [root@localhost devops]# python manage.py shell
In [1]: from hello.models import Devices
# 例項化物件
In [4]: D = Devices.objects.all()
In [5]: D
# 暫時還沒有資料,為空
Out[5]: <QuerySet []>
In [7]: data = {'device_name':'test-sw-01', 'ip':'192.168.1.1', 'vendor':'cisco','device_type':'switch','model':'c3850','sn':'001','os':'ios','version':'15.0'}
# 第一種建立方式(最常用)
In [8]: D.create(**data)
Out[8]: <Devices: test-sw-01>
# 第二種建立方式(防止重複,速度相對較慢):
# 返回一個元組(物件,True或False)
In [10]: data2 = {'device_name':'test-sw-02', 'ip':'192.168.1.2', 'vendor':'cisco','device_type':'switch','model':'c3850','sn':'001','os':'ios','version':'15.0'}
In [14]: D.get_or_create(**data2)
Out[14]: (<Devices: test-sw-02>, True)
In [16]: D
Out[16]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>]>
7.2.2 刪除刪除
資料庫表中的資料(偷偷增加了一臺裝置):
In [1]: from hello.models import Devices
# 刪除一條記錄
# 第一種方法:get
In [4]: D = Devices.objects.get(device_name = 'test-sw-02')
In [5]: D.delete()
Out[5]: (1, {'hello.Devices': 1})
# 第二種方法:filter
In [2]: Devices.objects.filter(device_name='test-sw-03').delete()
Out[2]: (1, {'hello.Devices': 1})
# 先還原資料,再刪除所有的記錄
In [5]: Devices.objects.all().delete()
Out[5]: (3, {'hello.Devices': 3})
7.2.3 修改資料
# 第一種方法:
In [2]: D = Devices.objects.get(device_name='test-sw-03')
In [3]: D.device_name = 'test-sw-13'
In [4]: D.save()
In [5]: Devices.objects.all()
Out[5]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>, <Devices: test-sw-13>]>
# 第二種方法:
# 指定欄位更新,偷偷去看下後臺的ID是多少
In [6]: Devices.objects.filter(id=11)
Out[6]: <QuerySet [<Devices: test-sw-13>]>
In [7]: Devices.objects.filter(id=11).update(device_name='test-sw-03')
Out[7]: 1
In [8]: Devices.objects.get(device_name='test-sw-03')
Out[8]: <Devices: test-sw-03>
# 多個欄位更新
In [26]: data = {'vendor':'huawei','device_type':'switch','model':'S9303','sn':'001','os':'VRP'}
In [27]: Devices.objects.filter(id=11).update(**data)
Out[27]: 1
最終效果如下(通過資料庫查詢):
7.2.4 檢視資料
-
查詢多條資料
列表巢狀一個字典(QuerySet物件)
# 查詢所有 In [30]: D = Devices.objects.all() In [31]: D Out[31]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>, <Devices: test-sw-03>]> # 每個物件及物件的屬性 In [32]: D[0] Out[32]: <Devices: test-sw-01> In [33]: D[0].device_name Out[33]: 'test-sw-01' # 切片,不支援負索引 In [34]: D[:2] Out[34]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>]> # 遍歷 In [36]: for d in D: ...: print(d.device_name) ...: test-sw-01 test-sw-02 test-sw-03 # 返回指定的欄位(values_list 和 values) In [37]: D.values_list('device_name','ip') Out[37]: <QuerySet [('test-sw-01', '192.168.1.1'), ('test-sw-02', '192.168.1.2'), ('test-sw-03', '192.168.1.3')]> In [39]: D.values('device_name','vendor') Out[39]: <QuerySet [{'device_name': 'test-sw-01', 'vendor': 'cisco'}, {'device_name': 'test-sw-02', 'vendor': 'cisco'}, {'device_name': 'test-sw-03', 'vendor': 'huawei'}]>
-
查詢一條資料
# 第一種方法: In [2]: D = Devices.objects.get(device_name='test-sw-01') In [3]: D # 返回的是一個物件 Out[3]: <Devices: test-sw-01> # 取物件的屬性值 In [4]: D.device_name Out[4]: 'test-sw-01' In [5]: D.vendor Out[5]: 'cisco # 第二種方法: In [6]: data = {'device_name':'test-sw-01'} In [7]: D = Devices.objects.get(**data) In [8]: D.device_name Out[8]: 'test-sw-01'
- 過濾查詢
In [9]: Devices.objects.filter(device_name='test-sw-01') Out[9]: <QuerySet [<Devices: test-sw-01>]> In [11]: Devices.objects.filter(**data) Out[11]: <QuerySet [<Devices: test-sw-01>]>
- 過濾常用方法:
# 不區分大小寫:<屬性值>__iexact In [16]: Devices.objects.filter(device_name__iexact='test-sw-01') Out[16]: <QuerySet [<Devices: test-sw-01>]> # 包含匹配:<屬性值>__contains In [17]: Devices.objects.filter(device_name__contains='sw') Out[17]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>, <Devices: test-sw-03>]> # 模糊匹配,不分割槽大小寫:<屬性值>__icontains In [18]: Devices.objects.filter(device_name__icontains='sw') Out[18]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>, <Devices: test-sw-03>]> # 正則模糊匹配:<屬性值>__regex In [20]: Devices.objects.filter(device_name__regex='-03$') Out[20]: <QuerySet [<Devices: test-sw-03>]> # 正則模糊匹配,不區分大小寫:<屬性值>__regex In [21]: Devices.objects.filter(device_name__iregex='^test') Out[21]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>, <Devices: test-sw-03>]> # 排除過濾:<屬性值>__contains In [22]: Devices.objects.exclude(device_name__contains='test-sw-01') Out[22]: <QuerySet [<Devices: test-sw-02>, <Devices: test-sw-03>]> # 包含帶有sw的device_name,但排除了vendor是cisco廠商的 In [23]: Devices.objects.filter(device_name__contains='sw').exclude(vendor='cisco') Out[23]: <QuerySet [<Devices: test-sw-03>]> # filter其他常用過濾查詢方法 __exact:精確匹配 __iexact:精確匹配,忽略大小寫 __gt:大於 __gte:大於等於 __lt:小於 __lte:小於等於 __in:在一個list列表範圍內 __startswith:以...開頭 __startswith:以...開頭,忽略大小寫 __endswith:以...結尾 __range:在...範圍內 __year:日期的年份 __month:日期的月份 __day:日期的日數 __isnull=True/False:欄位是否為空
get
和filter
的區別:# 都可以獲取到指定的物件; # get是獲取唯一資料的場景,資料不存在會報錯; # filter適用於任何場景,返回是一個QuerySet物件,資料不存在則返回是空的物件。
-
排序查詢
# 正序 In [32]: Devices.objects.all().order_by('device_name') Out[32]: <QuerySet [<Devices: test-sw-01>, <Devices: test-sw-02>, <Devices: test-sw-03>]> # 倒序,前面加 In [33]: Devices.objects.all().order_by('-device_name') Out[33]: <QuerySet [<Devices: test-sw-03>, <Devices: test-sw-02>, <Devices: test-sw-01>]>
8. 打通MTV
8.1 建立模型
參見以上的hello/models.py
的配置。
8.2 建立檢視view
from django.shortcuts import render
from hello.models import Devices
def devicelist(request):
# 物件例項化
devices = Devices.objects.all()
# {'devices':devices}表示傳參
return render(request, 'hello/device.html', {'devices':devices})
8.3 建立模板
<!--繼承母版-->
{% extends "base.html" %}
<!--重寫title的內容-->
{% block title %}裝置列表{% endblock %}
<!--重寫body的內容-->
{% block body %}
<p style="background-color: #77ee77">裝置列表</p>
<!--表格-->
<table border="1">
<!-- 表頭-->
<thead style="background-color: #00aced" >
<tr>
<td>裝置名稱</td>
<td>IP地址</td>
<td>廠商</td>
<td>裝置型別</td>
<td>型號</td>
<td>序列號</td>
<td>作業系統</td>
<td>版本號</td>
</tr>
</thead>
<!--表的正文-->
<tbody>
{% for device in devices %}
<tr>
<td> {{ device.device_name }} </td>
<td> {{ device.ip }} </td>
<td> {{ device.vendor }} </td>
<td> {{ device.device_type }} </td>
<td> {{ device.model }} </td>
<td> {{ device.sn }} </td>
<td> {{ device.os }} </td>
<td> {{ device.version }} </td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock%}
8.4 建立路由檢視URL
from django.urls import path
from hello import view
app_name = 'hello'
urlpatterns = [
path('devicelist', view.devicelist, name='devicelist'),
]
8.5 效果圖如下:
大家先不要在意前端效果,後面的專案,再把UI
這塊優化好,先到這裡了,大家學會了嗎?
好不容易碼完這篇了,大家點個贊吧!
如果喜歡的我的文章,歡迎關注我的公眾號:點滴技術,掃碼關注,不定期分享