Functional checkpoint: add/delete related parts from template

This commit is contained in:
eeintech 2020-10-16 13:50:31 -05:00
parent 8579abb9c2
commit 34e4409e7f
5 changed files with 83 additions and 71 deletions

View File

@ -1254,25 +1254,32 @@ class Part(MPTTModel):
return self.get_descendants(include_self=False) return self.get_descendants(include_self=False)
def fetch_related_parts(self): def get_related_parts(self):
""" Return all related parts """ """ Return list of tuples for all related parts:
- first value is PartRelated object
- second value is matching Part object
"""
related_parts = [] related_parts = []
parts_1 = self.related_parts_1.filter(part_1__id=self.pk) related_parts_1 = self.related_parts_1.filter(part_1__id=self.pk)
parts_2 = self.related_parts_2.filter(part_2__id=self.pk) related_parts_2 = self.related_parts_2.filter(part_2__id=self.pk)
for part in parts_1: for related_part in related_parts_1:
# Append # Add to related parts list
related_parts.append(part.part_2) related_parts.append((related_part, related_part.part_2))
for part in parts_2: for related_part in related_parts_2:
# Append # Add to related parts list
related_parts.append(part.part_1) related_parts.append((related_part, related_part.part_1))
return related_parts return related_parts
@property
def related_count(self):
return len(self.get_related_parts())
def attach_file(instance, filename): def attach_file(instance, filename):
""" Function for storing a file for a PartAttachment """ Function for storing a file for a PartAttachment
@ -1783,7 +1790,8 @@ class PartRelated(models.Model):
@classmethod @classmethod
def create(cls, part_1, part_2): def create(cls, part_1, part_2):
''' Create PartRelated object ''' ''' Create PartRelated object and relationship between two parts '''
related_part = cls() related_part = cls()
related_part.create_relationship(part_1, part_2) related_part.create_relationship(part_1, part_2)
return related_part return related_part

View File

@ -18,7 +18,32 @@
</div> </div>
</div> </div>
<table class='table table-striped table-condensed related-table' id='table-related-part' data-toolbar='#button-bar'> <table id='table-related-part' class='table table-condensed table-striped' data-toolbar='#button-toolbar'>
<thead>
<tr>
<th data-field='part' data-serachable='true'>{% trans "Part" %}</th>
</tr>
</thead>
<tbody>
{% for item in part.get_related_parts %}
{% with part_related=item.0 part=item.1 %}
<tr>
<td>
<a class='hover-icon'>
<img class='hover-img-thumb' src='{{ part.get_thumbnail_url }}'>
<img class='hover-img-large' src='{{ part.get_thumbnail_url }}'>
</a>
<a href='/part/{{ part.id }}/'>{{ part }}</a>
<div class='btn-group' style='float: right;'>
{% if roles.part.change %}
<button title='{% trans "Delete" %}' class='btn btn-default btn-glyph delete-related-part' url="{% url 'part-related-delete' part_related.id %}" type='button'><span class='fas fa-trash-alt icon-red'/></button>
{% endif %}
</div>
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table> </table>
@ -27,20 +52,24 @@
{% block js_ready %} {% block js_ready %}
{{ block.super }} {{ block.super }}
loadPartRelatedTable($("#table-related-part"), { $('#table-related-part').inventreeTable({
url: "{% url 'api-part-list' %}", });
params: {
part: {{ part.id }}, $("#add-related-part").click(function() {
}, launchModalForm("{% url 'part-related-create' %}", {
}); data: {
part: {{ part.id }},
$("#add-related-part").click(function() { },
launchModalForm("{% url 'part-related-create' %}", { reload: true,
data: { });
part: {{ part.id }}, });
},
reload: true, $('.delete-related-part').click(function() {
var button = $(this);
launchModalForm(button.attr('url'), {
reload: true,
});
}); });
});
{% endblock %} {% endblock %}

View File

@ -64,7 +64,7 @@
</li> </li>
{% endif %} {% endif %}
<li{% ifequal tab 'related-parts' %} class="active"{% endifequal %}> <li{% ifequal tab 'related-parts' %} class="active"{% endifequal %}>
<a href="{% url 'part-related' part.id %}">{% trans "Related Parts" %} {% if part.related_count > 0 %}<span class="badge">{{ part.related_count }}</span>{% endif %}</a> <a href="{% url 'part-related' part.id %}">{% trans "Related" %} {% if part.related_count > 0 %}<span class="badge">{{ part.related_count }}</span>{% endif %}</a>
</li> </li>
<li{% ifequal tab 'attachments' %} class="active"{% endifequal %}> <li{% ifequal tab 'attachments' %} class="active"{% endifequal %}>
<a href="{% url 'part-attachments' part.id %}">{% trans "Attachments" %} {% if part.attachment_count > 0 %}<span class="badge">{{ part.attachment_count }}</span>{% endif %}</a> <a href="{% url 'part-attachments' part.id %}">{% trans "Attachments" %} {% if part.attachment_count > 0 %}<span class="badge">{{ part.attachment_count }}</span>{% endif %}</a>

View File

@ -81,10 +81,8 @@ class PartRelatedCreate(AjaxCreateView):
ajax_template_name = "modal_form.html" ajax_template_name = "modal_form.html"
role_required = 'part.change' role_required = 'part.change'
# TODO: QuerySet should not show parts already related to object
def get_initial(self): def get_initial(self):
""" Point part_1 to parent part """ """ Set parent part as part_1 field """
initials = {} initials = {}
@ -102,12 +100,30 @@ class PartRelatedCreate(AjaxCreateView):
""" Create a form to upload a new PartRelated """ Create a form to upload a new PartRelated
- Hide the 'part_1' field (parent part) - Hide the 'part_1' field (parent part)
- Display parts which are not yet related
""" """
form = super(AjaxCreateView, self).get_form() form = super(AjaxCreateView, self).get_form()
form.fields['part_1'].widget = HiddenInput() form.fields['part_1'].widget = HiddenInput()
try:
# Get parent part
parent_part = self.get_initial()['part_1']
# Get existing related parts
related_parts = [related_part[1].pk for related_part in parent_part.get_related_parts()]
# Build updated choice list excluding parts already related to parent part
updated_choices = []
for choice in form.fields["part_2"].choices:
if choice[0] not in related_parts:
updated_choices.append(choice)
# Update choices for related part
form.fields['part_2'].choices = updated_choices
except KeyError:
pass
return form return form
def post_save(self): def post_save(self):
@ -116,14 +132,9 @@ class PartRelatedCreate(AjaxCreateView):
form = self.get_form() form = self.get_form()
if form.is_valid(): if form.is_valid():
print('form is valid!')
part_1 = form.cleaned_data['part_1'] part_1 = form.cleaned_data['part_1']
part_2 = form.cleaned_data['part_2'] part_2 = form.cleaned_data['part_2']
print(f'{part_1=}')
print(f'{part_2=}')
PartRelated.create(part_1, part_2) PartRelated.create(part_1, part_2)
@ -132,7 +143,6 @@ class PartRelatedDelete(AjaxDeleteView):
model = PartRelated model = PartRelated
ajax_form_title = _("Delete Related Part") ajax_form_title = _("Delete Related Part")
ajax_template_name = "related_delete.html"
context_object_name = "related" context_object_name = "related"
role_required = 'part.change' role_required = 'part.change'

View File

@ -163,41 +163,6 @@ function loadSimplePartTable(table, url, options={}) {
} }
function loadPartRelatedTable(table, options={}) {
/* Load related parts table */
var columns = [
{
field: options.params['part'],
title: '{% trans 'Part' %}',
sortable: true,
sortName: 'name',
formatter: function(value, row, index, field) {
var name = '';
if (row.IPN) {
name += row.IPN + ' | ' + row.name;
} else {
name += row.name;
}
return renderLink(name, '/part/' + row.pk + '/');
}
}
];
$(table).inventreeTable({
sortName: 'part',
groupBy: false,
name: options.name || 'related_parts',
formatNoMatches: function() { return "{% trans "No parts found" %}"; },
columns: columns,
showColumns: true,
});
}
function loadParametricPartTable(table, options={}) { function loadParametricPartTable(table, options={}) {
/* Load parametric table for part parameters /* Load parametric table for part parameters
* *