yourlabs / django-autocomplete-light

A fresh approach to autocomplete implementations, specially for Django. Status: v4 alpha, v3 stable, v2 & v1 deprecated.
https://django-autocomplete-light.readthedocs.io
MIT License
1.79k stars 466 forks source link

DAL is re-ordering items with the ModelSelect2Multiple widget #1357

Open YasirKusay opened 3 months ago

YasirKusay commented 3 months ago

I have just noticed something interesting with DAL if you are using the ModelSelect2Multiple widget for the forms.ModelMultipleChoiceField. I initially selected apricot, then apples:

Screen Shot 2024-03-22 at 7 08 07 pm

I then deleted both and then selected apples, then apricot:

Screen Shot 2024-03-22 at 7 08 52 pm

However, once I selected apricot, the options selected above are re-ordered to apricot, then apples:

Screen Shot 2024-03-22 at 7 09 56 pm

In other words, they are re-ordered to the original order in image 1. It appears that there is something in the background that is preserving the original order and ordering the items here based on that. I do not want that and I want to preserve the order of the currently selected items regardless. Is that possible?

YasirKusay commented 3 months ago

Here is some code if it helps:

## forms.py

from dal import autocomplete
from django import forms
from .models import Food, Analysis
from dal import autocomplete

class AnalysisForm(forms.Form):
    class Meta:
        model = Analysis
        fields = ('__all__')

    food = forms.ModelMultipleChoiceField(queryset=Food.objects.all(),
                                     required=True,
                                     widget=autocomplete.ModelSelect2Multiple(url='test2-autocomplete',
                                                         attrs={'data-placeholder': 'Foods ...',
                                                                'data-minimum-input-length': 1.,
                                                                "class": "food-select-form",
                                                                }))
## models.py

from django.db import models

# Create your models here.
class Food(models.Model):
    name = models.CharField(primary_key=True, max_length=40)

    def __str__(self):
        return self.name

class City(models.Model):
    name = models.CharField(primary_key=True, max_length=40)

    def __str__(self):
        return self.name

class Analysis(models.Model):
    food = models.ForeignKey(Food, on_delete=models.CASCADE)
    cities = models.ManyToManyField(City, blank=True)
## views.py

from django.shortcuts import render
from .models import Food
from dal import autocomplete
from .forms import AnalysisForm

def test(request):
    form = AnalysisForm()
    print("A")
    return render(request, 'test2/test2_file.html', {'form': form})

class FoodAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Food.objects.all()
        print(qs)

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs
## test2_file.html

   <body>
        <div class="container column">
            <form>
                <div class="all_autocomplete_forms column">
                    <div class="wrapperDiv">
                        {% csrf_token %}
                        {{ form.food }}
                    </div>
                </div>
                <button id="add_more" class="btn btn-secondary" type="button">Add more</button>
            </form>
        </div>
    </body>
YasirKusay commented 3 months ago

I developed a slight workaround. I deleted the for each individual food that gets added when I select the food from that form element when I click 'x' in the form for that option.