diff --git a/jdav_web/material/admin.py b/jdav_web/material/admin.py
index 68f9d69..803ec21 100644
--- a/jdav_web/material/admin.py
+++ b/jdav_web/material/admin.py
@@ -1,15 +1,15 @@
from django.contrib import admin
-from django.utils.translation import gettext_lazy as _
from django.contrib.admin import SimpleListFilter
-from django.db import models
-from django import forms
+from django.utils.translation import gettext_lazy as _
-from .models import MaterialPart, Ownership, MaterialCategory
-#from easy_select2 import apply_select2
+from .models import MaterialCategory
+from .models import MaterialPart
+from .models import Ownership
+# from easy_select2 import apply_select2
class MaterialCategoryAdmin(admin.ModelAdmin):
- fields = ['name']
+ fields = ["name"]
# Register your models here.
@@ -18,42 +18,50 @@ class OwnershipInline(admin.TabularInline):
This shows the ownership selection directly in the MaterialPart edit
view
"""
+
model = Ownership
extra = 0
- #formfield_overrides = {
+ # formfield_overrides = {
# models.ForeignKey: {'widget': apply_select2(forms.Select)}
- #}
+ # }
class NotTooOldFilter(SimpleListFilter):
- title = _('Age')
- parameter_name = 'age'
+ title = _("Age")
+ parameter_name = "age"
def lookups(self, request, model_admin):
return (
- ('too_old', _('Not too old')),
- ('not_too_old', _('Too old')),
+ ("too_old", _("Not too old")),
+ ("not_too_old", _("Too old")),
)
def queryset(self, request, queryset):
- if self.value() == 'too_old':
+ if self.value() == "too_old":
return queryset.filter(pk__in=[x.pk for x in queryset.all() if x.not_too_old()])
- if self.value() == 'not_too_old':
+ if self.value() == "not_too_old":
return queryset.filter(pk__in=[x.pk for x in queryset.all() if not x.not_too_old()])
class MaterialAdmin(admin.ModelAdmin):
"""Edit view of a MaterialPart"""
- list_display = ('name', 'description', 'quantity_real',
- 'ownership_overview', 'buy_date',
- 'lifetime', 'not_too_old', 'admin_thumbnail')
- search_fields = ('name', 'description')
+ list_display = (
+ "name",
+ "description",
+ "quantity_real",
+ "ownership_overview",
+ "buy_date",
+ "lifetime",
+ "not_too_old",
+ "admin_thumbnail",
+ )
+ search_fields = ("name", "description")
inlines = [OwnershipInline]
- list_filter = (NotTooOldFilter, 'material_cat', 'ownership__owner')
- #formfield_overrides = {
+ list_filter = (NotTooOldFilter, "material_cat", "ownership__owner")
+ # formfield_overrides = {
# models.ManyToManyField: {'widget': forms.CheckboxSelectMultiple}
- #}
+ # }
admin.site.register(MaterialCategory, MaterialCategoryAdmin)
diff --git a/jdav_web/material/apps.py b/jdav_web/material/apps.py
index c1ffb6e..f2d097f 100644
--- a/jdav_web/material/apps.py
+++ b/jdav_web/material/apps.py
@@ -3,5 +3,5 @@ from django.utils.translation import gettext_lazy as _
class MaterialConfig(AppConfig):
- name = 'material'
- verbose_name = _('material')
+ name = "material"
+ verbose_name = _("material")
diff --git a/jdav_web/material/materials.json b/jdav_web/material/materials.json
index da53968..2d91f68 100644
--- a/jdav_web/material/materials.json
+++ b/jdav_web/material/materials.json
@@ -39,4 +39,4 @@
"quantity": "2"
}
}
-]
\ No newline at end of file
+]
diff --git a/jdav_web/material/models.py b/jdav_web/material/models.py
index 3cac241..10baf6f 100644
--- a/jdav_web/material/models.py
+++ b/jdav_web/material/models.py
@@ -13,14 +13,15 @@ class MaterialCategory(models.Model):
"""
Describes one kind of material
"""
- name = models.CharField(max_length=40, verbose_name=_('Name'))
+
+ name = models.CharField(max_length=40, verbose_name=_("Name"))
def __str__(self):
return self.name
class Meta:
- verbose_name = _('Material category')
- verbose_name_plural = _('Material categories')
+ verbose_name = _("Material category")
+ verbose_name_plural = _("Material categories")
# Create your models here.
@@ -29,14 +30,16 @@ class MaterialPart(models.Model):
Represents one part of material, which is owned (and stored) by different
members of the association (Ownership)
"""
- name = models.CharField(_('name'), max_length=30)
- description = models.CharField(_('description'), default='', max_length=140)
- quantity = models.IntegerField(_('quantity'), default=0)
- buy_date = models.DateField(_('purchase date'), editable=True)
- lifetime = models.DecimalField(_('lifetime (years)'), decimal_places=0, max_digits=3)
- photo = models.ImageField(_('photo'), upload_to='images', blank=True)
- material_cat = models.ManyToManyField(MaterialCategory, default=None,
- verbose_name=_('Material category'))
+
+ name = models.CharField(_("name"), max_length=30)
+ description = models.CharField(_("description"), default="", max_length=140)
+ quantity = models.IntegerField(_("quantity"), default=0)
+ buy_date = models.DateField(_("purchase date"), editable=True)
+ lifetime = models.DecimalField(_("lifetime (years)"), decimal_places=0, max_digits=3)
+ photo = models.ImageField(_("photo"), upload_to="images", blank=True)
+ material_cat = models.ManyToManyField(
+ MaterialCategory, default=None, verbose_name=_("Material category")
+ )
def __str__(self):
"""String representation"""
@@ -44,53 +47,59 @@ class MaterialPart(models.Model):
def quantity_real(self):
real = sum([o.count for o in Ownership.objects.filter(material__id=self.pk)])
- return str(real) + '/' + str(self.quantity)
+ return str(real) + "/" + str(self.quantity)
- quantity_real.admin_order_field = 'quantity'
- quantity_real.short_description = _('Quantity')
+ quantity_real.admin_order_field = "quantity"
+ quantity_real.short_description = _("Quantity")
def admin_thumbnail(self):
if self.photo:
- return format_html(''.format(self.photo.url))
+ return format_html(
+ '
'.format(
+ self.photo.url
+ )
+ )
else:
- return format_html('kein Bild')
- admin_thumbnail.short_description = _('Thumbnail')
+ return format_html("kein Bild")
+
+ admin_thumbnail.short_description = _("Thumbnail")
def ownership_overview(self):
- summary = ''
+ summary = ""
for owner in self.ownership_set.all():
- summary += '
{}: {}
'.format(str(owner.owner), owner.count) + summary += "{}: {}
".format(str(owner.owner), owner.count) return format_html(summary) - ownership_overview.short_description = _('Owners') + + ownership_overview.short_description = _("Owners") def not_too_old(self): """Returns wether the part should be replaced cause of age""" - buy_time = timezone.make_aware(datetime.combine(self.buy_date, - datetime.min.time())) + buy_time = timezone.make_aware(datetime.combine(self.buy_date, datetime.min.time())) return yearsago(self.lifetime) < buy_time - not_too_old.admin_order_field = 'buy_date' + not_too_old.admin_order_field = "buy_date" not_too_old.boolean = True - not_too_old.short_description = _('Not too old?') + not_too_old.short_description = _("Not too old?") class Meta: - verbose_name = _('material part') - verbose_name_plural = _('material parts') + verbose_name = _("material part") + verbose_name_plural = _("material parts") class Ownership(models.Model): """Represents the connection between a MaterialPart and a Member""" + material = models.ForeignKey(MaterialPart, on_delete=models.CASCADE) - owner = models.ForeignKey('members.Member', verbose_name=_('owner'), on_delete=models.CASCADE) - count = models.IntegerField(_('count'), default=1) + owner = models.ForeignKey("members.Member", verbose_name=_("owner"), on_delete=models.CASCADE) + count = models.IntegerField(_("count"), default=1) def __str__(self): """String representation""" return str(self.owner) class Meta: - verbose_name = _('ownership') - verbose_name_plural = _('ownerships') + verbose_name = _("ownership") + verbose_name_plural = _("ownerships") def yearsago(years, from_date=None): diff --git a/jdav_web/material/tests.py b/jdav_web/material/tests.py index c736ce6..3511e12 100644 --- a/jdav_web/material/tests.py +++ b/jdav_web/material/tests.py @@ -1,11 +1,20 @@ -from django.test import TestCase, RequestFactory -from django.utils import timezone -from datetime import date, datetime +from datetime import date +from datetime import datetime from decimal import Decimal from unittest.mock import Mock -from material.models import MaterialCategory, MaterialPart, Ownership, yearsago -from material.admin import NotTooOldFilter, MaterialAdmin -from members.models import Member, MALE, FEMALE, DIVERSE + +from django.test import RequestFactory +from django.test import TestCase +from django.utils import timezone +from material.admin import MaterialAdmin +from material.admin import NotTooOldFilter +from material.models import MaterialCategory +from material.models import MaterialPart +from material.models import Ownership +from material.models import yearsago +from members.models import FEMALE +from members.models import MALE +from members.models import Member class MaterialCategoryTestCase(TestCase): @@ -19,8 +28,8 @@ class MaterialCategoryTestCase(TestCase): def test_verbose_names(self): """Test verbose names are set correctly""" meta = MaterialCategory._meta - self.assertTrue(hasattr(meta, 'verbose_name')) - self.assertTrue(hasattr(meta, 'verbose_name_plural')) + self.assertTrue(hasattr(meta, "verbose_name")) + self.assertTrue(hasattr(meta, "verbose_name_plural")) class MaterialPartTestCase(TestCase): @@ -31,7 +40,7 @@ class MaterialPartTestCase(TestCase): description="60m dynamic climbing rope", quantity=5, buy_date=date(2020, 1, 15), - lifetime=Decimal('8') + lifetime=Decimal("8"), ) self.material_part.material_cat.add(self.category) @@ -40,7 +49,7 @@ class MaterialPartTestCase(TestCase): lastname="Doe", birth_date=date(1990, 1, 1), email="john@example.com", - gender=MALE + gender=MALE, ) def test_str(self): @@ -54,27 +63,27 @@ class MaterialPartTestCase(TestCase): def test_quantity_real_with_ownership(self): """Test quantity_real with ownership records""" - Ownership.objects.create( - material=self.material_part, - owner=self.member, - count=3 - ) - Ownership.objects.create( - material=self.material_part, - owner=self.member, - count=1 - ) + Ownership.objects.create(material=self.material_part, owner=self.member, count=3) + Ownership.objects.create(material=self.material_part, owner=self.member, count=1) result = self.material_part.quantity_real() self.assertEqual(result, "4/5") def test_verbose_names(self): """Test field verbose names""" # Just test that verbose names exist, since they might be translated - field_names = ['name', 'description', 'quantity', 'buy_date', 'lifetime', 'photo', 'material_cat'] + field_names = [ + "name", + "description", + "quantity", + "buy_date", + "lifetime", + "photo", + "material_cat", + ] for field_name in field_names: field = self.material_part._meta.get_field(field_name) - self.assertTrue(hasattr(field, 'verbose_name')) + self.assertTrue(hasattr(field, "verbose_name")) self.assertIsNotNone(field.verbose_name) def test_admin_thumbnail_with_photo(self): @@ -104,7 +113,7 @@ class MaterialPartTestCase(TestCase): # Set a buy_date that makes the material old old_date = date(2000, 1, 1) self.material_part.buy_date = old_date - self.material_part.lifetime = Decimal('5') + self.material_part.lifetime = Decimal("5") result = self.material_part.not_too_old() self.assertFalse(result) @@ -117,7 +126,7 @@ class OwnershipTestCase(TestCase): description="Lightweight aluminum carabiners", quantity=10, buy_date=date(2021, 6, 1), - lifetime=Decimal('10') + lifetime=Decimal("10"), ) self.member = Member.objects.create( @@ -125,13 +134,11 @@ class OwnershipTestCase(TestCase): lastname="Smith", birth_date=date(1985, 3, 15), email="alice@example.com", - gender=FEMALE + gender=FEMALE, ) self.ownership = Ownership.objects.create( - material=self.material_part, - owner=self.member, - count=6 + material=self.material_part, owner=self.member, count=6 ) def test_ownership_creation(self): @@ -183,8 +190,11 @@ class NotTooOldFilterTestCase(TestCase): # Create test data self.member = Member.objects.create( - prename="Test", lastname="User", birth_date=date(1990, 1, 1), - email="test@example.com", gender=MALE + prename="Test", + lastname="User", + birth_date=date(1990, 1, 1), + email="test@example.com", + gender=MALE, ) # Create old material (should be too old) @@ -193,7 +203,7 @@ class NotTooOldFilterTestCase(TestCase): description="Old material", quantity=1, buy_date=date(2000, 1, 1), # Very old - lifetime=Decimal('5') + lifetime=Decimal("5"), ) # Create new material (should not be too old) @@ -202,21 +212,21 @@ class NotTooOldFilterTestCase(TestCase): description="New material", quantity=1, buy_date=date.today(), # Today - lifetime=Decimal('10') + lifetime=Decimal("10"), ) def test_not_too_old_filter_lookups(self): """Test NotTooOldFilter lookups method""" - request = self.factory.get('/') + request = self.factory.get("/") lookups = self.filter.lookups(request, None) self.assertEqual(len(lookups), 2) - self.assertEqual(lookups[0][0], 'too_old') - self.assertEqual(lookups[1][0], 'not_too_old') + self.assertEqual(lookups[0][0], "too_old") + self.assertEqual(lookups[1][0], "not_too_old") def test_not_too_old_filter_queryset_too_old(self): """Test NotTooOldFilter queryset method with 'too_old' value""" - request = self.factory.get('/?age=too_old') - self.filter.used_parameters = {'age': 'too_old'} + request = self.factory.get("/?age=too_old") + self.filter.used_parameters = {"age": "too_old"} queryset = MaterialPart.objects.all() filtered = self.filter.queryset(request, queryset) @@ -227,8 +237,8 @@ class NotTooOldFilterTestCase(TestCase): def test_not_too_old_filter_queryset_not_too_old(self): """Test NotTooOldFilter queryset method with 'not_too_old' value""" - request = self.factory.get('/?age=not_too_old') - self.filter.used_parameters = {'age': 'not_too_old'} + request = self.factory.get("/?age=not_too_old") + self.filter.used_parameters = {"age": "not_too_old"} queryset = MaterialPart.objects.all() filtered = self.filter.queryset(request, queryset)