From ac318ca86402d483b0fb3f894269131814631580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 13 Nov 2021 21:05:52 +0100 Subject: [PATCH] Do some random coding for Distribotr numbers and Component parameters. This is probably not the most ideal solution. Will change this later --- shimatta_kenkyusho/parts/forms.py | 51 ++++++-- .../migrations/0004_auto_20211113_1508.py | 30 +++++ .../migrations/0005_auto_20211113_1912.py | 22 ++++ shimatta_kenkyusho/parts/models.py | 31 +++-- shimatta_kenkyusho/parts/views.py | 77 ++++++++++- .../templates/parts/components-detail.html | 123 +++++++++++++----- 6 files changed, 277 insertions(+), 57 deletions(-) create mode 100644 shimatta_kenkyusho/parts/migrations/0004_auto_20211113_1508.py create mode 100644 shimatta_kenkyusho/parts/migrations/0005_auto_20211113_1912.py diff --git a/shimatta_kenkyusho/parts/forms.py b/shimatta_kenkyusho/parts/forms.py index 59ec547..01cded1 100644 --- a/shimatta_kenkyusho/parts/forms.py +++ b/shimatta_kenkyusho/parts/forms.py @@ -183,9 +183,25 @@ class EditComponentForm(forms.Form): raise ValidationError('Invalid Package') + def _save_new(self): + self.instance = parts_models.Component.objects.create( + name=self.cleaned_data['name'], + datasheet_link=self.cleaned_data['datasheet_link'], + description=self.cleaned_data['description'], + package=self.cleaned_data['package_object'], + component_type=self.cleaned_data['component_type_object'], + pref_distri=self.cleaned_data['pref_distri_object'], + manufacturer=self.cleaned_data['manufacturer_object'] + ) + + if bool(self.cleaned_data['image']): + self.instance.image = self.cleaned_data['image'] + self.instance.save() + def save(self): if self.instance is None: - self.instance = parts_models.Component.objects.create() + self._save_new() + return self.instance.name = self.cleaned_data['name'] self.instance.datasheet_link = self.cleaned_data['datasheet_link'] @@ -203,8 +219,8 @@ class EditComponentForm(forms.Form): self.instance.save() class EditComponentParameterForm(forms.Form): - parameter_type = forms.CharField() # This must come first. Do not change the order of these elements! - value = forms.CharField() + parameter_type = forms.CharField(initial='') # This must come first. Do not change the order of these elements! + value = forms.CharField(initial='') def __init__(self, *args, **kwargs): @@ -215,12 +231,12 @@ class EditComponentParameterForm(forms.Form): self.parameter_type_object = type_instance kwargs['initial']['parameter_type'] = init_values['parameter_type'].parameter_name if isinstance(init_values['value'], int) or isinstance(init_values['value'], float): - if type_instance.engineering_unit: + if type_instance.parameter_type == 'E': (num, prefix) = EngineeringNumberConverter.number_to_engineering(init_values['value'], False) - kwargs['initial']['value'] = f'{num} {prefix}' - elif type_instance.it_unit: + kwargs['initial']['value'] = f'{num}{prefix}' + elif type_instance.parameter_type == 'I': (num, prefix) = EngineeringNumberConverter.number_to_engineering(init_values['value'], True) - kwargs['initial']['value'] = f'{num} {prefix}' + kwargs['initial']['value'] = f'{num}{prefix}' super().__init__(*args, **kwargs) @@ -245,12 +261,12 @@ class EditComponentParameterForm(forms.Form): processed_value = None - if parameter_type.it_unit or parameter_type.engineering_unit: + if parameter_type.parameter_type == 'E' or parameter_type.parameter_type == 'I': try: processed_value = EngineeringNumberConverter.engineering_to_number(value_data) except: raise ValidationError(f'Cannot not convert Value "{value_data}" to a number') - elif parameter_type.freetext_parameter: + elif parameter_type.parameter_type == 'F': processed_value = value_data else: try: @@ -260,4 +276,19 @@ class EditComponentParameterForm(forms.Form): self.cleaned_data['processed_value'] = processed_value - return value_data \ No newline at end of file + return value_data + + +class DistributorNumberForm(forms.ModelForm): + class Meta: + model = parts_models.DistributorNum + fields = ['distributor', 'distributor_part_number'] + +class DistributorNumberFormSet(forms.BaseModelFormSet): + def save(self, component, commit=True): + instances = super().save(commit=False) + for instance in instances: + instance.component = component + if commit: + instance.save() + return instances \ No newline at end of file diff --git a/shimatta_kenkyusho/parts/migrations/0004_auto_20211113_1508.py b/shimatta_kenkyusho/parts/migrations/0004_auto_20211113_1508.py new file mode 100644 index 0000000..1ff8351 --- /dev/null +++ b/shimatta_kenkyusho/parts/migrations/0004_auto_20211113_1508.py @@ -0,0 +1,30 @@ +# Generated by Django 3.2 on 2021-11-13 15:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('parts', '0003_alter_componentparametertype_unit'), + ] + + operations = [ + migrations.RemoveField( + model_name='componentparametertype', + name='engineering_unit', + ), + migrations.RemoveField( + model_name='componentparametertype', + name='freetext_parameter', + ), + migrations.RemoveField( + model_name='componentparametertype', + name='it_unit', + ), + migrations.AddField( + model_name='componentparametertype', + name='parameter_type', + field=models.CharField(choices=[('F', 'Free Text'), ('N', 'Standard float number'), ('E', 'Engineering / SI Unit'), ('I', 'IT Type')], default='N', max_length=1), + ), + ] diff --git a/shimatta_kenkyusho/parts/migrations/0005_auto_20211113_1912.py b/shimatta_kenkyusho/parts/migrations/0005_auto_20211113_1912.py new file mode 100644 index 0000000..fa925f4 --- /dev/null +++ b/shimatta_kenkyusho/parts/migrations/0005_auto_20211113_1912.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2 on 2021-11-13 19:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('parts', '0004_auto_20211113_1508'), + ] + + operations = [ + migrations.AlterModelOptions( + name='distributornum', + options={'ordering': ['distributor__name']}, + ), + migrations.AlterField( + model_name='componentparameter', + name='value', + field=models.FloatField(default=0), + ), + ] diff --git a/shimatta_kenkyusho/parts/models.py b/shimatta_kenkyusho/parts/models.py index 89a75e6..ad5db2e 100644 --- a/shimatta_kenkyusho/parts/models.py +++ b/shimatta_kenkyusho/parts/models.py @@ -17,19 +17,23 @@ class ComponentParameterType(models.Model): class Meta: ordering = ['parameter_name'] + TYPE_CHOICES = ( + ('F', 'Free Text'), + ('N', 'Standard float number'), + ('E', 'Engineering / SI Unit'), + ('I', 'IT Type'), + ) + parameter_name = models.CharField(max_length=50, unique=True) parameter_description = models.TextField(null=True, blank=True) unit = models.CharField(max_length=10, null=True, blank=True) - freetext_parameter = models.BooleanField() - engineering_unit = models.BooleanField() - it_unit = models.BooleanField() + parameter_type = models.CharField(max_length=1, choices=TYPE_CHOICES, default='N') def __str__(self): - unit = self.unit - if unit: - return self.parameter_name + ' in ' + unit - else: - return self.parameter_name + unit = '' + if self.unit: + unit = ' in ' + self.unit + return self.parameter_name + unit + ' | ' + self.get_parameter_type_display() class ComponentType(models.Model): class Meta: @@ -202,11 +206,16 @@ class ComponentParameter(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True) component = models.ForeignKey(Component, on_delete=models.CASCADE) # A target component is required! parameter_type = models.ForeignKey(ComponentParameterType, on_delete=models.CASCADE) - value = models.FloatField() + value = models.FloatField(default=0) text_value = models.TextField(null=True, blank=True) def __str__(self): - return str(self.parameter_type) + ': ' + str(self.value) + if self.parameter_type.parameter_type == 'F': + value = self.text_value + else: + value = str(self.value) + + return str(self.component)+ ': '+ str(self.parameter_type) + ': ' + value class Stock(models.Model): @@ -247,7 +256,7 @@ class Stock(models.Model): class DistributorNum(models.Model): class Meta: unique_together = ('component', 'distributor') - ordering = ['distributor_part_number'] + ordering = ['distributor__name'] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True) distributor_part_number = models.CharField(max_length=100) distributor = models.ForeignKey(Distributor, on_delete=models.CASCADE) diff --git a/shimatta_kenkyusho/parts/views.py b/shimatta_kenkyusho/parts/views.py index 17581cf..7733aad 100644 --- a/shimatta_kenkyusho/parts/views.py +++ b/shimatta_kenkyusho/parts/views.py @@ -11,12 +11,12 @@ from django.views import View import django.forms as forms from django.views.generic import TemplateView, DetailView from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin -from .models import Storage, Stock, Component, Distributor, Manufacturer, Package, ComponentParameter, ComponentParameterType +from .models import Storage, Stock, Component, Distributor, Manufacturer, Package, ComponentParameter, ComponentParameterType, DistributorNum from .qr_parser import QrCodeValidator from django.core.paginator import Paginator from django.core.exceptions import ValidationError from django.db import IntegrityError -from .forms import MyTestForm, AddSubStorageForm, DeleteStockForm, EditWatermarkForm, EditStockAmountForm, AddStockForm, EditComponentForm, EditComponentParameterForm +from .forms import MyTestForm, AddSubStorageForm, DeleteStockForm, EditWatermarkForm, EditStockAmountForm, AddStockForm, EditComponentForm, EditComponentParameterForm, DistributorNumberForm, DistributorNumberFormSet from django.db.models import Q from django.db.models.functions import Lower import uuid @@ -391,16 +391,18 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): base_title = '' navbar_selected = 'Components' + + def prepare_initial_param_formset_data(self): parameters = ComponentParameter.objects.filter(component=self.object) initdata = [] for param in parameters: - param_type = param.parameter_type - if param_type.freetext_parameter: + param_type = param.parameter_type.parameter_type + if param_type == 'F': value = param.text_value else: value = param.value - initdata.append({'parameter_type': param_type, 'value': value}) + initdata.append({'parameter_type': param.parameter_type, 'value': value}) return initdata def get_context_data(self, **kwargs): @@ -409,11 +411,14 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): context['component'] = self.object context['edit_form'] = EditComponentForm(instance=self.object) - ParameterFormset = forms.formset_factory(EditComponentParameterForm, extra=0, max_num=100) + ParameterFormset = forms.formset_factory(EditComponentParameterForm, extra=1, max_num=100, can_delete=True) context['param_formset'] = ParameterFormset( initial=self.prepare_initial_param_formset_data()) context['stocks'] = Stock.objects.filter(component=self.object) + + DistriNumFormSet = forms.modelformset_factory(DistributorNum, form=DistributorNumberForm, extra=2) + context['distri_num_formset'] = DistriNumFormSet(queryset=DistributorNum.objects.filter(component=self.object), auto_id='id_fs_distri_no_%s') return context def handle_submit_edit_post(self, request, **kwargs): @@ -438,18 +443,76 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): return self.render_to_response(context) def handle_submit_edit_params_post(self, request, **kwargs): + ParameterFormset = forms.formset_factory(EditComponentParameterForm, extra=1, max_num=100) + fs = ParameterFormset(initial=self.prepare_initial_param_formset_data(), data=request.POST) + errors_set = False - + if fs.is_valid(): + # Go through all the parameter forms: + for form in fs: + if not form.has_changed(): + continue + + # Form has changed. Process the new value + try: + parameter_to_change = ComponentParameter.objects.get(component=self.object, + parameter_type__parameter_name=form.initial['parameter_type']) + parameter_to_change.parameter_type = form.cleaned_data['parameter_type_object'] + parameter_to_change.value = 0 + parameter_to_change.text_value = None + except: + try: + parameter_to_change = ComponentParameter.objects.create(component=self.object, + parameter_type=form.cleaned_data['parameter_type_object']) + except: + form.add_error('parameter_type', 'Parameter could not be saved. Unique?') + errors_set = True + break + + parameter_to_change.value = 0 + parameter_to_change.text_value = None + + if parameter_to_change.parameter_type.parameter_type == 'F': + parameter_to_change.text_value = form.cleaned_data['processed_value'] + parameter_to_change.value = 0 + else: + parameter_to_change.value = form.cleaned_data['processed_value'] + + try: + parameter_to_change.save() + except: + form.add_error('parameter_type', 'Parameter could not be saved. Unique?') + errors_set = True context = self.get_context_data() + if not fs.is_valid() or errors_set: + context['param_formset'] = fs return self.render_to_response(context) + def handle_submit_edit_distri_nums_post(self, request, **kwargs): + DistriNumFormSet = forms.modelformset_factory(DistributorNum, form=DistributorNumberForm, extra=2, formset=DistributorNumberFormSet) + fs = DistriNumFormSet(queryset=DistributorNum.objects.filter(component=self.object), data=request.POST, auto_id='id_fs_distri_no_%s') + + if fs.is_valid(): + print('Valid') + fs.save(self.object) + else: + print('Invalid') + + context = self.get_context_data() + if not fs.is_valid(): + context['distri_num_formset'] = fs + return self.render_to_response(context) + + def post(self, request, *args, **kwargs): self.object = self.get_object() if 'submit-edit-comp' in request.POST: return self.handle_submit_edit_post(request, **kwargs) elif 'submit-edit-params' in request.POST: return self.handle_submit_edit_params_post(request, **kwargs) + elif 'submit-edit-distri-nums' in request.POST: + return self.handle_submit_edit_distri_nums_post(request, **kwargs) return super().post(request, *args, **kwargs) diff --git a/shimatta_kenkyusho/templates/parts/components-detail.html b/shimatta_kenkyusho/templates/parts/components-detail.html index 9b4e25a..6d5ea7a 100644 --- a/shimatta_kenkyusho/templates/parts/components-detail.html +++ b/shimatta_kenkyusho/templates/parts/components-detail.html @@ -24,7 +24,7 @@ -
+
@@ -65,17 +65,36 @@
-

