Help us understand the problem. What is going on with this article?

DjangoのMiddlewareを自作してどこからでもrequest情報にアクセスできるようにしてみた

modelのuser_created(作成者)やuser_updated(更新者)に共通処理でログインユーザを格納できないか考え始めたのがきっかけ。

それまではviewからformにユーザ情報を渡して、user_createdやuser_updatedに格納する処理を書いてました。

Djangoのmiddleware(ミドルウェア)とは

公式より

ミドルウェアは、Django のリクエスト/レスポンス処理にフックを加えるためのフレームワークです。

リクエスト送信時やレスポンス返却前に行う処理を定義できるものです。

middlewareの実装

threadlocalを操作する関数を定義

common/middlewares/threadlocals.py
from threading import local


THREAD_LOCAL = local()


def set_thread_variable(key, value):
    """ スレッドローカルデータに値を格納する
    """
    setattr(THREAD_LOCAL, key, value)


def get_thread_variable(key, default=None):
    """ スレッドローカルデータから値を取得する
    """
    return getattr(THREAD_LOCAL, key, default)


def get_request():
    """ スレッドローカルデータからリクエスト情報を取得する
    """
    return get_thread_variable('request')

middlewareクラスを定義

common/middlewares/request_store_middleware.py
from common.middlewares.threadlocals import set_thread_variable
from django.utils.deprecation import MiddlewareMixin


class RequestStoreMiddleware(MiddlewareMixin):
    def process_request(self, reuqest):
        set_thread_variable('request', reuqest)

今回はリクエストの情報がほしいのでprocess_requestのみ定義しときます。

settings.pyのMIDDLEWAREに追加

settings.py
.
..
...
MIDDLEWARE = [
    .
    ..
    ...
    'common.middlewares.request_store_middleware.RequestStoreMiddleware', # 追加
]
...
..
.

好きなところでget_requestを呼ぶだけ

僕はDBへの保存時にユーザ情報を格納するのが目的なので、models.pyで使用することにしました。

common/models.py
.
..
...
from common.middlewares.threadlocals import get_request
from django.db.models.signals import pre_save
...
..
.
class Company(BaseModel):
    """ 企業モデルクラス
    """
    ...
    ..
    .
    created_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=True, blank=True)
    updated_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=True, blank=True)
...
..
.
def set_user_receiver(sender, instance, *args, **kwargs)
    request = get_request() # user情報を格納する前に認証チェックをしても良いかも
    instance.created_user = request.user
    instance.updated_user = request.user


pre_save.connect(set_user_receiver, sender=Company) # pre_saveを使うと、save()実行前に呼び出したい関数を登録できる。

おわり

Butterthon
いろんなことに興味あります。 最近のマイブームはPython, Django, Vue, Ruby(今更) スキル:C#, Java(Seasar2), Python(Django), Ruby(Rails), JavaScript, jQuery, Vue.js, AWS
https://twitter.com/Butterthon
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away