DjangoでDB接続・操作

# ORM (Object-Relational Mapping)
**データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法**である
コード-> ORM -> DB connection module -> DB

# install DB connection module
## postgreSql
`pip install psycopg[binary] `

# django側の設定
- ファイルを作成
	- `.pg_service.conf`
		- windowsの場合、`%APPDATA%\Roaming\postgresql`で作成する
		- linuxの場合、Homeディレクトリ
	- `.my_pgpass` Djangoのプロジェクト・ディレクトリ

### ファイルの内容
- `.pg_service.conf`
```
[db_service]
host=localhost
user=USER_NAME
dbname=DB_NAME
port=5432
```
- `.my_pgpass` 
```
localhost:5432:DB_NAME:USER_NAME:PASSWORD
```


# (ORM) DB操作
`app/models.py`でクラスの編集によってデーブルを操作する

## Create table
```python
from django.db import models

class Offices(models.Model):
    office_name = models.CharField(max_length=32)
    isDeleted = models.BooleanField(default=False)

    class Meta:
        db_table = 'offices' #テーブルの名前
```
ここで、一個のクラスが一個のテーブルに対応している。
クラスを作成してから、`manage.py`で `makemigrations`を実行して、`miragte`を行うと、DBに変更を書き込む。
Primary Keyを指定していない場合、idという列のをPrimary Keyとして自動的作ってくれる。
データ追加するとき、そのidの値が自動的に生成する。

>以下でいうmigrateとは、`manage.py`で`makemigrations`してから、`migrate`を行う操作です。

## Delete table

models.pyでそのテーブルに対応しているクラスを注釈にして、migrateすると、DBにあるテーブルを削除できる。

### 列の削除
同じく、テーブルで列を**削除**したい場合、クラスで新しいfieldを追加し、migrateするとDBが変更される。

## 列の追加
しかし、デーブルに列を追加したい場合、下記の警告が出る。これは、新しく追加された列で既存の行の値が決まっていないからです。
```
It is impossible to add a non-nullable field 'office_id' to offices without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit and manually define a default value in models.py.
```
そこで、二つの選択肢がある。
- `1)` を選択した場合、値をその場で入力する。
- `2)`を選択した場合、デフォルトの値を`models.py`で決める。（`default=<?>`か、`null=True, blank=True`などを入れる）

## Foreign Keyの設定
参照元：部門テーブル
```python
class Group(models.Model):
    group_id = models.IntegerField(primary_key=True)
    group_name = models.CharField(max_length=32, help_text='部門名')
    # Foreign Key を設定
    department = models.ForeignKey(Department, on_delete=models.CASCADE)
```

参照先：部署テーブル
```python
class Department(models.Model):
    department_id = models.IntegerField(primary_key=True, help_text='部署ID')
    department_name = models.CharField(max_length=32, help_text='部署名')
```

ここで、部署と部門は一対多の関係である。
### on_deleteの設定
外部キーで参照先テーブルを削除された場合の挙動を設定する
- CASCADE：参照先デーブルが削除されたら、参照元テーブルも削除される。
- PROTECT：参照元のデータが全部削除されていない限り、参照先のテーブルを削除できない


# (ORM) データ操作
## Create
`クラス.objects.create`でデータを追加する
`Offices.objects.create(office_id=1, office_name='本社', isDeleted=False)` ,
SQLの`insert into offices (office_id, office_name, isDeleted) values (1, '本社', False)`と等しい

## Delete
- 特定のレコードを削除：`クラス.objects.filter(id=3).delete()`
- 全てのレコードを削除：`クラス.objects.all().delete()`

## Select
`クラス.objects.all()`
`クラス.objects.filter(id=1)`
戻り値はQuerySet型のListで、Listの各要素がデーブルの一行をObjectとして格納している。

戻り値が一行しかない場合、`クラス.objects.filter(id=1).first()` でその行のObjectを返却させる
> `first()`は最初の行のObjectを返す

## Update
全てをUpdate：`クラス.objects.all().update(列=値)`
特定のレコードをUpdate：`クラス.objects.filter(id=1).update(列=値)`


# Admin.pyでテーブルのmodelsを登録
Appの`admin.py`で下記のように記載する：
```python
from App.models import オブジェクト
admin.site.register(modelsオブジェクト)
```
そして、`manage.py`で`createsuperuser`をし、管理者アカウントを作成し、`runserver`すると、テーブルをadminページで管理できるようになる。