こんにちは。リューさんです。この記事では、Djangoを用いてWebアプリケーションを作成しているときに詰まったこと、困ったこととその解決方法を書いていきます。
ViewsのTips
form入力後、もとのページにリダイレクトさせたい
formが一つの場合、元居たページにリダイレクトさせることは簡単です。しかし、複数ページで同じviewを使う場合、元居たページにリダイレクトさせるためには少し工夫が必要になります。
まず、templateに以下のように記述します。以下の例では、inputのvalueにURLを指定しています。
<form action="{% url 'foo:bar' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"/>
<!-- 適当なフォーム -->
<button class="btn btn-outline-primary" type="submit">send</button>
</form>
次に、viewでその値を受け取り、受け取ったURLにリダイレクトするようにします。views.pyに以下のように記述します。
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
def foo(request, foo_id):
# 何らかの処理
if request.method == "POST":
next_url = request.POST.get('next', None)
# 何らかの処理
if next_url:
return HttpResponseRedirect(next_url)
else:
return redirect('hoge:huga') #値がうまく取れなかったときの処理
これで上手くいくはずです。試してみてください。
Post送信後、入力した値をclearしたい
掲示板アプリなど、Post後に同じページに戻るようなページをDjangoで作っているとき、Postした入力値がformに残っているときがありませんか?また、Post後にF5やリロードすると、再び入力値が入っているなんてことはありませんか?
そんな時は、以下のようにviewでformをsave後にHttpResponseRedirectで同じページにリダイレクトするようにしましょう。また、このようにする場合はformが正常に処理できているか、などもユーザに通知すると良いかもしれません。
if request.method == "POST":
form = forms.TestForm(request.POST)
if form.is_valid():
test = form.save(commit=False)
test.user = request.user
test.save()
return HttpResponseRedirect(request.path)
FormのTips
ラジオボタンをつけたい
こちらは既に素晴らしい記事が多くあるのですが、自分用に書きます。
まず、今回は0,1…のような数字でvalueを管理したいと思っているので、models.pyに以下のように記述します。
from django.db import models
class Hoge(models.Model):
hoge = models.IntegerField(default=0)
次に、forms.pyに以下のように記述します。
from . import models
from django import forms
hoge_choice = [
(0, 'hello'),
(1, 'world'),
(2, '!!!!!'),
]
class HogeForm(forms.ModelForm):
hoge = forms.ChoiceField(
widget=forms.RadioSelect,
label='hoge',
choices=hoge_choice,
)
class Meta:
model = models.Hoge
fields = ('hoge',)
label = {
'hoge': 'ほげ',
}
あとはviews.pyにこのHogeFormを渡して、以下のようにtemplateに記述すればラジオボタンが実装できるはずです。以下の例はbootstrap4を用いた例ですので、適宜修正してください。
{{ form.hoge.label_tag }}
<div class="border-top border-bottom">
{% for radio in form.hoge %}
<div class="custom-control custom-radio pt-1 pb-1">
{{ radio.tag }}
<label class="custom-control-label" for="{{ radio.id_for_label }}">
{{ radio.choice_label }}
</label>
</div>
{% endfor %}
</div>
フォームのタイプに合わせてデザインを変えたい
templateファイルに以下のようにif文で分岐させるように記述することで実現できます。
{% for field in form %}
{% if field.field.widget.input_type == "checkbox" %}
<div class="form-check">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
{% else %}
<div class="form-group">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
{% endif %}
{% endfor %}
ただ、Bootstrapを使う場合、Djangoはulタグで囲まれたformを返してくるのでいい感じにすることができません。そのような場合はカスタムウイジェットを作ることで対応できます。
フォームのウィジェットを変更したい
forms.py に以下のように記述します。以下の例は__init__で変更していますが、Metaやviewで変更する方法もあります。
class Meta:
model = models.Hoge
fields = ('hoge', 'huga')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['hoge'].widget = forms.CheckboxSelectMultiple()
self.fields['hoge'].queryset = self.fields['hoge'].queryset.filter(hoge__gte=2)
ModelのTips
カスタムユーザモデルを作成する
Djangoの場合ベースのユーザモデルのままだと、開発している途中で「ユーザモデルに年齢や役職を持たせたい!」と思っても、データベースを初期化したり、マイグレーションをごにょごにょしたりしなければ変更できなかったりします。
そこで、カスタムユーザモデルの出番です。今回はより簡単なAbstractUserを継承して作成しましょう。models.pyに以下のように記述します。
class CustomUser(AbstractUser):
UserAuth = [
(0, 'student'),
(1, 'TA'),
(2, 'teacher'),
]
user_auth = models.IntegerField(verbose_name='権限', default=0, choices=UserAuth)
今回は上のようにカスタムユーザモデルに権限のフィールドを追加しました。このように一度カスタムユーザモデルを追加しておけば、以降はそのモデルに追記していけばいいので、必ず作成しておきましょう。
また、追記していくタイプのAbstractUserだけではなく、最初から設定されている属性の削除や変更等も行うことができるAbstractBaseUserを継承してカスタムユーザモデルを作成することも出来ます。ご自身が作成したいアプリに合わせて利用しましょう。
TemplateのTips
submitボタンが押せないとき
ブラウザで検証してみましょう。
An invalid form control with name=’hoge’ is not focusable.
というエラーが出ていませんか?この場合、おそらくformの部品に display:none; というcssが指定されていると思います。display:none;の代わりに、以下のコードを追加しましょう。
var icon_css = {
visibility:'hidden',
width:'0',
height:'0',
}
$('div.form-group input[name="hoge"]').css(icon_css);
この場合は、jqueryを用いてcssを追加していますが、方法は何でも良いです。
おわりに
この記事は公開した後もTipsを学び次第更新していきます。もし、間違えている箇所等ありましたらTwitter(@Ryu_programs)までお願いします。