[Django] DjangoORMはほぼ魔法！！なんでもできちゃうんだなぁ（初心者向け）

# この記事の目的
サクッとDjangoのORMに触れてみる

# ORMって？
DjangoのORM (Object-Relational Mapping) は、Pythonのオブジェクトとデータベースの間でデータをやりとりするための仕組みです。
ORMを使うことで、SQLを直接書くことなく、Pythonのコードでデータベースを操作することができます。

# さっそく実践編へ🐰
以下は、DjangoのORMを使ったデータベース操作の一例です。
```orm.py
from django.db import models

# モデルの定義
class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()

    def __str__(self):
        return self.title

# データの取得
books = Book.objects.all()  # 全てのBookオブジェクトを取得する
book = Book.objects.get(pk=1)  # pk=1のBookオブジェクトを取得する

# データの追加
new_book = Book(title='Django for Beginners', author='John Smith', published_date='2022-01-01')
new_book.save()  # データベースに保存する

# データの更新
book.title = 'Django for Experts'
book.save()  # データベースに保存する

# データの削除
book.delete()  # データベースから削除する
```

上記では、まずBookクラスを定義し、Djangoのmodels.Modelを継承します。
このクラスは、データベースのテーブルを表し、各属性はデータベースのカラムに対応します。
### objects属性
objects属性を使って、データベースのテーブルに対して、データの取得、追加、更新、削除を行います。
objects.all()メソッドで全てのデータを取得し、objects.get()メソッドで特定のデータを取得することができます。新しいデータを追加するには、新しいBookオブジェクトを作成して、save()メソッドでデータベースに保存します。既存のデータを更新する場合は、オブジェクトの属性を変更して、save()メソッドを呼び出します。データを削除する場合は、delete()メソッドを呼び出します。

#### ORMってすごいんだなぁ
ORMを使用すると、SQLの知識がなくても、Pythonでデータベース操作を行うことができます。
また、DjangoのORMは、多くの場合、複雑なクエリも簡単に書くことができるため、データベース操作を効率的に行うことができます。


# フィールドの制約
DjangoのORMを使用すると、データベースフィールドの制約を定義することができます。

```model.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    is_available = models.BooleanField(default=True)
```

上記では、is_availableフィールドにデフォルト値を設定し、必須項目にすることができます。
また、CharFieldフィールドには、最大長を設定することができます。


# フィールドの制約
DjangoのORMを使用すると、データベースフィールドの制約を定義することができます。たとえば、以下のような例があります。

```model.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    is_available = models.BooleanField(default=True)
```

上記の例では、is_availableフィールドにデフォルト値を設定し、必須項目にすることができます。また、CharFieldフィールドには、最大長を設定することができます。

# リレーション
DjangoのORMを使用すると、リレーションを定義することができます。

```model.py
class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published_date = models.DateField()
```

上記では、BookとAuthorのモデルを定義し、ForeignKeyを使用して、BookオブジェクトとAuthorオブジェクトの間の1対多のリレーションを定義しています。
on_delete引数を指定することで、親オブジェクトが削除されたときの動作を指定することができます。

# クエリのフィルタリング

DjangoのORMを使用すると、クエリをフィルタリングすることができます。
```query.py
books = Book.objects.filter(author__name='John Smith')
```

上記では、filter()メソッドを使用して、著者名が「John Smith」のすべてのBookオブジェクトを取得しています。
__を使用して、リレーションのフィールドにアクセスすることができます。


# クエリのソート
DjangoのORMを使用すると、クエリのソートを行うことができます。
```query.py
books = Book.objects.order_by('-published_date')
```
上記では、order_by()メソッドを使用して、published_dateフィールドを降順でソートしています。

# クエリの集約
DjangoのORMを使用すると、クエリの集約を行うことができます。
```query.py
from django.db.models import Count

authors = Author.objects.annotate(num_books=Count('book')).order_by('-num_books')
```

上記では、annotate()メソッドを使用して、num_booksという新しいフィールドを追加し、各著者の書籍数を計算しています。
Count()関数は、リレーションフィールドのカウントを行うために使用されています。
order_by()メソッドを使用して、num_booksフィールドを降順でソートしています。

# マネージャー
オブジェクトを操作するためにカスタムマネージャーを定義することができます。

```model.py
class BookManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_available=True)

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published_date = models.DateField()
    is_available = models.BooleanField(default=True)
    
    objects = models.Manager() # デフォルトのマネージャー
    available_books = BookManager() # カスタムマネージャー
```

上記では、BookManagerというカスタムマネージャーを定義し、is_available=Trueの条件を追加しています。available_booksという名前で、BookManagerを新しいマネージャーとして定義しています。オブジェクトには、デフォルトのマネージャーとしてobjectsがありますが、available_booksを使用することもできます。

# カスタムメソッド
モデルにカスタムメソッドを定義することができます。

```model.py
class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published_date = models.DateField()
    is_available = models.BooleanField(default=True)

    def is_new(self):
        return self.published_date > datetime.date.today() - datetime.timedelta(weeks=4)
```

上記では、is_new()というメソッドを追加しています。
このメソッドは、published_dateが最近4週間以内である場合にTrueを返します。
このようなメソッドを追加することで、モデルの機能を拡張することができます。


# P.S. いやぁ〜DjangoORMって魔法じゃん！
私は以前ずっとFastAPIで開発を行なっていて、ORMにSQLAlchemyを使用していました。
まだその時はエンジニアとしてかなりペーペーで英語の分厚いドキュメントが本当に苦痛でした。
DjangoのORMはもういつの間にかデータベースと接続されていて、よしなにデータベース操作が可能です。
うま〜いことDjango側でやってくれてるので頭がボケないようにしていきたいですね🐰