make dataset parsing more robust
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
f2db5d9dad
commit
8cf0897ec5
13 changed files with 337 additions and 36 deletions
|
|
@ -1,6 +1,6 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from toolshed.models import InventoryItem, Property, Tag, ItemProperty, ItemTag
|
||||
from toolshed.models import InventoryItem, Property, Tag, Category
|
||||
|
||||
|
||||
class InventoryItemAdmin(admin.ModelAdmin):
|
||||
|
|
@ -12,16 +12,24 @@ admin.site.register(InventoryItem, InventoryItemAdmin)
|
|||
|
||||
|
||||
class PropertyAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
search_fields = ('name',)
|
||||
list_display = ('name', 'description', 'category', 'unit_symbol', 'base2_prefix', 'dimensions', 'origin')
|
||||
search_fields = ('name', 'description', 'category', 'unit_symbol', 'base2_prefix', 'dimensions', 'origin')
|
||||
|
||||
|
||||
admin.site.register(Property, PropertyAdmin)
|
||||
|
||||
|
||||
class TagAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
search_fields = ('name',)
|
||||
list_display = ('name', 'description', 'category', 'origin')
|
||||
search_fields = ('name', 'description', 'category', 'origin')
|
||||
|
||||
|
||||
admin.site.register(Tag, TagAdmin)
|
||||
|
||||
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'description', 'parent', 'origin')
|
||||
search_fields = ('name', 'description', 'parent', 'origin')
|
||||
|
||||
|
||||
admin.site.register(Category, CategoryAdmin)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
# Generated by Django 4.2.2 on 2024-03-14 16:54
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('toolshed', '0005_alter_inventoryitem_availability_policy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='tag',
|
||||
options={'verbose_name_plural': 'tags'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='category',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='category',
|
||||
name='parent',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='toolshed.category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitem',
|
||||
name='category',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='inventory_items', to='toolshed.category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='property',
|
||||
name='category',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='properties', to='toolshed.category'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='tag',
|
||||
name='category',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='toolshed.category'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='category',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', False)), fields=('name', 'parent'), name='category_unique_name_parent'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='category',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('name',), name='category_unique_name_no_parent'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='property',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('category__isnull', False)), fields=('name', 'category'), name='property_unique_name_category'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='property',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('category__isnull', True)), fields=('name',), name='property_unique_name_no_category'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='tag',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('category__isnull', False)), fields=('name', 'category'), name='tag_unique_name_category'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='tag',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('category__isnull', True)), fields=('name',), name='tag_unique_name_no_category'),
|
||||
),
|
||||
]
|
||||
|
|
@ -8,13 +8,19 @@ from files.models import File
|
|||
|
||||
|
||||
class Category(SoftDeleteModel):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(null=True, blank=True)
|
||||
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
|
||||
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='children')
|
||||
origin = models.CharField(max_length=255, null=False, blank=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'categories'
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['name', 'parent'], condition=models.Q(parent__isnull=False),
|
||||
name='category_unique_name_parent'),
|
||||
models.UniqueConstraint(fields=['name'], condition=models.Q(parent__isnull=True),
|
||||
name='category_unique_name_no_parent')
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
parent = str(self.parent) + "/" if self.parent else ""
|
||||
|
|
@ -24,7 +30,7 @@ class Category(SoftDeleteModel):
|
|||
class Property(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(null=True, blank=True)
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True, related_name='properties')
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, related_name='properties')
|
||||
unit_symbol = models.CharField(max_length=16, null=True, blank=True)
|
||||
unit_name = models.CharField(max_length=255, null=True, blank=True)
|
||||
unit_name_plural = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
|
@ -34,6 +40,12 @@ class Property(models.Model):
|
|||
|
||||
class Meta:
|
||||
verbose_name_plural = 'properties'
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['name', 'category'], condition=models.Q(category__isnull=False),
|
||||
name='property_unique_name_category'),
|
||||
models.UniqueConstraint(fields=['name'], condition=models.Q(category__isnull=True),
|
||||
name='property_unique_name_no_category')
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
@ -42,9 +54,18 @@ class Property(models.Model):
|
|||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(null=True, blank=True)
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True, related_name='tags')
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, related_name='tags')
|
||||
origin = models.CharField(max_length=255, null=False, blank=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'tags'
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['name', 'category'], condition=models.Q(category__isnull=False),
|
||||
name='tag_unique_name_category'),
|
||||
models.UniqueConstraint(fields=['name'], condition=models.Q(category__isnull=True),
|
||||
name='tag_unique_name_no_category')
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
|
@ -61,8 +82,7 @@ class InventoryItem(SoftDeleteModel):
|
|||
published = models.BooleanField(default=False)
|
||||
name = models.CharField(max_length=255, null=True, blank=True)
|
||||
description = models.TextField(null=True, blank=True)
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True,
|
||||
related_name='inventory_items')
|
||||
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, related_name='inventory_items')
|
||||
availability_policy = models.CharField(max_length=20, choices=AVAILABILITY_POLICY_CHOICES, default='private')
|
||||
owned_quantity = models.IntegerField(default=1, validators=[MinValueValidator(0)])
|
||||
owner = models.ForeignKey(ToolshedUser, on_delete=models.CASCADE, related_name='inventory_items')
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ class CategoryTestMixin:
|
|||
self.f['cat3'] = Category.objects.create(name='cat3', origin='test')
|
||||
self.f['subcat1'] = Category.objects.create(name='subcat1', parent=self.f['cat1'], origin='test')
|
||||
self.f['subcat2'] = Category.objects.create(name='subcat2', parent=self.f['cat1'], origin='test')
|
||||
self.f['subcat3'] = Category.objects.create(name='subcat3', parent=self.f['subcat1'], origin='test')
|
||||
self.f['subcat11'] = Category.objects.create(name='subcat1', parent=self.f['subcat1'], origin='test')
|
||||
self.f['subcat12'] = Category.objects.create(name='subcat2', parent=self.f['subcat1'], origin='test')
|
||||
|
||||
|
||||
class TagTestMixin:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ class CombinedApiTestCase(UserTestMixin, CategoryTestMixin, TagTestMixin, Proper
|
|||
self.assertEqual(response.json()['availability_policies'], [['sell', 'Sell'], ['rent', 'Rent'], ['lend', 'Lend'],
|
||||
['share', 'Share'], ['private', 'Private']])
|
||||
self.assertEqual(response.json()['categories'],
|
||||
['cat1', 'cat2', 'cat3', 'cat1/subcat1', 'cat1/subcat2', 'cat1/subcat1/subcat3'])
|
||||
['cat1', 'cat2', 'cat3', 'cat1/subcat1', 'cat1/subcat2', 'cat1/subcat1/subcat1',
|
||||
'cat1/subcat1/subcat2'])
|
||||
self.assertEqual(response.json()['tags'], ['tag1', 'tag2', 'tag3'])
|
||||
self.assertEqual([p['name'] for p in response.json()['properties']], ['prop1', 'prop2', 'prop3'])
|
||||
self.assertEqual(response.json()['domains'], ['example.com'])
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ class CategoryTestCase(CategoryTestMixin, UserTestMixin, ToolshedTestCase):
|
|||
self.assertEqual(self.f['cat1'].children.last(), self.f['subcat2'])
|
||||
self.assertEqual(self.f['subcat1'].parent, self.f['cat1'])
|
||||
self.assertEqual(self.f['subcat2'].parent, self.f['cat1'])
|
||||
self.assertEqual(self.f['subcat1'].children.count(), 1)
|
||||
self.assertEqual(self.f['subcat1'].children.count(), 2)
|
||||
self.assertEqual(str(self.f['subcat1']), 'cat1/subcat1')
|
||||
self.assertEqual(str(self.f['subcat2']), 'cat1/subcat2')
|
||||
self.assertEqual(str(self.f['subcat3']), 'cat1/subcat1/subcat3')
|
||||
self.assertEqual(str(self.f['subcat11']), 'cat1/subcat1/subcat1')
|
||||
self.assertEqual(str(self.f['subcat12']), 'cat1/subcat1/subcat2')
|
||||
|
||||
|
||||
class CategoryApiTestCase(CategoryTestMixin, UserTestMixin, ToolshedTestCase):
|
||||
|
|
@ -33,10 +34,12 @@ class CategoryApiTestCase(CategoryTestMixin, UserTestMixin, ToolshedTestCase):
|
|||
def test_get_categories(self):
|
||||
reply = client.get('/api/categories/', self.f['local_user1'])
|
||||
self.assertEqual(reply.status_code, 200)
|
||||
self.assertEqual(len(reply.json()), 6)
|
||||
self.assertEqual(len(reply.json()), 7)
|
||||
self.assertEqual(reply.json()[0], 'cat1')
|
||||
self.assertEqual(reply.json()[1], 'cat2')
|
||||
self.assertEqual(reply.json()[2], 'cat3')
|
||||
self.assertEqual(reply.json()[3], 'cat1/subcat1')
|
||||
self.assertEqual(reply.json()[4], 'cat1/subcat2')
|
||||
self.assertEqual(reply.json()[5], 'cat1/subcat1/subcat3')
|
||||
self.assertEqual(reply.json()[5], 'cat1/subcat1/subcat1')
|
||||
self.assertEqual(reply.json()[6], 'cat1/subcat1/subcat2')
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue