python3.doc_47
R e i - D r e a m
for Laravel
TOP > Python3 > Django(コントローラ)
Guest
login

最終投稿日:2022年6月18日

Django(コントローラ)
基本構造
DJANGOの思想は、一般的に言われる【MVC】(モデル、ビュー、コントローラ)ではなく【MTV】(モデル、テンプレート、ビュー)となります。
まぁ、ビューはコントローラの様なもので呼び方の違いだけです。。
★ 関数ベース
from django.shortcuts import render
from django.http.response import HttpResponse
def index(request):
    return render(request, 【1】, 【2】)
【1】レンダリングするテンプレート指定
    テンプレートディレクトリは settings.py の TEMPLATES 変数に定義する。
【2】テンプレートへ変数をアサインする。 ※省略可
    辞書型でアサインする
    例)
        my_data = {
                'hoge':'ほげ~',
                'arr_hoge':['hoge','foo','bar','fuga']
            }
★ クラスベース
from django.shortcuts import render
from django.http.response import HttpResponse
from django.views.generic import View
class IndexView(View):
    def get(self,request):                                ※GET 遷移で呼ばれる
        return render(request, 【1】, 【2】)
    def post(self,request):                                ※POST 遷移で呼ばれる
        return render(request, 【1】, 【2】)
共通処理を作る
デコレータを利用すると共通処理を作る事ができます
from django.shortcuts import render
from django.views.generic import View
from django.utils.decorators import method_decorator
#任意のデコレータ名。引数 dispatch は、お約束かな。。
def hoge_decorator(dispatch):
    #全ての変数を受け取れる様にする
    def wrapper(request, *args, **kwargs):
        print('ここからデコレータ処理...')
        print(args)
        print(kwargs)
        args = ('222','bbb')
        print('ここまでデコレータ処理...')
        return dispatch(request, *args, **kwargs)
    return wrapper
#クラスの上に記述すれば、全てのメソッドに有効なデコレータとなる
@method_decorator(hoge_decorator, name='dispatch')
class IndexView1(View):
    #仮に何もパラメータを受け取らないメソッドでもデコレータと引数を合わせる必要がある
    def get(self, request, *args, **kwargs):
        d = {'hoge':'hoge'}
        return render(request, 'hello/index1.html', d)
class IndexView2(View):
    #メソッドの上に記述すれば、そのメソッドのみに有効なデコレータとなる
    @method_decorator(hoge_decorator, name='dispatch')
    def get(self, request, *args, **kwargs):
        print(args)
        print(kwargs)
        d = {'hoge':'hoge'}
        return render(request, 'hello/index1.html', d)
    def post(self, request, *args, **kwargs):
        pass
【解説】
class IndexView1 のメソッド get は、そもそも何のパラメータも受け取らないメソッドとなる
(例:ドメイン/アプリ名/index/)
この場合はデコレータ側で args の内容を変更しても受け取る事ができないので何の影響もない。
class IndexView2 のメソッド get は、args でパラメータを受ける設定となっていると仮定する
(例:ドメイン/アプリ名/index/111/aaa)
この場合は、本来 args の中身 ('111','aaa')を受け取るハズだが、デコレータ処理により('222','bbb')が返却され、メソッド get はその内容を受け取る事となる。
【テクニック】
デコレーターに引数を渡したい場合は、デコレータを更に wrap する事で可能です。

@method_decorator(hoge_decorator('foo'), name='dispatch')
上記デコレーターを処理するデコレーターの定義は以下となります。
def hoge_decorator(hoge):
    def _hoge_decorator(dispatch):
        def wrapper(request, *args, **kwargs):
            print('ここからデコレータ処理...')
            #文字列「foo」が取得できます
            print(hoge)
            print('ここまでデコレータ処理...')
            return dispatch(request, *args, **kwargs)
        return wrapper
    return _hoge_decorator
request の取得
● GET
URL が ****?hoge=aaa&foo=1 で受け取った場合は、QueryDict の辞書型で格納される
    request.GET で辞書型の配列を取得できる。       ※<QueryDict: {'hoge': ['aaa'], 'foo': ['1']}>
    request.GET.get(key = 'hoge', default = 'aaa')    ※個別に取得できる

URL が ****/123/aaa で受け取った場合は、[urls.py]の設定によって受け取り方が変わります
・url(r'^index/(?P\d+)/(?P\w+)$', ~ 省略 ~
           ※ちなみに \d+ は、1個以上の数字、\w+ は、1個以上の英数の正規表現
    ⇒ 以下の2通りの受け取り方ができる
        def get(self, request, id=0, foo=''):        ※そのままプレースホルダの変数名で受け取る
        def get(self, request, **kwargs):            ※辞書型の配列で受け取る
            kwargs.get('id')                                         ※個別に取得できる
● POST
request.POST で辞書型の配列を取得できる。       ※<QueryDict: {'hoge': ['aaa'], 'foo': ['1']}>
request.POST.get(key = 'hoge', default = 'aaa')    ※個別に取得できる
request.POST['hoge']            ※通常の辞書の様にも取得できる
【注意】
    checkbox 属性を取得する場合は、同じ name 属性名が複数存在するため最後の値しか取得できない
    これを回避するには getlist メソッドを使う
    例)
    request.POST.getlist('hoge')            ※リスト型で取得できる
● その他の取得
request.method                       ※「GET」「POST」の文字列を返却する
request.FILES['hoge']            ※ファイルオブジェクトを返却する
request.is_ajax()            ※AJAX からのアクセスかチェックする
request.resolver_match.app_name            ※各アプリの urls.py の app_name を取得できる
request.resolver_match.view_name           ※各アプリの urls.py の ビューの name を取得できる
その他の取得
● settings.py 内の変数を参照する
from django.conf import settings
例)
    settings.DEBUG
● インスタンスのクラス名を参照する
例)
     obj.__class__.__name__            ※自クラスなら self.__class__.__name__ となる
● アプリ名を参照する
例)
     request.resolver_match.app_name
URLの逆引き・リダイレクト処理
● URLの逆引き
アプリの urls.py に登録している name からURLを逆引きする
[urls.py]
    urlpatterns = [
        url(r'^index/$', IndexView1.as_view(), name='index1'),
        url(r'^index/(?P<id>\d+)/(?P<foo>\w+)$', IndexView2.as_view(), name='index2'),
        url(r'^index/(\d+)/(\w+)$', IndexView2.as_view(), name='index3'),
    ] [views.py] from django.urls import reverse
~ 省略 ~
    reverse('hello:index1')                                                             ※ドメイン/hello/index/
    reverse('hello:index2',kwargs={'id':111,'foo':'ccc'})    ※ドメイン/hello/index/111/ccc
    reverse('hello:index3',args=(111,'ccc'))                            ※ドメイン/hello/index/111/ccc
【書式】
reverse( 'アプリ名 : name属性名', パラメータ )
【解説】
パラメータがある場合、urls.py でプレースホルダ付きで定義している場合は必ず変数名【 kwargs 】で辞書型で第2引数を設定する。
プレースホルダが無い場合は変数名【 args 】を使ったタプル型で第2引数を設定する。
また、【 ? 】から始まるパラメータを設定したい場合は単純に以下の様に文字列を結合すれば良い。
例)
    reverse('hello:index1') + '?hoge=1&foo=2'
● リダイレクト処理
from django.http.response import HttpResponseRedirect
~ 省略 ~
    a = '999'
    b = 'DDD'
    return HttpResponseRedirect(f'/hello/index/{a}/{b}')
   ※fプレフィックスにより文字列を埋め込んでいる
    return HttpResponseRedirect(reverse('hello:index2',kwargs={'id':'888','foo':'EEE'}))
   ※reverse を使ってもできる
form 処理
forms.py より定義されたクラスを使い、フォームの制御をします。
#forms.py モジュールをインポート
from . import forms
class IndexView1(View):
    def get(self, request, *args, **kwargs):
        #定義した HogeForm クラスのインスタンスを生成(GET 遷移なので引数なし)
        form = forms.HogeForm()
        #または、対象テーブルよりデータを抽出し、
        instance = HogeTbl.objects.get(id = 1)
        #名前付き引数 instance で初期化すれば更新用の DB の値が反映されたフォームとなる
        form = forms.HogeForm(instance = instance)
        #テンプレートへアサインする
        d = {'form':form}
        return render(request, 'hello/index1.html', d)
    def post(self, request, *args, **kwargs):
        #定義した HogeForm クラスのインスタンスを生成(POST 遷移なので request.POST を引数とする)
        form = forms.HogeForm(request.POST)
        #バリデーション
        if form.is_valid():
            #エラーなし(強引にエラーする事でできる(当然分岐させてセーブしない様にしなきゃだめ))
            form.add_error('hoge', 'ほげは必須です')
            #これでDB保存は完了するが、色々手を加えたい場合は一旦インスタンスにする(下の例)
            form.save()
            #保存せずにインスタンスにする事ができる
            instance = form.save(commit=False)
            #hoge カラムに【5】を代入している
            instance.hoge = '5'
            #更新するカラムを限定する事ができる(逆のブラックリストはない。。)
            instance.save(update_fields = ['hoge','foo'])
        else:
            #エラー
            for field in form.errors:
                #エラーのあったカラム名を特定できる
                print(field)
        d = {'form':form}
        #例なので、バリデーションが OK/NG に関わらず同画面に遷移させています。
        return render(request, 'hello/index1.html', d)
【メモ】
DB に例えば複数チェックボックスの値を格納すると ['1','2','3'] と保存される。
一見リストの様に見えるが、DB に登録しているので当然タイプは文字列となる。
この場合 DB の内容を上の例でいう form = forms.HogeForm(instance = instance) と初期化してもチェックボックスの値は全て false の状態で表示されます。
これを回避するには、リストにキャストしてインスタンスに設定しなおすと良い。(ちょっと強引なので独自にリストに直すメソッドを作った方が良いかも。。)
例)
    instance = HogeTbl.objects.get(id = 1)
    instance.foo = list( instance.foo )            ※カラム foo の中身が文字列の ['1','2','3'] とする
    form = forms.HogeForm(instance = instance)
forms.py に定義した内容を動的に views.py で変更するには、fields を使います。
例)
    form = forms.InfoForm()
    form.fields['hoge'].label = '変更したい値'                                     ※ラベルの変更
    form.fields['hoge'].widget.attrs['style'] = 'font-size:30px;'    ※属性等も変更できる
きっぷる
ログインしてコメントを残そう!!


レンズモード 【新規購入限定用】
きっぷる