From 1bebc74449c3e5a1dd494ef5fda0fb9e638df522 Mon Sep 17 00:00:00 2001 From: Johannes Schriewer Date: Wed, 16 Dec 2020 01:26:42 +0100 Subject: [PATCH] Model updates, add FormFactor and Tags --- inventory/admin/__init__.py | 6 ++- inventory/admin/form_factor.py | 12 +++++ inventory/admin/tag.py | 11 +++++ inventory/migrations/0001_initial.py | 74 +++++++++++++++++++++------- inventory/models/__init__.py | 4 +- inventory/models/box.py | 5 +- inventory/models/documentation.py | 1 + inventory/models/form_factor.py | 14 ++++++ inventory/models/item.py | 2 + inventory/models/layout.py | 1 + inventory/models/tag.py | 11 +++++ 11 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 inventory/admin/form_factor.py create mode 100644 inventory/admin/tag.py create mode 100644 inventory/models/form_factor.py create mode 100644 inventory/models/tag.py diff --git a/inventory/admin/__init__.py b/inventory/admin/__init__.py index c10c444..b98df51 100644 --- a/inventory/admin/__init__.py +++ b/inventory/admin/__init__.py @@ -1,5 +1,7 @@ +from .containers import WorkshopAdmin, AreaAdmin, BoxAdmin from .distributor import DistributorAdmin -from .manufacturer import ManufacturerAdmin from .layout import LayoutAdmin from .item import ItemAdmin -from .containers import WorkshopAdmin, AreaAdmin, BoxAdmin \ No newline at end of file +from .manufacturer import ManufacturerAdmin +from .form_factor import FormFactorAdmin +from .tag import TagAdmin \ No newline at end of file diff --git a/inventory/admin/form_factor.py b/inventory/admin/form_factor.py new file mode 100644 index 0000000..c3e7165 --- /dev/null +++ b/inventory/admin/form_factor.py @@ -0,0 +1,12 @@ +from django.contrib import admin + +from inventory.models import FormFactor + + +class FormFactorAdmin(admin.ModelAdmin): + readonly_fields = ['created_at', 'changed_at'] + search_fields = ['name', 'description'] + list_display = ['name', 'description'] + + +admin.site.register(FormFactor, FormFactorAdmin) diff --git a/inventory/admin/tag.py b/inventory/admin/tag.py new file mode 100644 index 0000000..d608e2a --- /dev/null +++ b/inventory/admin/tag.py @@ -0,0 +1,11 @@ +from django.contrib import admin + +from inventory.models import Tag + + +class TagAdmin(admin.ModelAdmin): + readonly_fields = ['created_at', 'changed_at'] + search_fields = ['name', 'description'] + + +admin.site.register(Tag, TagAdmin) diff --git a/inventory/migrations/0001_initial.py b/inventory/migrations/0001_initial.py index 2852525..4e2fbd5 100644 --- a/inventory/migrations/0001_initial.py +++ b/inventory/migrations/0001_initial.py @@ -1,7 +1,5 @@ -# Generated by Django 3.0.4 on 2020-08-03 21:20 +# Generated by Django 3.1.4 on 2020-12-16 00:13 -import django.contrib.postgres.fields -import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion @@ -29,8 +27,32 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True)), ('changed_at', models.DateTimeField(auto_now=True)), ('web_link', models.URLField(blank=True, null=True)), - ('search_link', models.URLField(blank=True, null=True, verbose_name='Use {} for search placeholder')), + ('search_link', models.URLField(blank=True, help_text='Use {} for search placeholder', null=True)), ('phone', models.CharField(blank=True, max_length=128, null=True)), + ('email', models.EmailField(blank=True, default=None, max_length=254, null=True)), + ('icon', models.ImageField(blank=True, null=True, upload_to='')), + ], + ), + migrations.CreateModel( + name='Documentation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('changed_at', models.DateTimeField(auto_now=True)), + ('file', models.FileField(upload_to='')), + ], + ), + migrations.CreateModel( + name='FormFactor', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, unique=True)), + ('description', models.CharField(max_length=4096)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('changed_at', models.DateTimeField(auto_now=True)), + ('icon', models.ImageField(blank=True, null=True, upload_to='')), + ('datasheet', models.FileField(blank=True, null=True, upload_to='')), ], ), migrations.CreateModel( @@ -41,7 +63,8 @@ class Migration(migrations.Migration): ('description', models.CharField(max_length=4096)), ('created_at', models.DateTimeField(auto_now_add=True)), ('changed_at', models.DateTimeField(auto_now=True)), - ('data', django.contrib.postgres.fields.jsonb.JSONField()), + ('data', models.JSONField()), + ('template_name', models.CharField(blank=True, max_length=255, null=True)), ], ), migrations.CreateModel( @@ -49,16 +72,27 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255, unique=True)), - ('description', models.CharField(max_length=4096)), + ('description', models.CharField(blank=True, max_length=4096)), ('created_at', models.DateTimeField(auto_now_add=True)), ('changed_at', models.DateTimeField(auto_now=True)), ('web_link', models.URLField(blank=True, null=True)), + ('icon', models.ImageField(blank=True, null=True, upload_to='')), + ], + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, unique=True)), + ('description', models.CharField(max_length=4096)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('changed_at', models.DateTimeField(auto_now=True)), ], ), migrations.CreateModel( name='Workshop', fields=[ - ('container_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.Container')), + ('container_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.container')), ('name', models.CharField(max_length=255, unique=True)), ('description', models.CharField(max_length=4096)), ('created_at', models.DateTimeField(auto_now_add=True)), @@ -71,18 +105,20 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('index', models.PositiveIntegerField(verbose_name='Index of compartment in layout')), - ('name', models.CharField(max_length=255, unique=True)), + ('name', models.TextField(max_length=255)), ('description', models.CharField(max_length=4096)), ('created_at', models.DateTimeField(auto_now_add=True)), ('changed_at', models.DateTimeField(auto_now=True)), - ('metadata', django.contrib.postgres.fields.jsonb.JSONField(verbose_name='Custom metadata, used by templates')), + ('metadata', models.JSONField(blank=True, null=True, verbose_name='Custom metadata, used by templates')), ('distributor_item_no', models.CharField(blank=True, max_length=255, null=True)), ('price', models.DecimalField(blank=True, decimal_places=3, max_digits=7, null=True)), ('last_ordered_on', models.DateField(blank=True, null=True)), - ('documentation', django.contrib.postgres.fields.ArrayField(base_field=models.FileField(upload_to=''), size=None)), - ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_related', to='inventory.Container')), - ('distributor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.Distributor')), - ('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.Manufacturer')), + ('container', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_related', to='inventory.container')), + ('distributor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.distributor')), + ('documentation', models.ManyToManyField(blank=True, related_name='items', to='inventory.Documentation')), + ('form_factor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.formfactor')), + ('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.manufacturer')), + ('tags', models.ManyToManyField(blank=True, to='inventory.Tag')), ], options={ 'abstract': False, @@ -91,34 +127,34 @@ class Migration(migrations.Migration): migrations.AddField( model_name='container', name='layout', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.Layout'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.layout'), ), migrations.CreateModel( name='Box', fields=[ - ('container_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.Container')), + ('container_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.container')), ('index', models.PositiveIntegerField(verbose_name='Index of compartment in layout')), ('name', models.CharField(max_length=255, unique=True)), ('description', models.CharField(max_length=4096)), ('created_at', models.DateTimeField(auto_now_add=True)), ('changed_at', models.DateTimeField(auto_now=True)), - ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='box_related', to='inventory.Container')), + ('container', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='box_related', to='inventory.container')), ], options={ - 'abstract': False, + 'verbose_name_plural': 'Boxes', }, bases=('inventory.container', models.Model), ), migrations.CreateModel( name='Area', fields=[ - ('container_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.Container')), + ('container_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.container')), ('index', models.PositiveIntegerField(verbose_name='Index of compartment in layout')), ('name', models.CharField(max_length=255, unique=True)), ('description', models.CharField(max_length=4096)), ('created_at', models.DateTimeField(auto_now_add=True)), ('changed_at', models.DateTimeField(auto_now=True)), - ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='area_related', to='inventory.Container')), + ('container', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='area_related', to='inventory.container')), ], options={ 'abstract': False, diff --git a/inventory/models/__init__.py b/inventory/models/__init__.py index 5d5e227..0712dd8 100644 --- a/inventory/models/__init__.py +++ b/inventory/models/__init__.py @@ -1,9 +1,11 @@ from .area import Area from .box import Box from .distributor import Distributor +from .documentation import Documentation +from .form_factor import FormFactor from .item import Item from .layout import Layout from .manufacturer import Manufacturer +from .tag import Tag from .workshop import Workshop from .container import Container, CanBeContained -from .documentation import Documentation \ No newline at end of file diff --git a/inventory/models/box.py b/inventory/models/box.py index 899c992..1985f59 100644 --- a/inventory/models/box.py +++ b/inventory/models/box.py @@ -15,7 +15,10 @@ class Box(CanBeContained, Container): @property def template_name(self): - template = 'inventory/box-' + slugify(self.layout.name) + '.html' + if self.layout.template_name: + template = 'inventory/box-' + self.layout.template_name + '.html' + else: + template = 'inventory/box-' + slugify(self.layout.name) + '.html' try: get_template(template) return template diff --git a/inventory/models/documentation.py b/inventory/models/documentation.py index e78dfbc..a0d03bf 100644 --- a/inventory/models/documentation.py +++ b/inventory/models/documentation.py @@ -2,6 +2,7 @@ from django.db import models class Documentation(models.Model): + name = models.CharField(max_length=255, unique=True) created_at = models.DateTimeField(auto_now_add=True) changed_at = models.DateTimeField(auto_now=True) diff --git a/inventory/models/form_factor.py b/inventory/models/form_factor.py new file mode 100644 index 0000000..351c8fe --- /dev/null +++ b/inventory/models/form_factor.py @@ -0,0 +1,14 @@ +from django.db import models + + +class FormFactor(models.Model): + name = models.CharField(max_length=255, unique=True) + description = models.CharField(max_length=4096) + created_at = models.DateTimeField(auto_now_add=True) + changed_at = models.DateTimeField(auto_now=True) + + icon = models.ImageField(null=True, blank=True) + datasheet = models.FileField(null=True, blank=True) + + def __str__(self): + return self.name diff --git a/inventory/models/item.py b/inventory/models/item.py index 088fe9b..ceaa103 100644 --- a/inventory/models/item.py +++ b/inventory/models/item.py @@ -11,6 +11,7 @@ class Item(CanBeContained): changed_at = models.DateTimeField(auto_now=True) metadata = models.JSONField('Custom metadata, used by templates', blank=True, null=True) + form_factor = models.ForeignKey('inventory.FormFactor', null=True, blank=True, on_delete=models.PROTECT) manufacturer = models.ForeignKey('inventory.Manufacturer', null=True, blank=True, on_delete=models.PROTECT) distributor = models.ForeignKey('inventory.Distributor', null=True, blank=True, on_delete=models.PROTECT) @@ -18,6 +19,7 @@ class Item(CanBeContained): price = models.DecimalField(decimal_places=3, max_digits=7, null=True, blank=True) last_ordered_on = models.DateField(null=True, blank=True) documentation = models.ManyToManyField('inventory.Documentation', related_name='items', blank=True) + tags = models.ManyToManyField('inventory.Tag', blank=True) def __str__(self): return self.name \ No newline at end of file diff --git a/inventory/models/layout.py b/inventory/models/layout.py index 3bfa99c..2410b65 100644 --- a/inventory/models/layout.py +++ b/inventory/models/layout.py @@ -7,6 +7,7 @@ class Layout(models.Model): created_at = models.DateTimeField(auto_now_add=True) changed_at = models.DateTimeField(auto_now=True) data = models.JSONField() + template_name = models.CharField(max_length=255, null=True, blank=True) def __str__(self): return self.name diff --git a/inventory/models/tag.py b/inventory/models/tag.py new file mode 100644 index 0000000..ac83091 --- /dev/null +++ b/inventory/models/tag.py @@ -0,0 +1,11 @@ +from django.db import models + + +class Tag(models.Model): + name = models.CharField(max_length=255, unique=True) + description = models.CharField(max_length=4096) + created_at = models.DateTimeField(auto_now_add=True) + changed_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name