Description

- {% if component.description %} - {{component.description|linebreaks}} - {% else %} - - {% endif %}
-

Parameters

+

Description

+ {% if component.description %} + {{component.description|linebreaks}} + {% else %} + + {% endif %} +
+
+ {% if component.pref_distri %} +

Preferred Distributor

+
+ {% if component.pref_distri.image %} +
+ {{component.pref_distri.name}} +
+
+
{{component.pref_distri.name}}
+
+ {% endif %} +
+ {% endif %} +
+
+
+
+

Parameters

{% csrf_token %} @@ -87,35 +106,81 @@ {% for f in param_formset %} - - - + + + + {% if f.errors %} + + + + + {% endif %} {% endfor %}
{{f.parameter_type_object.unit|default_if_none:""}}{{f.parameter_type_object.unit|default_if_none:"-"}}
+ {% if f.parameter_type.errors %} + {{f.parameter_type.errors}} + {% endif %} + + {% if f.value.errors %} + {{f.value.errors}} + {% endif %} +
+ {{param_formset.management_form}}
-

Stocks

- - - - - - - {% for stock in stocks %} - - - - - {% endfor %} - -
StorageAmount
{{stock.storage.get_full_path}}{{stock.amount}}
+

Distributor Part Numbers

+
+ {% csrf_token %} + + + + + + + {% for form in distri_num_formset %} + + + + + + + + {% endfor %} + +
DistributorPart Number
+ {% if form.instance.distributor %} + {{form.instance.distributor.name}} + {% else %} + + {% endif %} + + +
+ {{distri_num_formset.management_form}} + +
- +
+ + + + + + + {% for stock in stocks %} + + + + + {% endfor %} + +
StorageAmount
{{stock.storage.get_full_path}}{{stock.amount}}
+