Enhance Location: Better change form and list all items in this location

pull/123/head
JensDiemer 2022-09-30 20:49:26 +02:00
rodzic 3850f9b8a6
commit c1a690b2fa
9 zmienionych plików z 201 dodań i 19 usunięć

Wyświetl plik

@ -1,12 +1,14 @@
from django.conf import settings
from django.contrib import admin
from django.db.models import Count
from django.db.models.options import Options
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from import_export.admin import ImportExportMixin
from import_export.resources import ModelResource
from inventory.admin.base import BaseUserAdmin, LimitTreeDepthListFilter
from inventory.models import LocationModel
from inventory.models import ItemModel, LocationModel
from inventory.string_utils import ltruncatechars
@ -22,6 +24,16 @@ class LocationModelAdmin(ImportExportMixin, BaseUserAdmin):
def item_count(self, obj):
return obj.item_count
@admin.display(description=_('ItemModel.verbose_name_plural'))
def items(self, obj):
item_qs = ItemModel.objects.filter(location=obj)
opts: Options = ItemModel._meta
context = {
'items': item_qs,
'opts': opts,
}
return render_to_string('admin/location/items.html', context)
@admin.display(ordering='path_str', description=_('LocationModel.verbose_name'))
def location(self, obj):
text = ' '.join(obj.path)
@ -34,7 +46,33 @@ class LocationModelAdmin(ImportExportMixin, BaseUserAdmin):
return qs
list_display = ('location', 'create_dt', 'update_dt', 'item_count')
readonly_fields = ('item_count',)
fieldsets = (
(
_('Internals'),
{
'classes': ('collapse',),
'fields': (
('id', 'version'),
'user',
),
},
),
(_('Meta'), {'classes': ('collapse',), 'fields': ('create_dt', 'update_dt')}),
(
_('Basic'),
{
'fields': (
'name',
'description',
'tags',
'parent',
)
},
),
(_('Items in this Location'), {'fields': ('items',)}),
)
autocomplete_fields = ('parent',)
readonly_fields = ('id', 'create_dt', 'update_dt', 'user', 'item_count', 'items')
list_display_links = ('location',)
list_filter = (LimitTreeDepthListFilter,)
search_fields = ('name', 'description', 'tags__name')

Wyświetl plik

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-30 20:11+0200\n"
"POT-Creation-Date: 2022-09-30 20:48+0200\n"
"PO-Revision-Date: 2022-09-30 20:07+0200\n"
"Last-Translator: Jaume López\n"
"Language-Team: \n"
@ -54,9 +54,15 @@ msgstr "Rebuts"
msgid "Handed over"
msgstr "Donats"
msgid "ItemModel.verbose_name_plural"
msgstr "Elements"
msgid "LocationModel.verbose_name"
msgstr "Localització"
msgid "Items in this Location"
msgstr ""
msgid "BaseModel.id.verbose_name"
msgstr "ID"
@ -180,9 +186,6 @@ msgstr "Preu de cessió"
msgid "ItemModel.handed_over_price.help_text"
msgstr " "
msgid "ItemModel.verbose_name_plural"
msgstr "Elements"
msgid "ItemLinkModel.verbose_name"
msgstr "Vincle"

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-30 20:11+0200\n"
"PO-Revision-Date: 2022-09-30 20:10+0200\n"
"POT-Creation-Date: 2022-09-30 20:48+0200\n"
"PO-Revision-Date: 2022-09-30 20:48+0200\n"
"Last-Translator: Jens Diemer\n"
"Language-Team: \n"
"Language: de\n"
@ -54,9 +54,15 @@ msgstr "Erhalt"
msgid "Handed over"
msgstr "Abgabe"
msgid "ItemModel.verbose_name_plural"
msgstr "Gegenstände"
msgid "LocationModel.verbose_name"
msgstr "Standort"
msgid "Items in this Location"
msgstr "Gegenstände an diesem Ort:"
msgid "BaseModel.id.verbose_name"
msgstr "ID"
@ -179,9 +185,6 @@ msgstr "Abgabepreis"
msgid "ItemModel.handed_over_price.help_text"
msgstr "Wurde bei der Abgabe Geld eingenommen?"
msgid "ItemModel.verbose_name_plural"
msgstr "Gegenstände"
msgid "ItemLinkModel.verbose_name"
msgstr "Link"

