diadia

興味があることをやってみる。自分のメモを残しておきます。

django リダイレクトについて

URL dispatcher — Django 1.4.6 documentation

 

 

クラスベースビューには、データ表示系のもの(ListViewやDetailView)とデータベース編集系のもの(CreateView,Updateview,DeleteView)がある。

データベース編集系には一種の特徴がある。フォームにデータ入力し送信すると、別のページに飛ばすことが一連の流れとして組み込まれている。詳しくは下記に補足1として後述する。

そういうわけでこちらが飛ばす先のページを予め設定していないとエラーになってしまう。

エラー:リダイレクト先を設定してねって。

 

 

このリダイレクト先を設定する方法について少しわかったのでまとめておく。

リダイレクト先を決める機能はsuccess_url である。

使い方は簡単でsuccess_url=reverse_lazy('urls.pyで定めたビューネーム')と設定すれば良い。詳しく知りたい場合は補足2参照。

 

ただしurlが動的な場合には、話が違ってくる。

なぜならこの方法が通用しないから。

reverse_lazyの引数にビューネームに加え、遷移したい数字等も必要になるのだ。

要は、success_url=reverse_lazy("ビューネーム",4)みたいなことがしたいわけだ。

でこの4は状況にによっては5や6にしたいってわけ。

get_success_url(self)を使うと、urls.pyの urlが取得できると思われる。

pathの第一引数のこと。

def get_url_success(self):

     return reverse_lazy("urls.pyのname",kwargs={"pk":self.kwargs["pk"]} )

 

 

 

(補足1)edit系のクラスベースビューにリダイレクトが組み込まれている件について

edit系(CreateView,Updateview,DeleteView)にはそれぞれsuccess_url (※デフォルトでNone設定)属性をもつ。継承時には、この属性を定めてあげないとリダイレクト先に飛べずにエラーとなってしまう。例としてCreateViewを見てみる。
CreateViewはBaseCreateViewのpostメソッドを読み込む。このpostメソッドはProcessFormViewのpostメソッドを読み込む(つながる)。そしてform_validメソッドを読み込むことになる。

class BaseCreateView(ModelFormMixin, ProcessFormView):
    ...省略...
    def post(self, request, *args, **kwargs):
        self.object = None
        return super().post(request, *args, **kwargs)

https://github.com/django/django/blob/2.1/django/views/generic/edit.py#L160

class ProcessFormView(View):
    ...省略...
    def post(self, request, *args, **kwargs):
        """
        Handle POST requests: instantiate a form instance with the passed
        POST variables and then check if it's valid.
        """
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

https://github.com/django/django/blob/2.1/django/views/generic/edit.py#L129

form_validメソッドはまずModelFormMixinのほうを読み込む。ここでフォームに入力されたデータが新たに作られる。作られたのちFormMixinのform_validメソッドを読み込む。読み込んだ先はHttpResponseインスタンスの生成につながる。この引数にget_success_url()メソッドがあり、ここでsuccess_urlが必要になる。

class ModelFormMixin(FormMixin, SingleObjectMixin):
    ...省略...
    def form_valid(self, form):
        """If the form is valid, save the associated model."""
        self.object = form.save()
        return super().form_valid(form)

https://github.com/django/django/blob/2.1/django/views/generic/edit.py#L123

class FormMixin(ContextMixin):
    ...省略...
    def form_valid(self, form):
        """If the form is valid, redirect to the supplied URL."""
        return HttpResponseRedirect(self.get_success_url())

https://github.com/django/django/blob/2.1/django/views/generic/edit.py#L55

get_success_url()メソッドはModelFormMixinを読み込む。ここでCreateViewの継承したクラスにsuccess_urlを設定していないと、get_absolute_urlを取得しようとする。それでもできなかったものは"No URL to redirect to. Either provide a url or define"" a get_absolute_url method on the Model."というエラーを吐き出すことになる。

class ModelFormMixin(FormMixin, SingleObjectMixin):
     ...省略...
    def get_success_url(self):
       
        """Return the URL to redirect to after processing a valid form."""
        if self.success_url:
            url = self.success_url.format(**self.object.__dict__)
        else:
            try:
                url = self.object.get_absolute_url()
            except AttributeError:
                raise ImproperlyConfigured(
                    "No URL to redirect to.  Either provide a url or define"
                    " a get_absolute_url method on the Model.")
        return url

https://github.com/django/django/blob/2.1/django/views/generic/edit.py#L110

(補足2)success_url=reverse_lazy('urls.pyで定めたビューネーム')の使い方について

reverse_lazyとreverseの使い方は以下のように使う。
reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
https://docs.djangoproject.com/ja/2.2/ref/urlresolvers/#django.urls.reverse

reverse_lazy(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
https://docs.djangoproject.com/ja/2.2/ref/urlresolvers/#django.urls.reverse_lazy
要するにどちらもviewnameを記述すればよい。viewnameはurlconf(urls.py)で記述したname="hoge"のhogeを書くか、views.function_nameみたいな形でも良い。
今回の記事でなぜreverse_lazyを使ったのかについては以下の根拠がある。

Some common cases where this function is necessary are: providing a reversed URL as the url attribute of a generic class-based view. providing a reversed URL to a decorator (such as the login_url argument for the django.contrib.auth.decorators.permission_required() decorator). providing a reversed URL as a default value for a parameter in a function's signature.

generic class-based viewのurlアトリビュートとしてURLをreverseで使いたいときにはreverse_lazyが必要になる、ということだそうだ。今回はedit系のViewのurl(success_url)属性を定めるのでreverse_lazy()を採用する。