【Django】ページネーションの実装について
表示内容が多い場合、内容物を分割して表示するページネーションという方法が一般的に使われると思います。今回はDjangoでのページネーションの導入について書いていきます。
まず汎用ビューを使っている場合は以下のように簡単に実装できるそうです。
例としてはBlogモデルを例にしてます。
view.py
from django.views.generic import ListView from .models import Blog class BlogistView(Listview): model = Blog paginate_by = 5 (内容物の表示数。今回は5件/1ページ)
汎用ビューを使わない場合は以下の関数で実装すできます。
例としては自分で投稿したブログ内容の一覧を想定しています。
view.py
~ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger ~ ~ class MyPageView( UserPassesTestMixin, LoginRequiredMixin): def paginate_queryset(request, queryset, count): paginator = Paginator(queryset, count) page = request.GET.get('page') try: page_obj = paginator.page(page) except PageNotAnInteger: page_obj = paginator.page(1) except EmptyPage: page_obj = paginator.page(paginator.num_pages) return page_obj def myblog_list(request): user = request.user blogs = Blog.objects.filter(custom_user_id=user.id).order_by('post_date') page_obj = paginate_queryset(request, blogs, 5) #(blogs(DBから取得した内容物)を5件/1ページ表示する設定) context = { 'user': user, 'blog_page': page_obj.object_list, 'page_obj': page_obj, } return render(request, 'myblog.html', context)
テンプレートとしては以下の内容で実装しております。
〜〜 <div class="pagenation">ページ</div> <ul class="pagination"> {% if page_obj.has_previous %} <li class="page-item"> <a class="page-link" href="?page={{ page_obj.previous_page_number }}"> <span aria-hidden="true">«</span> </a> </li> {% endif %} {% for num in page_obj.paginator.page_range %} {% if page_obj.number == num %} <li class="page-item active"><a class="page-link" href="#!">{{ num }}</a></li> {% else %} <li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li> {% endif %} {% endfor %} {% if page_obj.has_next %} <li class="page-item"> <a class="page-link" href="?page={{ page_obj.next_page_number }}"> <span aria-hidden="true">»</span> </a> </li> {% endif %} </ul> </div>
実装の結果の様子は以下の写真のようになります。
テンプレートについては他にも種類があるそうなので、
好きなデザインのページネーションを導入ができそうです。
【Django】メッセージフレームワークのフロントエンドについて
前回メッセージフレームワークについて実装しましたが、前回の状態では、
文字だけの表示となってしまう為、今回はBootstrapを使った見た目を調整とメッセージに閉じる機能について書いていきます。
前回のtemplate内容
{% if messages %} {% for message in messages %} {{ message }} {% endfor %} {% endif %}
1.view側のメッセージタイプとtemplate側のclassについて
essages.info(self.request, "メッセージ内容") messages.success(self.request, "メッセージ内容") messages.warning(self.request, "メッセージ内容。") messages.error(self.request, "メッセージ内容") messages.debug(self.request, "メッセージ内容") 上から順に <div class="alert alert-{{ message.tags }}"> のレンダリングが <div class="alert alert-info"> →Bootstrapでのデザイン有り <div class="alert alert-success"> →Bootstrapでのデザイン有り <div class="alert alert-warning"> →Bootstrapでのデザイン有り <div class="alert alert-error"> →Bootstrapでのデザイン無し <div class="alert alert-debug"> →Bootstrapでのデザイン無し
このままではerrorとdebugはBootstrapのデザインが適用できないので、
既にあるBootstrapのデザインに適用できるよう、
classを別のものに置き換えるという方法で、デザインを適用させます。
下が今回の方法のイメージです。
デザイン適用のイメージ messages.error(self.request, "メッセージ内容") ↓ <div class="alert alert-danger"> →Bootstrapでのデザイン有り messages.debug(self.request, "メッセージ内容") ↓ <div class="alert alert-dark"> →Bootstrapでのデザイン有り
2.setting.pyの追加
setting.pyの下の方に以下の内容を追加
...... MESSAGE_TAGS = { messages.ERROR: 'danger', messages.DEBAG: 'dark', }
これでerrorのメッセージもBootstrapのデザインが適用できます。
実装後は下のような感じです。
3.閉じるボタンの実装
メッセージを閉じる場合のXボタンを付けるためには、templateに以下のbuttonタグを追加すれば実装できます。
{% if messages %} {% for message in messages %} <div class="alert alert-{{ message.tags }}"> <div class="message-body"> <div class=""> {{ message }} <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> </div> </div> {% endfor %} {% endif %}
実装後のイメージ(サインイン時のmessages.successの場合)
【Django】メッセージフレームワークの実装について
アプリの投稿などアクションの結果をメッセージとして表示させる為の機能として、メッセージフレームワークというものがあります。今回はメッセージフレームワークの実装について書いていきます。
1.setting.pyの確認・設定
INSTALLED_APPS、MIDDLEWAREはデフォルトの状態で上記のようになっています。
MESSAGE_STORAGEの設定はパフォーマンスに優れたCookieStorageやCookieStoragenとSessionStorageの適位切替の設定(FallbackStorage、デフォルト設定)がありますが、一部うまく表示されないことがあるそうです。
2.view.pyの設定
viewでは主にmessagesのインポートと関数にメッセージ文を組み込みます。
自分の使用例
また、messages.success(self.request, "メッセージ内容")の内容であれば、
以下のSuccessMessageMixinのインポートとsuccess_message = "メッセージ内容"で実装できます。以下はログイン時のメッセージ導入の場合。
汎用view(django.views.generic)であれば、CreateView, UpdateView, DeleteViewなどで使えるそうです(自分では未検証)。
3.templateファイル
実装の様子
字が小さいですがメッセージの導入が完了しました。
このままでは見た目がアレなので、次回はフロントエンド側について書いていきます。
【Django】フロントエンド向けライブラリについて(Sass processor, widget tweaks)
デフォルトのDjangoのフロントエンドを実装する際、Sass(SCSS)使用、Djangoテンプレート変数のフォーム({{ form }})の細かなスタイルングが出来ず、色々調べました。
ライブラリーおかげで上記の問題が解決できたので、使用したライブラリーをまとめてみました。
1. Sass processor
Sass processorはSass(SCSS)をコンパイルする為のライブラリーです。CSSを使うならSassとしてコーディングする方がメリットがあるので、必要となると思います。(rails, lalavelでは標準であるみたいです。)
①ライブラリのインストール
pip install libsass django-compressor django-sass-processor
②setting.pyに追加
③テンプレートファイル(base.htmlなどがベター)に読み込みのためのコードを記述
以上でCSSと同じようにSass・SCSSを使えるようになります。
2.widget tweaks
widget tweaksはテンプレートファイルで使う{{ from }}にclass属性を付与し、CSSなどでスタイリングしたり、textareaのcolsやrowの設定を簡単にしたりします。
①ライブラリのインストール
pip install django-widget-tweaks
②setting.pyに追加
③テンプレートファイルに読み込みのためのコードを記述
class属性を指定できることでフィールドごとの細かなスタイリングやbootstrapなども活用できるので、使い勝手が良いと思います。
【Django】テンプレートでのモデルの値の取得
Djangoで汎用ビュー(ListView 、DetailViewなど)を用いた場合は簡単にモデルの値をテンプレに使用できますが、今回は汎用ビューを使用しない場合でのモデルの値を取得する方法を投稿します。
今回はブログ投稿サイトで自分の投稿した管理ページの実装を想定し、ブログの情報(title,post__date)を取得するといった内容です。
汎用ビューは便利ですが、複数のモデルの取得をする実装なんかには使うのが難しい(自分の力量不足かもしれません)ので、色々な方法の実装を身に付けて、選択肢を増やしておくことが必要だと感じました。
【Django】プルダウンメニュー選択の実装
Djangoの入力フォームにてプルダウンメニューでの選択表示を実装について書きます。
プルダウンメニューを実装する方法として2つの方法で実践しています。
1.models.pyでの実装
2.forms.pyでの実装
1.models.pyでの実装
プルダウンメニューでの選択表示をcategory_choiceと定義して、対象のタプル内にchoices=category_choiceを記述。
2.forms.pyでの実装
プルダウンメニューでの選択表示をgender_choiceと定義して、Fieldクラスで、forms.ChoiceFieldを記述し、タプル内にchoices=gender_choiceを記述。
1,2の両者ともあとはテンプレートファイル側で通常通りformを実装でOKとなります。
個人的にはruby on railsのactive_hashよりも手軽に実装できるような感じます。
【Django】datetimeと現在時間のデフォルト値設定
ToDoリストのようなアプリを作っておりますが、リストの登録の際、期限設定の入力を毎回手入力しないよう、期限の月のデフォルト値として現在の月を設定しようと考えました。
まずは現在の時間の取得ですが、Pythonの標準ライブラリである、datetimeモジュールをインポートし、現在の時刻を"date_string"として定義します。
また、時間、分、秒も取得が可能です。
次にデフォルト値の設定ですが、こちらは先ほど取得した"date_string"から今月の値を取得しています。
これで初期値として現在の時間を取得が可能となります。
初期状態でイメージは以下のようになります。