Django:2タイプのCRUD記載方法について特徴と注意事項のまとめ

Django:2タイプのCRUD記載方法について特徴と注意事項のまとめ

DjangoのCRUDは2つの記載パターンがあります。(細分化すればさらにパターン分けられます)

その特徴と注意点をまとめていきます。

大きく分かれる2つのパターン

1つは『至れり尽くせり』だけど制限も様々ある方法。もう1つは『自由度が高い』けどサポートの少ない方法です。

  1. Djangoのプリセットクラスを使う方法:『至れり尽くせり』
  2. 関数(def)を使ってやりくりする方法:『自由度が高い』

パターンをすべて書いていこうとすると長くなるので、詳細は小分けして記載していきます。
この記事内では大枠を記載します。

Djangoのプリセットクラスを使うと実装が簡単

Djangoにはとても優秀なプリセットクラスがいくつも存在しています。

from django.views import generic
from .models import hoge
from .forms import HogeCreateForm

# 一覧
class HogeListView(generic.ListView):
    model = hoge
    template_name = 'hoge_list.html'
    paginate_by = 10
    ordering = ['-created_at']

# 詳細
class HogeDetailView(generic.DetailView):

# 新規追加
class HogeCreateView(generic.edit.CreateView):

# 更新
class HogeUpdateView(generic.edit.UpdateView):

# 削除
class HogeDeleteView(generic.edit.DeleteView):

『一覧』だけ動く形で書いてみました。
今回は詳細説明を省きますが、その他のCRUDもこの程度の文量で制御できます。

プリセットクラスの素晴らしい点

『そのパーツで欲しい機能』が内包された【命令セット】である

プリセットクラスの良さはこの一言に尽きます。

例えば、上に記載した【ListView】のプリセットクラスですが、これだけの記載で url = app:url_list に対してis_paginatedという変数を渡しています。

このis_paginatedには前頁、次頁のリンクまで含まれているのでTemplateで呼べば簡単にページネーションを実装できます。便利ですね。

プリセットクラスの欠点

  1. GETで渡した値をrequestから取得しようとしても一手間必要
  2. 複数の引数を渡すのが難しい

文字で書くと「たったこれだけ」の欠点ですが実装していく過程で『かなりの障害』になることがあります。
両方とも「できない訳ではない」点に注目です。
例えば、getの値はclass内で関数(def)を起動させてselfから取得すれば取得可能です。
複数の引数をtemplate.htmlに渡す方法も同じく、class内でdefを動かせば実装できます。

ただし、こういったカスタマイズをすればするほど『至れり尽くせり』が少しづつ遠くなっていきます。
単純に記載行数も増えますし。

「だったらプリセットクラスを使わないことをデフォルトにしてしまえばいいのでは?」と言う事で、私は基本的にプリセットクラスを使ってません。

プリセットクラスを利用した時のurls.pyの書き方

from django.urls import path
from . import views
app_name = 'Hoge'
urlpatterns = [
path('hoge/<int:num>/', views.HogeListView.as_view(), name='list'),
path('hoge/<int:pk>/edit', views.HogeDetailView.as_view(), name='detail'),
path('hoge/create/', views.HogeCreateView.as_view(), name='create'),
path('hoge/<int:pk>/update/', views.HogeUpdateView.as_view(), name='update'),
path('hoge/<int:pk>/delete/', views.HogeDeleteView.as_view(), name='delete'),
]

こんな感じでviewsのクラス名の後に【.as_view()】をつけます。

関数(def)を使って実装すれば『自由度』高く何でもできる

Views.py の中でClassを宣言せず defを宣言して記載を始めます。

import datetime
from django.shortcuts import render,redirect
from django.db.models import Q
from .models import hoge
from .forms import HogeCreateForm

