Djangoアプリ開発

# 目次
* はじめに
* 開発環境など
* 開発
    * プロジェクト作成
    * DB作成
    * 表示用URL作成
    * URLをクリックした際の処理を記述
    * 一覧を表示するWebページの作成
    * 完成

## はじめに
Djangoでのアプリ開発に初挑戦したので、知識を整理するために、この記事を書きます。


## 開発環境など
|種類|内容| |
| ---- | ---- |--|
|OS|Windows11|
|Python|3.10.9|
|統合開発環境|VScode|
|親プロジェクト作成フォルダ|D:¥Python¥Django|
|親プロジェクトフォルダ|sales|D:¥Python¥Django¥sales|

　親プロジェクトフォルダ＝Djangoの個々のプロジェクトを入れるフォルダ

## 開発
### プロジェクト作成
Powershell起動

    cd D:¥Python¥Django
    mkdir sales
    cd sales
    code .

起動したVScode

    ターミナル起動
    python -m venv venv
    ターミナル再起動

    ターミナルのプロンプトがvenvになっていることを確認（なっていなかったら、デフォルトのインタープリターとしてvenvのpythonを指定）

pipバージョンアップ

    python -m pip install --upgrade pip

requirements.txt 作成

    Django~=4.1.3

依存関係インストール

	pip install -r requirements.txt

プロジェクト作成

	django-admin startproject sales_pj .

アプリ作成

	python manage.py startapp sales_app

アプリ登録

	settings.py の INSTALLED_APPS の先頭に 'sales_app' を追加

### DB作成
DB構造
　Djangoが自動生成する３つのテーブルの主キー（ID）は記載していません。

    製品区分：ProductClass
        製品区分：product_class

    商品仕様：Product
        製品id：product_class_id
        商品名：name
        単位：unit
        価格：price

    売上：Sales
        商品仕様id：product_id
        日付：date
        売上数：soled_count

モデル定義：models.py

        class ProductClass(models.Model):
            product_class = models.CharField(max_length=50, null=False)
            
        class Product(models.Model):
            product_class_id = models.ForeignKey(ProductClass, on_delete=models.CASCADE)
            name = models.CharField(max_length=50, null=False)
            unit = models.CharField(max_length=10, null=False)
            price = models.IntegerField()
        
        class Sales(models.Model):
            product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
            date = models.DateField()
            soled_count = models.IntegerField()

モデル定義ファイル生成

    python manage.py makemigrations

モデルのデータベース生成（デフォルトのsqlite3で作成）

    python manage.py migrate

データをちょっと登録（フリーソフトの「A5:SQL Mk-2」を利用）

    ProductClass に bread を登録
    Product に メロンパン(単位:個、価格:150)、クリームパン(単位:個、価格:120)を登録
    詳細は省略

### 表示用URL作成
アプリ用のurlを設定：sales_pjのurls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('sales_app.urls')),
    ]

表示用URLを作成・設定：sales_appのurls.py
　sales_appにurls.pyを作成
　（views.pyのProductClassListView、ProductListViewは後で作る）

    from django.urls import path
    from .views import ProductClassListView, ProductListView
    
    urlpatterns = [
        path('ProductClassList/', ProductClassListView.as_view()),
        path('ProductList/', ProductListView.as_view()),
    ]


### URLをクリックした際の処理を記述
views.py

    from django.views.generic import ListView
    from .models import ProductClass, Product
    
    # Create your views here.
    
    class ProductClassListView(ListView):
        template_name = 'product_class_list.html'
        model = ProductClass
    
    class ProductListView(ListView):
        template_name = 'product_list.html'
        model = Product


### 一覧を表示するtemplate(Webページ)の作成
#### template作成事前準備
template保存用フォルダ作成

    D:\Django\Sales\sales_app\templates

template保存用フォルダ情報をsettings.pyに登録

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [BASE_DIR, 'sales_app/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',
                ],
            },
        },
    ]


##### ProductClassの一覧を表示するtemplateの作成
ProductClassの一覧を表示するWebページ用のtemplateを作成：product_class_list.html
　外部制約で紐づいた子供の情報(FOREIGN KEYを宣言しているテーブル側の情報)も表示する

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        {% for element in object_list %}
        {{ element.product_class }}
        <table border="1">
          <tr>
            <th>内容</th>
            <th>単位</th>
            <th>価格</th>
          </tr>
          {% for item in element.product_set.all %}
            <tr>
              <td>{{ item.name }}</td>
              <td>{{ item.unit }}</td>
              <td>{{ item.price }}</td>
            </tr>
          {% endfor %}
        </table>
        {% endfor %}
    </body>
    </html>

##### Productの一覧を表示するtemplateの作成
Productの一覧を表示するWebページ用のtemplateを作成：product_list.html
　外部制約で紐づいた親の情報(FOREIGN KEYが指し示しているテーブル側の情報)も表示する

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <table border="1">
          <tr>
            <th>品目</th>
            <th>内容</th>
            <th>単位</th>
            <th>価格</th>
          </tr>
          {% for product in object_list %}
            <tr>
              <td>{{ product.product_class_id.product_class }}</td>
              <td>{{ product.name }}</td>
              <td>{{ product.unit }}</td>
              <td>{{ product.price }}</td>
            </tr>
          {% endfor %}
          </table>
    </body>
    </html>

### 完成
動作確認

    python manage.py runserver
　

    http://127.0.0.1:8000/ProductClassList/

表示例

bread
|内容|単位|価格|
|-----|-----|-----|
|メロンパン|個|150|
|クリームパン|個|120|


    http://127.0.0.1:8000/ProductList/

表示例

| 品目 | 内容 | 単位 | 価格 |
|-----|-----|-----|-----|
|bread|メロンパン|個|150|
|bread|クリームパン|個|120|

#### おわり
孫テーブルのSalesを使った集計の一覧表示は今後考えます。