django-autocomplete-light
django-autocomplete-light copied to clipboard
Select2 preload bug while rendering after form error
Due to the fact that I can't change the default representation of the object (TestTarget), I've overloaded both the get_result_label
and the get_selected_result_label
methods on the autocomplete view function to use the full_name
property on the object:
class TestTargetAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = models.TestTarget.objects.filter(active=True).all()
if self.q:
qs = qs.filter(name__icontains=self.q)
return qs
def get_result_label(self, item):
return item.full_name
def get_selected_result_label(self, item):
return item.full_name
class TestTarget(models.Model):
uuid = models.UUIDField(
db_index=True,
default=uuid_lib.uuid4,
editable=False
)
name = models.CharField(max_length=255, null=True)
active = models.BooleanField(default=True)
class Meta:
db_table = 'test_target'
@property
def full_name(self):
return self.name
def __str__(self):
return "<TestTarget {}>".format(self.name)
If there is a form error upon submission, one would expect the get_result_label
or the get_selected_result_label
method to be called during the re-rendering of the form. However, it seems to be default to calling the __str__
method on the object as it re-renders.
Before submission:
After submitting with a form error:
This is because initial rendering is done by the widget, not by the view !
@jpic what is the appropriate solution to this issue then?
Same question, what is the appropriate solution to this issue ?
How to manage the rendering of the initial value ? I'd like to have the same rendering as def get_result_label(self, item):
that I have done. Especially in the admin view
More details : I defined in admin.py:
class TestChangeFormBase(...):
...
class Meta:
model = TestChangeFormBase
widgets = some_widgets
...
some_widgets = {
...
specific_user : SpecificUserAutocompleteWidget
...
}
SpecificUserAutocompleteWidget = autocomplete.ModelSelect2(
url = 'specificuser-autocomplete',
attrs = {
'data-placeholder': _('SpecificUser?'),
'data-minimum-input-length': 1,
'data-html': True,
'data-container-css-class': 'height-auto'
}
)
in views.py
class SpecificUserAutocompleteView(FilteredAutocomplete):
queryset = SpecificUser.objects.all()
serializer_class = SpecificUserSerializer
filter_backends = (SearchFilter,)
search_fields = ('first_name', 'last_name')
filters = {'is_specific': True, 'deleted__isnull': True}
def get_result_label(self, item):
context = {
'choice': item,
}
return render_to_string('people/person_choice.html', context)
def get_selected_result_label(self, result):
context = {
'choice': result,
}
return render_to_string('people/person_choice.html', context)
```
This is working fine when selecting a user in the select box. But when I load the object, the select box contains the `__str__` value of the model of SpecificUser
Before I was using autocomplete 2.3.6 but I did the required refactoring to upgrade to 3.3.2 and it is not working as before.
I tried in `__init__` of my form to do :
```python
if 'specific_user' in self.fields:
self.fields["specific_user"].label_from_instance = self.label_from_instance
@mark_safe
def label_from_instance(self, obj):
return format_html('<a href="{0}">{1}</a>',str(obj), str(obj)+" TEST "+str(obj.mobile_phone_number))
```
But then it displays only text without html. Also It will be better to use my template `'people/person_choice.html'`.
This is because v2 was using a metaclass that was a pain in the ass to maintain across django versions and there were not enough contributions to maintain it (i had to do it all by myself for free and I couldn't). Couldn't maintain the custom JS either. Hope to have the chance to give it another try one day when I find sponsor. Otherwise, you can participate to #1067
You can still make your rendering function and use it both in the widget rendering and the view rendering methods, but it's up to you.
Your last paste is not complete, are you defining label_from_instance in the form class ? How is that supposed to work ? Does it work when you define that method in the form field class ?
Hello @jpic and thank you for the job done!! I understand that you did not want to maintain the old version this is why I decided to upgrade to the last version to avoid the "pain in the ass" ;).
====
Yes I defined label_from_instance
in the form class. I took the idea from #964.
Also I've seen that #607 is suggesting to override
class UserModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.get_full_name().title()
====
How is that supposed to work ? Does it work when you define that method in the form field class ?
It works but without HTML code, the results contains only text which is not what I want :/.
====
My template people/person_choice
contains :
{% load i18n l10n %}
{% load static %}
<div class="block person" data-value="{{ choice.pk }}"> <strong>{{ choice.full_name }} </strong>
<p style="padding: 2px 10px 2px 10px !important">
{% if choice.phone_numbers %}
{{ choice.phone_numbers|join:'/' }}
<br/>
{% endif %}
{% if choice.work_email_address %}
<a href="mailto:{{ choice.work_email_address }}">{{ choice.work_email_address }}</a>
{% elif choice.home_email_address %}
<a href="mailto:{{ choice.home_email_address }}">{{ choice.home_email_address }}</a>
{% endif %}
</p>
</div>
And is call this in the SpecificUserAutocompleteView (already copied in my previous message)
====
You can still make your rendering function and use it both in the widget rendering and the view rendering methods, but it's up to you.
Can you explain with more details what you mean, an example would be wonderful!
All right, we can't have HTML in options so that's too bad for custom rendering.
However, you can deal with it in js, by putting your own js starter.
I really want to make a javascript-autocomplete-light package, based on jquery-autocomplete-light that we had, but it's far off my priorities for now, unfortunately. I think I had a kickstarter campaign ready to start but didn't proceed.
Ok thank you for your answers. What is your kickstarter campaign ?
I had the idea that if people are interested in seeing a port of jquery-autocomplete-light into modern javascript (with unit tests instead of selenium tests that would make it more maintainable), they would pay for it. But I don't really believe in that anymore, so, the rewrite is stuck at the bottom of my todo list until a customer asks for an autocomplete (this has surprisingly not happened for a while).
Agreed, PR welcome
Le ven. 3 janv. 2020 à 00:26, pySilver [email protected] a écrit :
Solution is in the docs: https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2
It would be nice to have generic view for this case.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/yourlabs/django-autocomplete-light/issues/1034?email_source=notifications&email_token=AAAXDLHGXMTP6LROC6WU2NTQ3ZZ2BA5CNFSM4FSXZWAKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEH7ZCQI#issuecomment-570396993, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAXDLENWWCYKQKYROQYZQTQ3ZZ2BANCNFSM4FSXZWAA .