【Django(日報アプリ開発)】日報を公開・非公開にする ListViewのQuerySetを動的に変更する

Django

(最終更新月:2021年9月)

前回の記事では、カスタムユーザーにおける自動テストプログラムを作成しました

今まで数記事に渡ってユーザー関連の記事となりましたが、当記事以降、アプリに必要な機能を順番に追加していきます

当記事では、日報を公開、非公開とする機能を追加し、

  • ログインユーザー別に動的なリストビューを作成する

方法について解説をしていきます

いくつものファイルに渡り変更を加えていきます

次章にて流れをしっかりと把握してからそれぞれのファイルでの変更点をみていきます

関連書籍

今回行うこと

当記事を通じて、日報に公開、非公開、という機能を追加します

そのうえで、リストビューで表示する日報は、

  • 自身の作成したすべての日報(公開、非公開は問わない)
  • 他人の作成した公開されている日報

の2種類となります

機能を実装するためには、下記の流れでそれぞれ変更を加えていく必要あります

  1. (models.py) publicフィールドの追加
  2. (forms.py) チェックボックスのため、Bootstrapの別クラス「form-check-input」を追加
  3. (views.py) 正しく表示するためのQuerySetを返す
  4. (views.py) QuerySetを新しい順に並びかえる
  5. (nippo-list.html) HTMLテンプレートで、作成者情報、作成日時を追加で表示
  6. (test.py) 自動テストの追加

順を追って進めていきましょう!

models.py

class NippoModel(models.Model):
    ...
    public = models.BooleanField(default=False, verbose_name="公開する")
    ...

NippoModelクラスに「public」という新たなフィールドを追加します

デフォルトは「False」となり、公開するときは自身で「True」へ変更します

マイグレーションを忘れずに、次へ進みましょう

forms.py

__init__関数内で、フィールドのforLoopを変更しました

class NippoModelForm(forms.ModelForm):

    class Meta:
        model = NippoModel
        exclude = ["user"]

    def __init__(self, *args, **kwargs):
        for key, field in self.base_fields.items():
            if key != "public":
                field.widget.attrs["class"] = "form-control"
            else:
                field.widget.attrs["class"] = "form-check-input"
        super().__init__(*args, **kwargs)

今までの記述ですと、すべてのフォームに「form-control」クラスが適用されてしまうため、うまく表示されません

「public」フィールドには「form-check-input」というクラスを設定しましょう

views.py

get_queryset関数で、ログインユーザーごとの「object_list」を返すよう定義します

class NippoListView(ListView):
    template_name = "nippo/nippo-list.html"
    model = NippoModel

    def get_queryset(self):
        qs = NippoModel.objects.all()
        if self.request.user.is_authenticated:
            qs = qs.filter(Q(public=True)|Q(user=self.request.user))
        else:
            qs = qs.filter(public=True)

        qs = qs.order_by("-timestamp")
        return qs

ログインユーザーの場合は、自分の日報、もしくは他人の公開済みの日報を渡します

ログインしていない場合は、公開済みの日報のみとなります

(Qオブジェクトについては、こちらをご覧ください)

また、新しいものから表示されるよう「order_by」メソッドでの記述も追加しています

ここで行っていることはテンプレート上で記述することも可能ですし、またmodels.pyでQuerySetクラスをいじることでも反映できます

のちのち必要なときに解説いたします

nippo-list.html

forLoop内のみ変更、抜粋しています

{% for obj in object_list %}
    <div class="card my-3 mx-auto" style="max-width:700px;">
        <div class="card-header">
            {{ obj.timestamp|date:"Y年n年j日" }}
        </div>
        <div class="card-body">
            <h5 class="card-title">
            {% if obj.user == request.user %}
                <a href={% url 'nippo-update' obj.pk %}>
                    {{ obj.title}}<span style="font-size:10px;">(編集)</span>
            {% else %}
                <a href={% url 'nippo-detail' obj.pk %}>
                    {{ obj.title}}
            {% endif %}
                </a>
            </h5>
            <p class="card-text">
                {{ obj.content }}
            </p>
        </div>
        <div class="card-footer">
        by 
        {% if obj.user == request.user %}
            <span class="badge bg-primary">あなた</span>
        {% else %}
            <span class="badge bg-secondary">{{ obj.user }}</span>
        {% endif %}                 
        </div>
    </div>
{% endfor %}

ヘッダーやフッターを追加しました

DateField「timestamp」には、テンプレートフィルター「date」を使うことで年月等を任意に表示することができます(別記事で紹介予定です)

test.py

今まで作成した機能で、ログインしている場合としていない場合でリストビューの表示がかわるはず

渡される「object_list」の数によりきちんと動作しているかを判断するテスト関数になります

def test_listview_with_anonymous(self):
    url = reverse("nippo-list")
    response = self.client.get(url)
    object_list = response.context_data["object_list"]
    self.assertEqual(len(object_list), 0)

def test_listview_with_own_user(self):
    url = reverse("nippo-list")
    self.client.login(email=self.email, password=self.password)
    response = self.client.get(url)
    object_list = response.context_data["object_list"]
    self.assertEqual(len(object_list), 1)

おわりに

リストビューにアクセスしてみるといかがでしょうか?

一つ補足として、いろいろなユーザーでアクセスをするときにGoogle Chromeをお使いの方であれば、「シークレットウィンドウ」を使うと便利です

Chromeブラウザで右上の○が3つ並んでる箇所をクリックすると、新しいシークレットウィンドウを出すことができます

現ブラウザのログイン状況は共有されません

「知らなかった!」という方は是非ご活用ください!

当記事の結果としては、私の画面ではこんなふうになりました

ここで新たな機能の必要性がでてきました

作者を特定するという点はよいのですが、メールアドレスが公開されるというのはいかがでしょうか?

次回の記事では、ログインするための「email」「password」以外のアカウント情報に関するモデルクラスを作成します

OneToOneFieldを使い、ユーザークラスと1対1で紐付けられたクラスを作成していきます

当ブログは、「プログラミング初心者が一からWebアプリを作り、ネットで公開するまで」を解説しているサイトです。

日報アプリを一から開発し、ウェブに公開するまではこちらにまとめています

また、公開したウェブアプリはこちら(https://nippo.itc-app.site)でご覧いただけます(公開後もアップデート中)

 

その他、各分野別に

  1. Pythonについて
  2. HTML・CSSについて
  3. Djangoフレームワークについて
  4. Webサーバーについて
  5. 実際に公開をする方法

を記載したページも用意しています

 

ご自身の目的に合わせて、お好きな箇所からご覧ください

404 NOT FOUND | ITCブログ
今の自分にチャレンジする
タイトルとURLをコピーしました