Implement component deletion
This commit is contained in:
		@@ -180,123 +180,11 @@ class ComponentForm(forms.ModelForm):
 | 
			
		||||
    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)
 | 
			
		||||
    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:
 | 
			
		||||
        model = parts_models.Component
 | 
			
		||||
        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 Meta:
 | 
			
		||||
        model = parts_models.Package
 | 
			
		||||
 
 | 
			
		||||
@@ -147,8 +147,26 @@ class ComponentView(LoginRequiredMixin, BaseTemplateMixin, TemplateView):
 | 
			
		||||
        comp_paginator = Paginator(Component.objects.all(), self.default_page_size)
 | 
			
		||||
 | 
			
		||||
        context['components'] = comp_paginator.get_page(comp_page_num)
 | 
			
		||||
        context['comp_form'] = ComponentForm()
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
    template_name = 'parts/packages.html'
 | 
			
		||||
    base_title = 'Packages'
 | 
			
		||||
@@ -518,54 +536,49 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView):
 | 
			
		||||
        self.base_title = 'Component / '+self.object.name
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        context['component'] = self.object
 | 
			
		||||
        context['edit_form'] = EditComponentForm(instance=self.object)
 | 
			
		||||
 | 
			
		||||
        context['stocks'] = Stock.objects.filter(component=self.object)
 | 
			
		||||
        context['comp_form'] = ComponentForm(instance=self.object)
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        context = self.get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        cform = ComponentForm(instance=self.object, data=request.POST, files=request.FILES)
 | 
			
		||||
        if cform.is_valid():
 | 
			
		||||
            print('valid')
 | 
			
		||||
            cform.save()
 | 
			
		||||
        else:
 | 
			
		||||
            print('invalid')
 | 
			
		||||
        
 | 
			
		||||
        context = self.get_context_data(**kwargs)
 | 
			
		||||
        if not cform.is_valid():
 | 
			
		||||
            context['comp_form'] = cform
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        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:
 | 
			
		||||
            return self.handle_submit_edit_component_post(request, **kwargs)
 | 
			
		||||
        
 | 
			
		||||
        elif 'submit-component-delete' in request.POST:
 | 
			
		||||
            return self.handle_submit_delete_post(request, **kwargs)
 | 
			
		||||
        else:
 | 
			
		||||
            return super().post(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
class PackageDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView):
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
            {% 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-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 class="col m-1">
 | 
			
		||||
@@ -144,15 +145,54 @@
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% 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 %}
 | 
			
		||||
{% endblock content %}
 | 
			
		||||
 | 
			
		||||
{% block custom_scripts %}
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
{% if edit_form.errors %}
 | 
			
		||||
{% if comp_form.errors %}
 | 
			
		||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('comp-edit-modal')).show()
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% if delete_error %}
 | 
			
		||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('component-delete-modal')).show();
 | 
			
		||||
{% endif %}
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock custom_scripts %}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,15 @@
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-md">
 | 
			
		||||
            <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 %}
 | 
			
		||||
                    <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">
 | 
			
		||||
@@ -35,4 +43,15 @@
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% 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 %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user