iT邦幫忙

2022 iThome 鐵人賽

DAY 9
0

Day9 模型要買櫃,實作 Model 模型

買了許多新模型當然也要買個模型櫃,買櫃子時也要記得貨比三家,買貴退差價已經是現在常見的消費者福利了。
本章節我們將延續上一節學習到的內容,建立電商網站的第一個應用程式來實作商品模型。

第一個 App

讓我們來建立第一個 App 吧,電商網站首先會想到的是需要一個商品列表的呈現頁面。
這裡我們以 products 來做為我們的 App 名稱,透過 docker 執行 startapp 指令來建立一個新的 app:

docker exec --workdir /opt/app/web example_tenant_web python3.10 manage.py startapp products

現在 web 目錄結構如下:
main 為 django 主要應用程式
customers 為多租戶應用程式
products 為剛剛建立的商品應用程式

.
├── customers
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── main
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── product
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

建立好 App 後我們要在 main/settings.py 進行註冊,每個租戶的商品資料是會各自管理的,所以 products 屬於租戶獨自擁有的應用程式 TENANT_APPS

# main/settings.py

TENANT_APPS = (

    # ...

    'products',
)

接下來我們就開始撰寫 products 的模型吧!

商品模型

定義商品模型 Product ,商品模型的欄位定義了商品名稱、商品描述、商品價格、建立日期、修改日期,使用的欄位與參數皆為『認識模型,常用欄位與參數介紹』中說明過的。
在 Meta 中定義了模型的單複數名稱與使用建立時間進行的排序方式,__str__ 則是調用 Product 物件時返回的物件名稱,要注意的是返回值一定要是 Str 類型,為了避免有時候純數字會被誤判為 Int 類型,所以會使用 f-string 來進行字串格式化。

# products/models.py

from django.db import models

# Create your models here.
class Product(models.Model):
    '''
    商品模型
    '''
    name = models.CharField('商品名稱', max_length=50)
    description = models.TextField('商品描述', max_length=500, null=True, blank=True)
    price = models.PositiveIntegerField('商品價格', default=0)
    created = models.DateTimeField('建立日期', auto_now_add=True)
    modified = models.DateTimeField('修改日期', auto_now=True)

    class Meta:
        verbose_name = '商品'
        verbose_name_plural = '商品'
        ordering = ['-created']

    def __str__(self):
        return f'{self.name}'

商品分類模型

定義商品分類模型 ProductCategory ,商品分類模型的欄位定義了商品分類名稱、商品分類描述、建立日期、修改日期,Meta 與 __str__ 與 Product 設定方式一致。

# products/models.py

# ...

class ProductCategory(models.Model):
    '''
    商品分類模型
    '''
    name = models.CharField('商品分類名稱', max_length=50)
    description = models.TextField('商品分類描述', max_length=500, null=True, blank=True)
    created = models.DateTimeField('建立日期', auto_now_add=True)
    modified = models.DateTimeField('修改日期', auto_now=True)

    class Meta:
        verbose_name = '商品分類'
        verbose_name_plural = '商品分類'
        ordering = ['-created']

    def __str__(self):
        return f'{self.name}'

關聯模型

要將 Product 與 ProductCategory 進行關聯,就要使用到之前介紹過的 Foreignkey 欄位。
我們在 Product 模型加入一個名為 category 的關聯欄位:

# products/models.py

# ...

class Product(models.Model):
    '''
    商品模型
    '''
    name = models.CharField('商品名稱', max_length=50)
    description = models.TextField('商品描述', max_length=500, null=True, blank=True)
    price = models.PositiveIntegerField('商品價格', default=0)
    created = models.DateTimeField('建立日期', auto_now_add=True)
    modified = models.DateTimeField('修改日期', auto_now=True)
    category = models.ForeignKey(
        'products.ProductCategory', blank=True, null=True, 
        on_delete=models.RESTRICT, verbose_name='商品分類', related_name='product_set'
    ) # 新增 category 欄位

    class Meta:
        verbose_name = '商品'
        verbose_name_plural = '商品'
        ordering = ['-created']

    def __str__(self):
        return f'{self.name}'

# ...

資料庫遷移 ( 幫模型買模型櫃 —— 買櫃 )

定義好模型後,一定要進行資料庫遷移 makemigrations 與 migrate
使用 makemigrations 指令生成資料庫遷移檔案

docker exec --workdir /opt/app/web example_tenant_web \
python3.10 manage.py makemigrations products
...

Migrations for 'products':
  products/migrations/0001_initial.py
    - Create model ProductCategory
    - Create model Product

使用 migrate 指令執行資料庫遷移,這裡會將所有租戶都進行遷移

docker exec --workdir /opt/app/web example_tenant_web \
python3.10 manage.py migrate products

...

=== Starting migration
Operations to perform:
  Apply all migrations: products
Running migrations:
  Applying products.0001_initial...
 OK
=== Starting migration
Operations to perform:
  Apply all migrations: products
Running migrations:
  Applying products.0001_initial...
 OK
=== Starting migration
Operations to perform:
  Apply all migrations: products
Running migrations:
  Applying products.0001_initial...
 OK

Schema 結構

查看 schema 結構,可以看到租戶獨立 schema 都新增了 products_product 與 products_productcategory 資料表

                            List of relations
       Schema       |            Name            |    Type     |  Owner  
--------------------+----------------------------+-------------+---------
 public             | customers_client           | table       | db_user
 public             | customers_domain           | table       | db_user
 public             | django_content_type        | table       | db_user
 public             | django_migrations          | table       | db_user

 example01          | auth_group                 | table       | db_user
 example01          | auth_group_permissions     | table       | db_user
 example01          | auth_permission            | table       | db_user
 example01          | auth_user                  | table       | db_user
 example01          | auth_user_groups           | table       | db_user
 example01          | auth_user_user_permissions | table       | db_user
 example01          | django_admin_log           | table       | db_user
 example01          | django_migrations          | table       | db_user
 example01          | django_session             | table       | db_user
 example01          | django_site                | table       | db_user
 example01          | products_product           | table       | db_user
 example01          | products_productcategory   | table       | db_user

 example02          | auth_group                 | table       | db_user
 example02          | auth_group_permissions     | table       | db_user
 example02          | auth_permission            | table       | db_user
 example02          | auth_user                  | table       | db_user
 example02          | auth_user_groups           | table       | db_user
 example02          | auth_user_user_permissions | table       | db_user
 example02          | django_admin_log           | table       | db_user
 example02          | django_migrations          | table       | db_user
 example02          | django_session             | table       | db_user
 example02          | django_site                | table       | db_user
 example02          | products_product           | table       | db_user
 example02          | products_productcategory   | table       | db_user

實作模型,任務完成!

makemigrate 與 migrate 將會一直扮演與資料庫溝通的重要角色,也會一直是使用 Django 的一個課題,有些棘手的情況本來就不好解,所以遇到挫折也不要氣餒。筆者在反覆練習與使用後現在已經可以運用自如,不慌不忙地解決各種資料不同步的問題,相信每個人也都一定辦的到!

下一回『Django Admin,管理室不收管理費』就要來來認識 Django 強大的自帶管理端,來為我們今天建立的模型鋪好地磚。


上一篇
Day8 認識模型,常用欄位與參數介紹
下一篇
Day 10 Django Admin,管理室不收管理費
系列文
全能住宅改造王,Django 多租戶架構的應用 —— 實作一個電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言