Wyświetl plik

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-30 20:11+0200\n"
"POT-Creation-Date: 2022-09-30 20:48+0200\n"
"PO-Revision-Date: 2021-10-09 19:36+0200\n"
"Last-Translator: Jens Diemer\n"
"Language-Team: \n"
@ -54,9 +54,15 @@ msgstr ""
msgid "Handed over"
msgstr ""
msgid "ItemModel.verbose_name_plural"
msgstr "Items"
msgid "LocationModel.verbose_name"
msgstr "Location"
msgid "Items in this Location"
msgstr ""
msgid "BaseModel.id.verbose_name"
msgstr "ID"
@ -179,9 +185,6 @@ msgstr "Handed over price"
msgid "ItemModel.handed_over_price.help_text"
msgstr " "
msgid "ItemModel.verbose_name_plural"
msgstr "Items"
msgid "ItemLinkModel.verbose_name"
msgstr "Link"

Wyświetl plik

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-30 20:11+0200\n"
"POT-Creation-Date: 2022-09-30 20:48+0200\n"
"PO-Revision-Date: 2021-10-09 19:36+0200\n"
"Last-Translator: Jaume López\n"
"Language-Team: \n"
@ -54,9 +54,15 @@ msgstr "Recibidos"
msgid "Handed over"
msgstr "Cedidos"
msgid "ItemModel.verbose_name_plural"
msgstr "Elementos"
msgid "LocationModel.verbose_name"
msgstr "Localización"
msgid "Items in this Location"
msgstr ""
msgid "BaseModel.id.verbose_name"
msgstr "ID"
@ -180,9 +186,6 @@ msgstr "Precio de cesión"
msgid "ItemModel.handed_over_price.help_text"
msgstr " "
msgid "ItemModel.verbose_name_plural"
msgstr "Elementos"
msgid "ItemLinkModel.verbose_name"
msgstr "Vínculo"

Wyświetl plik

@ -0,0 +1,18 @@
{% load i18n admin_urls %}
<table>
<thead>
<tr>
<th>{% trans "No." %}</th>
<th>{% trans "ItemModel.verbose_name_plural" %}</th>
</tr>
</thead>
<tbody>
{% for obj in items %}
<tr>
<td>{{ forloop.counter }}</td>
<td><a href="{% url opts|admin_urlname:'change' obj.pk %}">{{ obj }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>

Wyświetl plik

@ -0,0 +1,37 @@
from unittest import mock
from bx_django_utils.test_utils.html_assertion import (
HtmlAssertionMixin,
assert_html_response_snapshot,
)
from django.template.defaulttags import CsrfTokenNode, NowNode
from django.test import TestCase, override_settings
from inventory import __version__
from inventory_project.tests.fixtures import get_normal_user
@override_settings(SECURE_SSL_REDIRECT=False)
class AdminTestCase(HtmlAssertionMixin, TestCase):
@classmethod
def setUpTestData(cls):
cls.normaluser = get_normal_user()
def test_empty_change_list(self):
self.client.force_login(self.normaluser)
with mock.patch.object(NowNode, 'render', return_value='MockedNowNode'), mock.patch.object(
CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'
):
response = self.client.get(
path='/admin/inventory/locationmodel/',
)
assert response.status_code == 200
self.assert_html_parts(
response,
parts=(
f'<title>Select Location to change | PyInventory v{__version__}</title>',
'<a href="/admin/inventory/locationmodel/add/" class="addlink">Add Location</a>',
'<p class="paginator">0 Locations</p>',
),
)
assert_html_response_snapshot(response=response, validate=False)

Wyświetl plik

@ -0,0 +1,77 @@
<div class="" id="content">
<h1>
Select Location to change
</h1>
<div id="content-main">
<ul class="object-tools">
<li>
<a class="import_link" href="/admin/inventory/locationmodel/import/">
Import
</a>
</li>
<li>
<a class="export_link" href="/admin/inventory/locationmodel/export/?">
Export
</a>
</li>
<li>
<a class="addlink" href="/admin/inventory/locationmodel/add/">
Add Location
</a>
</li>
</ul>
<div class="module filtered" id="changelist">
<div class="changelist-form-container">
<div id="toolbar">
<form id="changelist-search" method="get">
<div>
<!-- DIV needed for valid HTML -->
<label for="searchbar">
<img alt="Search" src="/static/admin/img/search.svg"/>
</label>
<input autofocus="" id="searchbar" name="q" size="40" type="text" value=""/>
<input type="submit" value="Search"/>
</div>
</form>
</div>
<form id="changelist-form" method="post" novalidate="">
MockedCsrfTokenNode
<p class="paginator">
0 Locations
</p>
</form>
</div>
<div id="changelist-filter">
<h2>
Filter
</h2>
<h3>
By Limit tree depth
</h3>
<ul>
<li class="selected">
<a href="?" title="All">
All
</a>
</li>
<li>
<a href="?level=1" title="Only root">
Only root
</a>
</li>
<li>
<a href="?level=2" title="Root + first sub">
Root + first sub
</a>
</li>
<li>
<a href="?level=3" title="Root + first + second sub">
Root + first + second sub
</a>
</li>
</ul>
</div>
</div>
</div>
<br class="clear"/>
</div>