def HogeListView(request, num=1):

    #時間を取得
    d = datetime.date.today()

    #ユーザー名を合成※名前と名字を合成
    user = request.user.last_name + " " + request.user.first_name
    # GETで渡した検索条件を取得
    q_title = request.GET.get('title')
    q_userid = request.GET.get('userid')

    if q_title is None and q_userid is None:
        list = hoge.objects.order_by('-updated_at')
    else:
        list = hoge.objects.order_by('-updated_at')
        if q_title:
            list = list.filter(Q(title__icontains=q_name))
        if q_userid:
            list = list.filter(Q(user_id__icontains=q_userid))
    list = Paginator(list, 10)

    params = {
        'object_list': list.get_page(num),
        'day': d.strftime('%Y/%m/%d'),
        'user': user
    }
    return render(request, 'hoge/list.html', params)

簡単にGETでのテーブル検索を書いてみました。
出来ることが増えるのでプリセットクラスと比べる(制御する物の数だけ)と文量は増えます。

関数(def)の素晴らしい点

思いついたことをその通りに実装でき、小回りが利く

GETでの受け渡しが簡単にできることはもちろん、例えばユーザーIDという情報を取得できていれば、そのユーザー宛てのメッセージをHogeの抽出データと一緒に渡してページ上で展開することもできます。

複数のアプリを連携させることも、複数のmodelを連携させることも思うままに操作できます。
例えばこんな感じ。消すとこは消しておきましたけど、これ私が最近作ってるCMSです。
これはページ構成要素のリスト(プリセットで言う所のListView)で簡単なページですけど、プリセットクラスでは実装が面倒な要素がいくつか入っています。

  • サイドナビのログインユーザー名/ユーザー区分/ユーザー区分アイコン(fa-cogsの所)
  • 検索の仕組み
  • 右上のユーザー専用ナビ(ログインすると別システムのDB見てリンク集が表示される)

こういう細かな制御もできてしまいます。※本件が細かいかどうかは置いておいて

関数(def)の欠点

  1. コードが長くなりがち(その分ミスや不整合も増える可能性が高まる)
  2. ページネーションなどプリセットクラスに入っている動作もコードに起こさないといけない

「何でも自由にできるけど、それ自分でやってね」という感じです。

リスト表示だけを組もうとすると、関数(def)でも4行で出来ますが、プリセットクラスに入っているページネーションやバリデーションなどは完備されていないのでそのパーツは自分で作成していくことになります。

関数(def)を利用した時のurls.pyの書き方

from django.urls import path
from . import views
app_name = 'Hoge'
urlpatterns = [
path('hoge/<int:num>/', views.HogeListView, name='list'),
path('hoge/<int:pk>/edit', views.HogeDetailView, name='detail'),
path('hoge/create/', views.HogeCreateView, name='create'),
path('hoge/<int:pk>/update/', views.HogeUpdateView, name='update'),
path('hoge/<int:pk>/delete/', views.HogeDeleteView, name='delete'),
]

プリセットクラスと異なり、viewsのクラス名の後に【.as_view()】はつけません。
※つけるとエラー 'function' object has no attribute 'as_view' が出ます。

プリセットクラスは勉強用、実用は関数(def)でいいと思う

全体の流れを知るには関数はやれる事が多すぎて収集つきません。

私みたいに目的があって勉強しながら作成している場合はプリセットクラスで満足できないことが多々あるのでdefからスタートでいいと思います。ただし、ググって多く出てくる初心者用の情報はプリセットクラスを利用しているものが多いので分類できる程度の知識は必要になってきます。

全体の流れのお勉強を主目的としている場合はCRUDの流れをつかむのが第一なのでプリセットクラスの活用がGoodです。前述の通り、初心者向けの情報はプリセットクラスを利用したものが多いですし、簡単なアプリであればこれだけで十分に作成できます。

まとめ

今回はCRUDの基礎として最初に疑問に持つであろうviews.pyの書き出し【class ~~】【def ~~】の違いについてまとめてみました。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください