Make progress with automatic form field for model autocompletion
This commit is contained in:
parent
258fd1747c
commit
a0775a69ca
@ -3,15 +3,56 @@ from django.forms import widgets
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from parts import models as parts_models
|
from parts import models as parts_models
|
||||||
from shimatta_modules.EngineeringNumberConverter import EngineeringNumberConverter
|
from shimatta_modules.EngineeringNumberConverter import EngineeringNumberConverter
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
class AutoCompleteWidget(widgets.Input):
|
||||||
|
template_name = 'widgets/autocomplete-foreign-key.html'
|
||||||
|
|
||||||
|
def __init__(self, api_search_url, image_field_name, foreign_model, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.image_field_name = image_field_name
|
||||||
|
self.foreign_model = foreign_model
|
||||||
|
self.api_search_url = api_search_url
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
context = super().get_context(name, value, attrs)
|
||||||
|
try:
|
||||||
|
instance = self.foreign_model.objects.get(id=uuid.UUID(value))
|
||||||
|
except Exception as ex:
|
||||||
|
print(ex)
|
||||||
|
instance = None
|
||||||
|
|
||||||
|
image = None
|
||||||
|
if instance is not None:
|
||||||
|
image = getattr(instance, self.image_field_name)
|
||||||
|
|
||||||
|
|
||||||
class AutoCompleteWidget(widgets.TextInput):
|
context['custom'] = {
|
||||||
template_name = 'widgets/autrocomplete-foreign-key.html'
|
'search_url': self.api_search_url,
|
||||||
|
'image_field_name': self.image_field_name,
|
||||||
|
'current_instance': instance,
|
||||||
|
'image': image,
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class AutocompleteForeingKeyField(forms.UUIDField):
|
class AutocompleteForeingKeyField(forms.UUIDField):
|
||||||
def __init__(self, foreign_model=None, api_search_url=None, autocomplete_media_div=False, **kwargs):
|
def __init__(self, foreign_model=None, api_search_url=None, image_field_name='image', **kwargs):
|
||||||
kwargs['widget'] = AutoCompleteWidget
|
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
self.widget = AutoCompleteWidget(api_search_url, image_field_name, foreign_model)
|
||||||
|
self.foreign_model = foreign_model
|
||||||
|
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
pre_cleaned_uuid = super().clean(value)
|
||||||
|
if pre_cleaned_uuid is None and not self.required:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
obj = self.foreign_model.objects.get(id=pre_cleaned_uuid)
|
||||||
|
except self.foreign_model.DoesNotExist:
|
||||||
|
raise ValidationError('Given element does not exist')
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class MyTestForm(forms.Form):
|
class MyTestForm(forms.Form):
|
||||||
pass
|
pass
|
||||||
@ -118,8 +159,9 @@ class AddStockForm(forms.Form):
|
|||||||
new_stock.save()
|
new_stock.save()
|
||||||
|
|
||||||
class ComponentForm(forms.ModelForm):
|
class ComponentForm(forms.ModelForm):
|
||||||
manufacturer = AutocompleteForeingKeyField(widget=AutoCompleteWidget)
|
manufacturer = AutocompleteForeingKeyField(api_search_url='foo', foreign_model=parts_models.Manufacturer)
|
||||||
component_type = AutocompleteForeingKeyField()
|
component_type = AutocompleteForeingKeyField(api_search_url='bar', foreign_model=parts_models.ComponentType, required=False, image_field_name=None)
|
||||||
|
package = AutocompleteForeingKeyField(api_search_url='pkgurl', foreign_model=parts_models.Package, required=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = parts_models.Component
|
model = parts_models.Component
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -521,7 +521,7 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView):
|
|||||||
context['edit_form'] = EditComponentForm(instance=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()
|
context['comp_form'] = ComponentForm(instance=self.object)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -546,10 +546,25 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView):
|
|||||||
context['edit_form'] = form
|
context['edit_form'] = form
|
||||||
return self.render_to_response(context)
|
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['comp_form'] = cform
|
||||||
|
|
||||||
|
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:
|
if 'submit-edit-comp' in request.POST:
|
||||||
return self.handle_submit_edit_post(request, **kwargs)
|
return self.handle_submit_edit_post(request, **kwargs)
|
||||||
|
if 'submit-edit-component' in request.POST:
|
||||||
|
return self.handle_submit_edit_component_post(request, **kwargs)
|
||||||
|
|
||||||
return super().post(request, *args, **kwargs)
|
return super().post(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@ -119,9 +119,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<form action="" method="post">
|
||||||
{{comp_form|crispy}}
|
{% csrf_token %}
|
||||||
|
{{comp_form|crispy}}
|
||||||
|
<input type="submit" name="submit-edit-component" value="Submit">
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if component.get_resolved_image %}
|
{% if component.get_resolved_image %}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<div class="dropdown">
|
||||||
|
<input autocomplete="off" data-ac-url="{{custom.search_url}}" data-bs-toggle="dropdown" class="form-control{% if widget.errors %} is-invalid{% endif %}" type="text" placeholder="Search...">
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center" id="{{widget.attrs.id}}-dflex-container">
|
||||||
|
{% if custom.current_instance %}
|
||||||
|
{% if custom.image_field_name %}
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
{% if custom.image %}
|
||||||
|
<img src="{{custom.image.url}}" style="max-width:64px;max-height:64px;" class="mr-3">
|
||||||
|
{% else %}
|
||||||
|
{% load static %}
|
||||||
|
<img src="{% static 'css/icons/card-image.svg' %}" style="width:64px;max-height:64px;" class="mr-3">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex-grow-1 ms-3">
|
||||||
|
{% if custom.current_instance %}
|
||||||
|
{{custom.current_instance}}
|
||||||
|
{% else %}
|
||||||
|
<span class="text-secondary">None selected</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul id="{{widget.attrs.id}}-ac-ul" class="dropdown-menu">
|
||||||
|
</ul>
|
||||||
|
<input type="hidden" {% if widget.value != None %}value="{{widget.value}}"{%endif%} name={{widget.name}}>
|
||||||
|
</div>
|
@ -1,7 +0,0 @@
|
|||||||
<div class="dropdown">
|
|
||||||
<input autocomplete="off" data-bs-toggle="dropdown" class="form-control{% if widget.errors %} is-invalid{% endif %}" type="text" {% if widget.value != None %}value="{{widget.value}}"{%endif%}
|
|
||||||
{% for name, value in widget.attrs.items %}{% if value is not False and name != 'id' %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %} id="{{widget.attrs.id}}_search_field">
|
|
||||||
<ul id="{{form.manufacturer.id_for_label}}-ac-ul" class="dropdown-menu">
|
|
||||||
</ul>
|
|
||||||
<input type="hidden" value="" name={{widget.name}}>
|
|
||||||
</div>
|
|
Loading…
Reference in New Issue
Block a user