-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #68 from tsh11na/issue-62
管理画面のアップデート
- Loading branch information
Showing
13 changed files
with
333 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,103 @@ | ||
from django.contrib import admin | ||
from django.db.models import Sum | ||
|
||
from .models import ItemCategory, Tsuke | ||
from .models import ItemCategory, Tsuke, TsukeTotal | ||
|
||
|
||
class PaidFilter(admin.SimpleListFilter): | ||
"""清算済みフィルタ""" | ||
title = "清算" | ||
parameter_name = "is_paid" | ||
|
||
def lookups(self, request, model_admin): | ||
return ( | ||
("paid", "済"), | ||
("unpaid", "未"), | ||
) | ||
|
||
def queryset(self, request, queryset): | ||
if self.value() == "paid": | ||
return queryset.filter(is_paid=True) | ||
if self.value() == "unpaid": | ||
return queryset.filter(is_paid=False) | ||
|
||
|
||
class ItemCategoryAdmin(admin.ModelAdmin): | ||
list_display = ["category"] | ||
change_list_template = "admin/itemcategory_change_list.html" | ||
|
||
|
||
class TsukeAdmin(admin.ModelAdmin): | ||
list_display = ["purchase_date", "amount", "user", "note", "payment_date"] | ||
list_display = ["purchase_date", "amount", "user", "note", "is_paid", "payment_date"] | ||
readonly_fields = [field.name for field in Tsuke._meta.fields] | ||
list_filter = ["user", "category", PaidFilter] | ||
change_list_template = "admin/tsuke_change_list.html" # 一覧画面 | ||
change_form_template = "admin/tsuke_change_form.html" # 詳細画面 | ||
|
||
def has_add_permission(self, request, obj=None) -> bool: | ||
"""ツケは登録ページからしか追加できない""" | ||
return False | ||
|
||
def has_view_permission(self, request, obj=None) -> bool: | ||
if request.user.is_staff: | ||
return True # スタッフは閲覧可能 | ||
return False | ||
|
||
def has_delete_permission(self, request, obj=None) -> bool: | ||
if request.user.is_superuser: | ||
return True # スーパーユーザのみ削除可能 | ||
return False | ||
|
||
def changelist_view(self, request, extra_context=None): | ||
response = super().changelist_view(request, extra_context) | ||
|
||
# try: | ||
# qs = response.context_data["cl"].get_queryset(request) | ||
# except (AttributeError, KeyError): | ||
# return response | ||
|
||
# フィルタ条件を取得 | ||
filters = { | ||
param: request.GET.getlist(param) for param in request.GET | ||
if not param.startswith("_") | ||
} | ||
|
||
response.context_data['filters'] = filters | ||
return response | ||
|
||
|
||
class TsukeTotalAdmin(admin.ModelAdmin): | ||
list_display = ["user"] | ||
change_list_template = "admin/tsuketotal_change_list.html" | ||
|
||
def has_add_permission(self, *args, **kwargs): | ||
"""ツケの合計は変更できない""" | ||
return False | ||
|
||
def changelist_view(self, request, extra_context=None): | ||
response = super().changelist_view(request, extra_context) | ||
try: | ||
qs = response.context_data["cl"].queryset | ||
except (AttributeError, KeyError): | ||
return response | ||
metrics = { | ||
"total_amount": Sum("amount"), | ||
} | ||
|
||
# ユーザ一覧を取得 | ||
user_list = [tsuke.user for tsuke in qs] | ||
# ユーザごとの合計金額を取得 | ||
total_amount = { | ||
user: qs.filter(user=user, is_paid=False).aggregate(**metrics)["total_amount"] or 0 | ||
for user in user_list | ||
} | ||
|
||
response.context_data["summary"] = total_amount | ||
return response | ||
|
||
admin.site.site_header = "Tsukepp 管理画面" | ||
admin.site.index_title = "メニュー" | ||
|
||
admin.site.register(ItemCategory, ItemCategoryAdmin) | ||
admin.site.register(Tsuke, TsukeAdmin) | ||
admin.site.register(TsukeTotal, TsukeTotalAdmin) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Generated by Django 4.2.6 on 2024-02-10 02:23 | ||
|
||
from django.db import migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("tsuke", "0007_alter_tsuke_payment_date"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="TsukeTotal", | ||
fields=[], | ||
options={ | ||
"verbose_name": "ツケ合計", | ||
"verbose_name_plural": "ツケ合計", | ||
"proxy": True, | ||
"indexes": [], | ||
"constraints": [], | ||
}, | ||
bases=("tsuke.tsuke",), | ||
), | ||
] |
21 changes: 21 additions & 0 deletions
21
tsuke/migrations/0009_alter_tsuketotal_options_alter_tsuke_is_paid.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Generated by Django 4.2.6 on 2024-02-10 09:08 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("tsuke", "0008_tsuketotal"), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterModelOptions( | ||
name="tsuketotal", | ||
options={"verbose_name": "集計", "verbose_name_plural": "集計"}, | ||
), | ||
migrations.AlterField( | ||
model_name="tsuke", | ||
name="is_paid", | ||
field=models.BooleanField(default=False, verbose_name="清算"), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{% extends "admin/change_list.html" %} | ||
|
||
{% block content_title %} | ||
<h1>品目一覧</h1> | ||
{% endblock %} | ||
|
||
<!-- タイトル以外は変更しない --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{% extends "admin/change_form.html" %} | ||
|
||
{% block content_title %} | ||
<h1>ツケ詳細</h1> | ||
{% endblock %} | ||
|
||
<!-- タイトル以外は変更しない --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{% extends "admin/change_list.html" %} | ||
|
||
{% block content_title %} | ||
<h1> | ||
ツケ一覧 | ||
<!-- {% for x in cl.filter_specs %} | ||
{% endfor %} --> | ||
{% for filter in cl.filter_specs %} | ||
{% if filter.lookup_choices and filter.lookup_val %} | ||
| {{ filter.lookup_title }} = | ||
{% for choice in filter.lookup_choices %} | ||
{% if choice.0|stringformat:"s" == filter.lookup_val %} | ||
{{ choice.1 }} | ||
{% endif %} | ||
{% endfor %} | ||
{% endif %} | ||
{% endfor %} | ||
{% if "is_paid__exact" in filters %} | ||
{% if filters.is_paid__exact.0 == "0" %} | ||
| 未清算 | ||
{% elif filters.is_paid__exact.0 == "1" %} | ||
| 清算済 | ||
{% endif %} | ||
{% endif %} | ||
</h1> | ||
{% endblock %} | ||
|
||
<!-- タイトル以外は変更しない --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{% extends "admin/change_list.html" %} | ||
|
||
{% block content_title %} | ||
<h1>未清算のツケの合計額(ユーザごと)</h1> | ||
{% endblock %} | ||
|
||
{% block result_list %} | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>ユーザ</th> | ||
<th>未精算額合計</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for user, amount in summary.items %} | ||
<tr> | ||
<td><a href="{% url 'admin:tsuke_tsuke_changelist' %}?is_paid__exact=0&user__id__exact={{user.id}}">{{ user }}</a></td> | ||
<td>{{ amount }}</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
"""テスト用のアカウントやログイン状態を定義するモジュール""" | ||
|
||
from django.contrib.auth import get_user_model | ||
from django.test import TestCase | ||
from django.urls import reverse_lazy | ||
|
||
|
||
class LoggedInTestCase(TestCase): | ||
""" | ||
ログイン状態を定義するテストケース | ||
(「動かして学ぶ!Python Django開発入門」p.286より) | ||
""" | ||
def setUp(self): | ||
"""テストメソッド実行前の事前設定""" | ||
self.username = "testa" | ||
self.password = 'xyab2023' | ||
self.SUBMIT_TOKEN = "test_token" | ||
|
||
self.test_user = get_user_model().objects.create_user( | ||
username=self.username, | ||
password=self.password, | ||
) | ||
|
||
self.client.login( | ||
username=self.username, | ||
password=self.password | ||
) | ||
|
||
def set_pseudo_token(self): | ||
"""疑似submit tokenをセッションに格納する""" | ||
sess = self.client.session | ||
sess["submit_token"] = self.SUBMIT_TOKEN | ||
sess.save() | ||
|
||
|
||
class SuperuserLoggedInTestCase(LoggedInTestCase): | ||
"""管理サイトのログイン状態を定義するクラス""" | ||
def setUp(self): | ||
"""テストメソッド実行前の事前設定""" | ||
self.username = "admin" | ||
self.password = 'admin2023' | ||
self.SUBMIT_TOKEN = "test_token" | ||
|
||
self.test_user = get_user_model().objects.create_superuser( | ||
username=self.username, | ||
email="[email protected]", | ||
password=self.password | ||
) | ||
|
||
self.client.login( | ||
username=self.username, | ||
password=self.password | ||
) | ||
|
||
def set_pseudo_token(self): | ||
"""疑似submit tokenをセッションに格納する""" | ||
sess = self.client.session | ||
sess["submit_token"] = self.SUBMIT_TOKEN | ||
sess.save() | ||
|
||
|
||
class TestAccount(LoggedInTestCase): | ||
"""アカウント機能のテストクラス""" | ||
def test_login_ok(self): | ||
"""すでにログイン状態であることの確認""" | ||
response = self.client.get( | ||
'/accounts/login/' | ||
) | ||
self.assertRedirects(response, reverse_lazy('tsuke:index')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from django.urls import reverse_lazy | ||
|
||
from ..models import ItemCategory, Tsuke | ||
from .test_account import SuperuserLoggedInTestCase | ||
|
||
|
||
class TestAdminTsukeTotal(SuperuserLoggedInTestCase): | ||
"""管理サイトのツケ合計表示用のテストクラス""" | ||
|
||
@classmethod | ||
def setUpTestData(cls): | ||
cls.category1 = ItemCategory.objects.create(category="飲み物") | ||
cls.category2 = ItemCategory.objects.create(category="お菓子") | ||
|
||
def test_admin_tsuke_total(self): | ||
"""管理サイトのツケ合計が正しく表示されることを確認""" | ||
url = reverse_lazy("admin:tsuke_tsuketotal_changelist") | ||
response = self.client.get(url) | ||
self.assertEqual(response.status_code, 200) | ||
|
||
# 疑似データを登録 | ||
Tsuke.objects.create( | ||
amount=123, | ||
category=self.category1, | ||
note="お茶", | ||
is_paid=False, | ||
user=self.test_user, | ||
) | ||
Tsuke.objects.create( | ||
amount=456, | ||
category=self.category2, | ||
note="グミ", | ||
is_paid=False, | ||
user=self.test_user, | ||
) | ||
Tsuke.objects.create( | ||
amount=789, | ||
category=self.category1, | ||
note="コーヒー", | ||
is_paid=True, # 清算済 | ||
user=self.test_user, | ||
) | ||
|
||
# 未清算のツケのみの合計額が表示されることを確認 | ||
response = self.client.get(url) | ||
self.assertContains(response, "579") # 123 + 456 |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.