はじめに
djangoで、Recordというモデルがあるとします。そのRecordには所有者(owner)というフィールドをもっているとします。更新画面のURLではRecordのプライマリキーを持たせるようにしていて各Recordの更新画面にアクセスしています。「ログインしているユーザー」と「アクセスしようとしているRecordの更新画面の所有者」が異なる場合、アクセスを拒否させたいです。これの実現方法を3つ模索しました。紹介していきます。
- get_object関数に所有判定を書く
- dispatch関数に所有判定を書く
- get関数に所有判定を書く
get_object関数に所有判定を書く
サンプルコード
.py
class RecordUpdateView(LoginRequiredMixin, UpdateView):
#...
def get_object(self, queryset=None):
# 所有者でないレコードにアクセスできないようにする
record = super().get_object()
if self.request.user == record.owner:
return record
else:
raise PermissionDenied
#...
考察
- これが一番無難な実装かなと個人的には思います。
- 仮に他のViewで同様のことがしたい場合、
SingleObjectMixin
を継承しているViewクラス(DeleteViewなど)でないと使えないかもしれません。SingleObjectMixin
がget_object
関数を持っているためです。
dispatch関数に所有判定を書く
サンプルコード
.py
class RecordUpdateView(LoginRequiredMixin, UpdateView):
#...
def dispatch(self, request, *args, **kwargs):
# 所有者でないレコードにアクセスできないようにする
record = super().get_object()
if self.request.user == record.owner:
return super().dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
#...
考察
- ChatGPTに質問して、返ってきた提案です。
- 未ログインの状態で該当のURLにアクセスした場合も所有者判定が行われてしまいます。これは違和感を感じる方も出てくるのではないかと思います。
get関数に所有判定を書く
サンプルコード
.py
class RecordUpdateView(LoginRequiredMixin, UpdateView):
#...
def get(self, request, *args, **kwargs):
# 所有者でないレコードにアクセスできないようにする
record = super().get_object()
if self.request.user == record.owner:
return super().get(request, *args, **kwargs)
else:
raise PermissionDenied
#...
考察
-
get
関数というだけあり、GETメソッド場合しか判定がされないと思います。 -
get
関数は多くのViewクラスで持っているため、応用すればSingleObjectMixin
を持ってないクラスでも使用できそうです。(Recordを親としたデータリストのViewなど)
以上です。
参考