概要
DjangoのCreateView、UpdateViewでBootstrapのModalフォームを使ったサンプルアプリを作りました。
”django-bootstrap-modal-forms”というプラグインの”BSModalCreateView”、”BSModalUpdateView”を使っています。
日本語のリファレンスや、小さい規模のサンプルアプリが見つからなかったので、まとめておきました。
環境
Python 3.8.0
Django 3.0.4
Bootstrap 4.1.3
プラグイン:django-bootstrap-modal-forms
インストール
- django-bootstrap-modal-formsプラグインのインストール
pip install django-bootstrap-modal-forms==1.5.0
- django-widget-tweaksのインストール
pip install django-widget-tweaks==1.4.5
やり方
settings.pyの編集
# myproject/myproject/settings.py
INSTALLED_APPS = [
~
'bootstrap_modal_forms',
'widget_tweaks'
]
使用するModel
# mypeoject/myapp/models.py
import datetime
from django.db import models
class TodoItem(models.Model):
item = models.CharField(max_length=50)
item_date = models.DateField(default=datetime.date.today)
user = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE
)
def __str__(self):
return self.item
forms.pyの編集
# mypeoject/myapp/forms.py
from bootstrap_modal_forms.forms import BSModalForm
from modalform.models import TodoItem
class CreateUpdateTodoItemForm(BSModalForm):
class Meta:
model = TodoItem
fields = ['item', 'item_date']
views.pyの編集
# mypeoject/myapp/views.py
from bootstrap_modal_forms.generic import BSModalCreateView, BSModalUpdateView
from modalform.forms import CreateUpdateTodoItemForm
from modalform.models import TodoItem
def show_todo_items(request):
all_items = TodoItem.objects.filter(user=request.user)
return render(request, 'show_todo_items.html', {'all_items': all_items})
class CreateTodoItemFormView(BSModalCreateView):
template_name = 'create_modal_form.html'
form_class = CreateUpdateTodoItemForm
success_message = 'Success: Item was created.'
success_url = reverse_lazy('show_todo_items')
def form_valid(self, form):
form.instance.user_id = self.request.user.id
return super(CreateTodoItemFormView, self).form_valid(form)
class UpdateTodoItemFormView(BSModalUpdateView):
model = TodoItem
template_name = 'update_modal_form.html'
form_class = CreateUpdateTodoItemForm
success_message = 'Success: Item was updated.'
success_url = reverse_lazy('show_todo_items')
def delete_todo_item(request, todo_id):
item = TodoItem.objects.get(pk=todo_id)
item.delete()
messages.success(request, ('Deleted successfully!'))
return redirect('show_todo_items')
urls.pyの編集
from django.urls import path
from modalform import views
urlpatterns = [
path('', views.show_todo_items, name='show_todo_items'),
path('create_todo_item/', views.CreateTodoItemFormView.as_view(), name='create_todo_item'),
path('update_todo_item/<int:pk>', views.UpdateTodoItemFormView.as_view(), name='update_todo_item'),
path('delete_todo_item/<todo_id>', views.delete_todo_item, name='delete_todo_item'),
]
template(html)の作成
show_todo_items.htmlの作成
{% extends 'base.html' %}
{% load static %}
~
{% block content %}
<!-- Todo追加フォーム -->
<form class="form-inline my-2 my-lg-0" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<button type="button" class="create_item bg-light rounded" data-id="{% url 'create_todo_item' %}"><span class="fa fa-pencil">Itemの登録</span></button>
</form><br>
<!-- modal -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
<div class="modal-dialog" role="document">
<div class="modal-content"></div>
</div>
</div>
<!-- TodoListテーブルの表示 -->
{% if all_items %}
<table class="table table-bordered tablesorter-bootstrap" id="recipe-table">
<thead>
<tr class="table-primary">
<th style="text-align: center;">Item</th>
<th style="text-align: center;">Date</th>
<th style="text-align: center;">Edit</th>
<th style="text-align: center;">Delete</th>
</tr>
</thead>
<tbody>
{% for i in all_items %}
<tr class="table-info">
<td style="text-align: center;">{{ i.item }}</td>
<td style="text-align: center;">{{ i.item_date|date:"n/j D" }}</td>
<td style="text-align: center;">
<button type="button" class="update_item bg-light rounded" data-id="{% url 'update_todo_item' i.pk %}"><span class="fa fa-pencil">Edit</span></button>
</td>
<td style="text-align: center;">
<button type="button" class="bg-light rounded"><a href="{% url 'delete_todo_item' i.id %}"><span class="fa fa-pencil">×</span></a></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<script type="text/javascript">
{# Create Item Modal Form #}
$(function () {
$(".create_item").each(function () {
$(this).modalForm({formURL: $(this).data('id')});
});
});
{# Update Item Modal Form #}
$(function () {
$(".update_item").each(function () {
$(this).modalForm({formURL: $(this).data('id')});
});
});
</script>
{% endblock content %}
create_modal_form.htmlの作成
{% load widget_tweaks %}
<form method="post" action="" autocomplete="off">
{% csrf_token %}
<div class="modal-header">
<h3 class="modal-title">Create Item</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
<div class="{% if field.errors %} invalid{% endif %}">
{% for error in field.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary my-2 my-sm-0" data-dismiss="modal">Close</button>
<button id="create" class="btn btn-outline-secondary my-2 my-sm-0" type="submit">Save</button>
</div>
</form>
<script type="text/javascript">
$('#id_item_date').datepicker({
dateFormat: 'yy-mm-dd',
autocomplete: "off"
})
</script>
※この例では、日付の表示にdatepickerを使っています。
フォームのidは"id_field名"で自動的に割り当てられます
update_modal_form.htmlの作成
{% load widget_tweaks %}
<form method="post" action="" autocomplete="off">
{% csrf_token %}
<div class="modal-header">
<h3 class="modal-title">Update Item</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
<div class="{% if field.errors %} invalid{% endif %}">
{% for error in field.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary my-2 my-sm-0" data-dismiss="modal">Close</button>
<button id="update" class="btn btn-outline-secondary my-2 my-sm-0" type="submit">Update</button>
</div>
</form>
<script type="text/javascript">
$('#id_item_date').datepicker({
dateFormat: 'yy-mm-dd',
autocomplete: "off"
})
</script>
※create_modal_form.htmlとほぼ同じです。
モーダルタイトルをCreate Item→Update Item、ボタンをupdate→saveに修正しただけです。
Github
サンプルアプリのコードはGithubにアップしています。
Readmeにデモ動画も載せているので、以下のページを見てもらえると分かりやすいと思います。
Githubのページ
まとめ
プラグインdjango-bootstrap-modal-formsを使った、bootstrap4のmodalのCreateView、UpdateViewフォームの作り方を紹介しました。
Djangoでモーダルフォームを使ったサンプルが中々見つけられなかったので、参考にしていただければと思います。