Implement component deletion

This commit is contained in:
Mario Hüttel 2022-01-01 17:53:10 +01:00
parent 8ef217f224
commit dbbd8b4a99
4 changed files with 109 additions and 149 deletions

View File

@ -180,123 +180,11 @@ class ComponentForm(forms.ModelForm):
manufacturer = AutocompleteForeingKeyField(api_search_url='manufacturer-list', foreign_model=parts_models.Manufacturer, required=False) manufacturer = AutocompleteForeingKeyField(api_search_url='manufacturer-list', foreign_model=parts_models.Manufacturer, required=False)
component_type = AutocompleteForeingKeyField(api_search_url='componenttype-list', foreign_model=parts_models.ComponentType, name_field_name='class_name', required=False, image_field_name=None) component_type = AutocompleteForeingKeyField(api_search_url='componenttype-list', foreign_model=parts_models.ComponentType, name_field_name='class_name', required=False, image_field_name=None)
package = AutocompleteForeingKeyField(api_search_url='package-list', foreign_model=parts_models.Package, required=False) package = AutocompleteForeingKeyField(api_search_url='package-list', foreign_model=parts_models.Package, required=False)
pref_distri = AutocompleteForeingKeyField(api_search_url='distributor-list', foreign_model=parts_models.Distributor, required=False)
class Meta: class Meta:
model = parts_models.Component model = parts_models.Component
fields = '__all__' fields = '__all__'
class EditComponentForm(forms.Form):
name = forms.CharField(required=True)
datasheet_link = forms.CharField(max_length=300, required=False)
description = forms.CharField(required=False, widget=forms.Textarea)
# Look up these fields later. Will be autocompleted in UI
manufacturer = forms.CharField(required=False, initial='')
component_type = forms.CharField(required=False, label='Component Type', initial='')
pref_distri = forms.CharField(required=False, label='Preferred Distributor', initial='')
package = forms.CharField(required=False, initial='')
image = forms.ImageField(required=False)
def __init__(self, *args, instance=None, **kwargs):
super().__init__(*args, **kwargs)
self.instance = instance
if instance:
self.fields['name'].initial = instance.name
self.fields['datasheet_link'].initial = instance.datasheet_link
if instance.component_type:
self.fields['component_type'].initial = instance.component_type.class_name
self.fields['description'].initial = instance.description
if instance.manufacturer:
self.fields['manufacturer'].initial = instance.manufacturer.name
if instance.package:
self.fields['package'].initial = instance.package.name
if instance.pref_distri:
self.fields['pref_distri'].initial = instance.pref_distri.name
self.fields['image'].initial = instance.image
def clean_component_type(self):
data = self.cleaned_data['component_type'].strip()
if len(data) == 0:
self.cleaned_data['component_type_object'] = None
return
try:
self.cleaned_data['component_type_object'] = parts_models.ComponentType.objects.get(class_name=data)
except:
raise ValidationError('Invalid Component Type')
def clean_manufacturer(self):
data = self.cleaned_data['manufacturer'].strip()
if len(data) == 0:
self.cleaned_data['manufacturer_object'] = None
return
try:
self.cleaned_data['manufacturer_object'] = parts_models.Manufacturer.objects.get(name=data)
except:
raise ValidationError('Invalid Manufacturer')
def clean_pref_distri(self):
data = self.cleaned_data['pref_distri'].strip()
if len(data) == 0:
self.cleaned_data['pref_distri_object'] = None
return
try:
self.cleaned_data['pref_distri_object'] = parts_models.Distributor.objects.get(name=data)
except:
raise ValidationError('Invalid Distributor')
def clean_package(self):
data = self.cleaned_data['package'].strip()
if len(data) == 0:
self.cleaned_data['package_object'] = None
return
try:
self.cleaned_data['package_object'] = parts_models.Package.objects.get(name=data)
except:
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._save_new()
return
self.instance.name = self.cleaned_data['name']
self.instance.datasheet_link = self.cleaned_data['datasheet_link']
self.instance.description = self.cleaned_data['description']
if bool(self.cleaned_data['image']) is False:
self.instance.image = None
else:
self.instance.image = self.cleaned_data['image']
self.instance.manufacturer = self.cleaned_data['manufacturer_object']
self.instance.pref_distri = self.cleaned_data['pref_distri_object']
self.instance.package = self.cleaned_data['package_object']
self.instance.component_type = self.cleaned_data['component_type_object']
self.instance.save()
class PackageForm(forms.ModelForm): class PackageForm(forms.ModelForm):
class Meta: class Meta:
model = parts_models.Package model = parts_models.Package

View File

@ -147,7 +147,25 @@ class ComponentView(LoginRequiredMixin, BaseTemplateMixin, TemplateView):
comp_paginator = Paginator(Component.objects.all(), self.default_page_size) comp_paginator = Paginator(Component.objects.all(), self.default_page_size)
context['components'] = comp_paginator.get_page(comp_page_num) context['components'] = comp_paginator.get_page(comp_page_num)
context['comp_form'] = ComponentForm()
return context return context
def handle_new_component_post(self, request, **kwargs):
cform = ComponentForm(data=request.POST, files=request.FILES)
if cform.is_valid():
cform.save()
context = self.get_context_data(**kwargs)
if not cform.is_valid():
context['comp_form'] = cform
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
if 'submit-edit-component' in request.POST:
return self.handle_new_component_post(request, **kwargs)
else:
return super().post(request, *args, **kwargs)
class PackageView(LoginRequiredMixin, BaseTemplateMixin, TemplateView): class PackageView(LoginRequiredMixin, BaseTemplateMixin, TemplateView):
template_name = 'parts/packages.html' template_name = 'parts/packages.html'
@ -518,55 +536,50 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView):
self.base_title = 'Component / '+self.object.name self.base_title = 'Component / '+self.object.name
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['component'] = self.object context['component'] = self.object
context['edit_form'] = EditComponentForm(instance=self.object)
context['stocks'] = Stock.objects.filter(component=self.object) context['stocks'] = Stock.objects.filter(component=self.object)
context['comp_form'] = ComponentForm(instance=self.object) context['comp_form'] = ComponentForm(instance=self.object)
return context return context
def handle_submit_edit_post(self, request, **kwargs):
form_error = False
form = EditComponentForm(instance=self.object, data=request.POST, files=request.FILES)
if form.is_valid():
try:
form.save()
except IntegrityError as ie:
form.add_error('name', 'Component name, package, and manufacturer are not unique!')
form.add_error('package', 'Component name, package, and manufacturer are not unique!')
form.add_error('manufacturer', 'Component name, package, and manufacturer are not unique!')
form_error = True
self.object = self.get_object()
else:
form_error = True
context = self.get_context_data(**kwargs)
if form_error:
context['edit_form'] = form
return self.render_to_response(context)
def handle_submit_edit_component_post(self, request, **kwargs): def handle_submit_edit_component_post(self, request, **kwargs):
context = self.get_context_data(**kwargs)
cform = ComponentForm(instance=self.object, data=request.POST, files=request.FILES) cform = ComponentForm(instance=self.object, data=request.POST, files=request.FILES)
if cform.is_valid(): if cform.is_valid():
print('valid')
cform.save() cform.save()
else:
print('invalid') context = self.get_context_data(**kwargs)
context['comp_form'] = cform if not cform.is_valid():
context['comp_form'] = cform
return self.render_to_response(context) return self.render_to_response(context)
def handle_submit_delete_post(self, request, **kwargs):
delete_error = None
protected_stuff = None
try:
self.object.delete()
except ProtectedError as pe:
delete_error = 'Component is protected'
protected_stuff = pe.protected_objects
except:
delete_error = 'Cannot delete component. Unknown error'
if delete_error is None:
return redirect('parts-components')
else:
context = self.get_context_data(**kwargs)
context['delete_error'] = delete_error
context['protected_stuff'] = protected_stuff
return self.render_to_response(context)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
if 'submit-edit-comp' in request.POST:
return self.handle_submit_edit_post(request, **kwargs)
if 'submit-edit-component' in request.POST: if 'submit-edit-component' in request.POST:
return self.handle_submit_edit_component_post(request, **kwargs) return self.handle_submit_edit_component_post(request, **kwargs)
elif 'submit-component-delete' in request.POST:
return super().post(request, *args, **kwargs) return self.handle_submit_delete_post(request, **kwargs)
else:
return super().post(request, *args, **kwargs)
class PackageDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): class PackageDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView):
template_name = 'parts/packages-detail.html' template_name = 'parts/packages-detail.html'

View File

@ -22,6 +22,7 @@
<a class="btn btn-secondary mb-2" href="{{component.datasheet_link}}"><i class="bi bi-file-pdf-fill"></i> Datasheet</a> <a class="btn btn-secondary mb-2" href="{{component.datasheet_link}}"><i class="bi bi-file-pdf-fill"></i> Datasheet</a>
{% endif %} {% endif %}
<button class="btn btn-primary mb-2" data-bs-toggle="modal" data-bs-target="#comp-edit-modal"><i class="bi bi-pencil-square"></i> Edit Component</button> <button class="btn btn-primary mb-2" data-bs-toggle="modal" data-bs-target="#comp-edit-modal"><i class="bi bi-pencil-square"></i> Edit Component</button>
<button class="btn btn-danger mb-2" data-bs-toggle="modal" data-bs-target="#component-delete-modal"><i class="bi bi-file-x"></i> Delete {{component.name}}</button>
</div> </div>
</div> </div>
<div class="col m-1"> <div class="col m-1">
@ -144,15 +145,54 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<!-- Delete modal -->
<div class="modal fade" id="component-delete-modal" tabindex="-1">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content">
<div class="modal-header">
<h5>{{component.name}}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h4>Delete this Component?</h4>
{% if delete_error %}
<div class="alert alert-danger">
{{delete_error}}
</div>
{% if protected_stuff %}
<h4>Following prevent the deletion:</h4>
<ul>
{% for elem in protected_stuff %}
<li>{{elem}}</li>
{% endfor %}
</ul>
{% endif %}
{% endif %}
</div>
<div class="modal-footer">
<form action="" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger" name="submit-component-delete"><i class="bi bi-file-x"></i> Delete {{component.name}}</button>
</form>
</div>
</div>
</div>
</div>
{% include 'parts/modals/edit-component-modal.html' with heading="Edit "|add:component.name form=comp_form %} {% include 'parts/modals/edit-component-modal.html' with heading="Edit "|add:component.name form=comp_form %}
{% endblock content %} {% endblock content %}
{% block custom_scripts %} {% block custom_scripts %}
<script type="text/javascript"> <script type="text/javascript">
{% if edit_form.errors %} {% if comp_form.errors %}
bootstrap.Modal.getOrCreateInstance(document.getElementById('comp-edit-modal')).show() bootstrap.Modal.getOrCreateInstance(document.getElementById('comp-edit-modal')).show()
{% endif %} {% endif %}
{% if delete_error %}
bootstrap.Modal.getOrCreateInstance(document.getElementById('component-delete-modal')).show();
{% endif %}
</script> </script>
{% endblock custom_scripts %} {% endblock custom_scripts %}

View File

@ -5,7 +5,15 @@
<div class="row"> <div class="row">
<div class="col-md"> <div class="col-md">
<h2>Components</h2> <h2>Components</h2>
<div class="list-group"> <form action="" method="get">
<div class="input-group mb-3">
<input class="form-control" name="search" type="search" placeholder="Search Component..." {% if search_string %}value="{{search_string}}"{% endif %}>
<button type="submit" class="btn btn-primary">
<i class="bi bi-search"></i>
</button>
<button class="btn btn-success" type="button" data-bs-toggle="modal" data-bs-target="#comp-edit-modal"><i class="bi bi-plus-circle"></i> Add Component</button> </div>
</form>
<div class="list-group mb-3">
{% for comp in components %} {% for comp in components %}
<a href="{% url 'parts-components-detail' uuid=comp.id %}" class="text-decoration-none"> <a href="{% url 'parts-components-detail' uuid=comp.id %}" class="text-decoration-none">
<li class="list-group-item list-group-item-action d-flex align-items-center"> <li class="list-group-item list-group-item-action d-flex align-items-center">
@ -35,4 +43,15 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock content %}
{% include 'parts/modals/edit-component-modal.html' with form=comp_form heading='New Component' %}
{% endblock content %}
{% block custom_scripts %}
<script type="text/javascript">
{% if comp_form.errors %}
bootstrap.Modal.getOrCreateInstance(document.getElementById('comp-edit-modal')).show()
{% endif %}
</script>
{% endblock custom_scripts %}