python工業互聯網應用實戰3—模型層構建

  本章開始我們正式進入到實戰項目開發過程,如何從需求分析獲得的實體數據轉到模型設計中來,變成Django項目中得模型層。當然,第一步還是在VS2019 IDE環境重創建一個工程項目,本文我們把工程名稱命名為IndDemo,如下圖:

 VS2019創建的Django項目結構如下圖

 現在按F5調試程式,又來到Django熟悉的歡迎頁面了。

 接下來讓開始這趟實戰之旅吧!

1.1. 實體關係圖

   從上一章需求涉及到的實體,來構建我們的實體關係圖吧,這裡的步驟也相當於早期開發設計的表結構設計,只是如前面章節說的有了ORM機制後,我們討論採用對象模型來設計和討論實體可能更適合於實際的場景討論,便於團隊在同一個頻道下溝通,當然這裡實質上與表設計沒有太多本質的區別,但是多對多等中間表在實體關係圖中就看不到了,表結構設計時就不能忽略這個中間表的存在。產品經理更專註於需求而不是資料庫存儲結構是不是更符合專業分工?開發人員也不用大費周章來折騰表結構的優化了。嗯,這些可以丟給DBA來優化吧。

 本圖採用網址ponyorm網站在線繪製,網址://editor.ponyorm.com/.

1.2. Django model

  為了便於對照學習和理解,我們新增一個新的APP 命名為:Task來專門處理這個業務,不修改默認的APP里的程式碼,也便於過程中可以通過這個默認APP功能,參照它的結構和語法等。

 現在我們的工程目錄結構如下:

     打開Task.models.py文件編寫我們實體關係圖的模型程式碼吧,作者本人比較習慣「大駝峰」命名法也就是首字母都大寫的模式TaskNum,後面很多命名都會採用這個方式,不採用python主流的蛇形命名法的task_num方式,純屬個人習慣。我們依據設計我們開始構建我們的model程式碼如下:

from django.db import models
from django.contrib.auth.models import User

PRIORITY=((1,u'正常'),(2,u''),(3,u'緊急'))

class Task(models.Model):
    TASK_STATE=((1,u'未處理'),(4,u'處理成功'),(5,u'執行中'),(99,u'完成'),(-1,u'已取消'))

    TaskId = models.AutoField(primary_key=True, db_column='task_id')
    TaskNum = models.IntegerField(u'任務號', null=False, db_column='task_num')
    Source = models.CharField(u'源地址', null=False, max_length=50, db_column='source')
    Target = models.CharField(u'目標地址', null=False, max_length=50, db_column='target')
    Barcode = models.CharField(u'容器條碼', null=False, max_length=50, db_column='barcode')
    State = models.IntegerField(u'狀態', choices=TASK_STATE, null=False, db_column='state')
    Priority = models.IntegerField(u'優先順序', choices=PRIORITY, null=True, db_column='priority')
    BeginDate = models.DateTimeField(u'開始時間',null=True, db_column='begin_date')
    EndDate = models.DateTimeField(u'結束時間',null=True, db_column='end_date')
    SystemDate = models.DateTimeField(u'系統時間', null=False, auto_now_add=True, db_column='system_date')
    User = models.ForeignKey(User, verbose_name="操作員", on_delete=models.CASCADE,db_column='user_id')

    class Meta:
        db_table = 'task_task'
        ordering = ['-Priority','TaskId']
        verbose_name = verbose_name_plural = "任務"

    def __str__(self):
        return str(self.TaskNum)


class Job(models.Model):
    JOB_STATE=((1,u'新作業'),(2,u'下達執行'), (99,u'完成'),(-1,u'已取消'))

    JobId = models.AutoField(primary_key=True, db_column='job_id')
    Task = models.ForeignKey('Task', verbose_name="任務", blank=True, on_delete=models.CASCADE)
    TaskNum = models.IntegerField(u'任務號', null=False, db_column='task_num')
    OrderNo = models.IntegerField(u'順序號', null=False, db_column='order_no')
    Source = models.CharField(u'源地址', null=True, max_length=50, db_column='source')
    Target = models.CharField(u'目標地址', null=True, max_length=50, db_column='target')
    Executor = models.CharField(u'執行器', null=False,blank=True, max_length=50, db_column='executor')
    State = models.IntegerField(u'狀態', choices=JOB_STATE, null=False, db_column='state')
    Priority = models.IntegerField(u'優先順序', choices=PRIORITY, null=True, db_column='priority')
    BeginDate = models.DateTimeField(u'開始時間',null=True, db_column='begin_date')
    EndDate = models.DateTimeField(u'結束時間',null=True, db_column='end_date')
    SystemDate = models.DateTimeField(u'系統時間', null=False, auto_now_add=True, db_column='system_date')
    Barcode = models.CharField(u'條碼', null=False, max_length=50, db_column='barcode')
    User = models.ForeignKey(User, verbose_name="操作員", on_delete=models.CASCADE,db_column='user_id')

    class Meta:
        db_table = 'task_job'
        ordering = ['JobId']
        verbose_name = verbose_name_plural = "作業"

    def __str__(self):
        return str(self.TaskNum) +'-'+str(self.OrderNo)

 1.3. make migrations創建資料庫遷移

   首先,我們在項目的settings.py文件里登記我們新增加的APP,程式碼如下:

INSTALLED_APPS = [
    'app',
    'Task',
    # Add your apps here to enable them
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

然後,在IDE通過菜單就可以創建新建model產生的資料庫遷移,如下圖:

 

1.4. migrate 遷移資料庫

  同樣在IDE窗口可以直接執行遷移命令,執行完數據遷移命令,工程默認鏈接的SQLite資料庫就包含這次我們創建的數據表了。

 通過資料庫工具查看數據文件裡面的表創建情況。

1.5. Create Superuser

  由於我們的model Task中定義了User這個引用django.contrib.auth.models.User的外鍵非空屬性,我們需要創建一個Django Admin的超級用戶,才能正常的保存Task 模型。

  按照命令提示創建好超級用戶我們就可以通過ORM操作資料庫了。

1.6. Django ORM操作

    Django ORM提供了諸多的API介面,詳情請參考官網文檔或網上教程,筆者的項目實戰也是遇到某類問題了,也是大量通過搜索引擎來找到相關的使用方法來改進功能程式碼的。 實戰項目使用到ORM的操作很多,未來我們會逐步的使用到時,會進一步說明。本章節只舉一些常用的例子。

 通過ORM我們可以不關心資料庫表結構,採用ORM機制就可以CRUD表裡的數據了,數據將按照對象的方式的方式返回。

1.返回所有的Task對象

>>> from Task.models import Task

>>> Task.objects.all()

<QuerySet []>  

2.新增Task對象

>>> a=Task(None,'1001','121','1-1-1001','2002001',1,1,None,None,None,1)

>>> a.save()

>>> Task.objects.all()

<QuerySet [<Task: 1001>]>

  通過資料庫工具也能看到這條新創建的Task

 

3.通過TaskId獲取Task對象

>>> Task.objects.filter(pk=1)

<QuerySet [<Task: 1001>]>
>>> Task.objects.get(TaskId=1)

<Task: 1001>

  注意上面get方法的兩個不同的屬性

 4.通過dict對象創建Task對象,這個模式後面用在以Json格式從前台提交數據會非常方便

>>>data={"TaskNum":"1002","Source":"122","Target":"1-1-1002","Barcode":"2002002","State":1,"Priority":1,"User_id":1}

>>> model=Task(**data)

>>> model.save()

>>> Task.objects.all()

<QuerySet [<Task: 1001>, <Task: 1002>]>

  注意:User外鍵對象必須通過_id賦值”User_id”:1,通常在變數前加一個星號(*)表示這個變數是元組/列表,加兩個星號表示這個參數是字典。

 5.匹配條件

>>> Task.objects.filter(TaskNum='1001')

<QuerySet [<Task: 1001>]>

6.不匹配條件

>>> Task.objects.exclude(TaskNum='1001')

<QuerySet [<Task: 1002>]>

7.獲取單條數據(主鍵唯一)

>>> Task.objects.get(pk=1)

<Task: 1001>

>>> Task.objects.get(TaskId=1)

<Task: 1001> 

8.大於 __gt

>>> Task.objects.filter(pk__gt=1)

<QuerySet [<Task: 1002>]>

9.大於等於 __gte

>>> Task.objects.filter(pk__gte=1)

<QuerySet [<Task: 1001>, <Task: 1002>]>

 10.小於 __lt

>>> Task.objects.filter(pk__lt=2)

<QuerySet [<Task: 1001>]>

11.小於等於 __lte

>>> Task.objects.filter(pk__lte=2)

<QuerySet [<Task: 1001>, <Task: 1002>]>

 12.大於和小於, 1 < TaskId < 5

>>> Task.objects.filter(pk__gt=1,pk__lt=5)

<QuerySet [<Task: 1002>]>

13.包含 __in []

>>> Task.objects.filter(pk__in=[1,2,3,4,5])

<QuerySet [<Task: 1001>, <Task: 1002>]>

 14.不包含,not in

>>> Task.objects.exclude(pk__in=[2,3,4,5])

<QuerySet [<Task: 1001>]>

 15.為空:isnull=True

>>> Task.objects.filter(BeginDate__isnull=True)

<QuerySet [<Task: 1001>, <Task: 1002>]>

16.匹配,大小寫敏感 __contains

>>> Task.objects.filter(Barcode__contains="2001")

<QuerySet [<Task: 1001>]>

 17.匹配,大小寫不敏感 __icontains

>>> Task.objects.filter(Barcode__icontains="2001")

<QuerySet [<Task: 1001>]> 

 18.範圍,__range

>>> Task.objects.filter(pk__range=[2,6])

<QuerySet [<Task: 1002>]>

 19.排序,order by

>>> Task.objects.all().order_by('pk')

<QuerySet [<Task: 1001>, <Task: 1002>]> 

20.倒排序,order by

>>> Task.objects.all().order_by('-pk')

<QuerySet [<Task: 1002>, <Task: 1001>]> 

  更多的ORM查詢操作查閱官網文檔,上面是業務編程過程用得比較多的一些過濾查詢方法。

 1.7. 小節

本章我們著重在通過構建實體和實體關係圖,實體的屬性通常來自業務需求分析和設計時增加的一些必要的欄位,如:時間戳、創建對象的用戶等就是為了便於查找、定位、過濾數據,以及業務管理上考慮必要增加的一些多出來的實體屬性。這裡筆者由於歷史習慣,表欄位命名又採用蛇形命名法,所以增加了一個強制欄位名稱的屬性db_column=‘user_id’都是個人習慣緣故,如果全部採用蛇形命名法這個屬性就可以去掉了。完成了model的構建後,我們就可以進行展開業務邏輯的開發了。

下一章我們講講Django後台開發的利器 Django Admin,來快速的構建一個後台管理框架,你會發現Django給我們省了好多好多事情。