Search code examples
djangodjango-formsdjango-viewsdjango-templatesdjango-autocomplete-light

django-autocomplete-light's suggestions displayed beyond the drop-down list


For some reason, suggestions from django-autocomplete-light 3.5.0 are displayed beyond the drop-down list, to the right (there's narrow blue rectangle visible that indicates suggestions): enter image description here I'm able to reverse the widget's url and obtain correct suggestions. Everything's working fine but rendering - when I click on this narrow rectangle, correct value appears in the edit box. I collected all the static files. I'm working on Linux 20.04 LTS, Chrome 83.0.4103.106, python 3.7.7, django 3.0.3, bootstrap 4.5.0 and font-awesome 4.7.0. Here is the code (except settings) that I wrote forms.py

class OpinionForm(forms.ModelForm):
    # user field is defined as hidden and disabled such that it couldn't be changed
    user = forms.ModelChoiceField(
        widget=forms.HiddenInput,
        queryset=get_user_model().objects.all(),
        disabled=True
    )

    # defining all the fields with autocomplete feature
    country = forms.ModelChoiceField(
        queryset=Country.objects.all(),
        widget=autocomplete.ModelSelect2(url="country_autocomplete")
    )

    class Meta:
        model = Opinion
        fields = ("content",)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["country"].label = "Kraj"
        self.fields["content"].label = "Treść"

models.py

class Country(models.Model):
    name = models.CharField(max_length=200, null=False)

    def __str__(self):
        return self.name

class Opinion(models.Model):
    user = models.ForeignKey(to=settings.AUTH_USER_MODEL)
    content = models.TextField()
    created = models.DateTimeField(auto_now=True)

urls.py

urlpatterns = [
    path("add_opinion", views.CreateOpinionView.as_view(), name="add_opinion"),
    path("country-autocomplete/", CountryAutocomplete.as_view(create_field="name"),
]

views.py

class CountryAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        if not self.request.user.is_authenticated:
            return Country.objects.none()
        qs = Country.objects.all()
        if self.q:
            qs = qs.filter(name__istartswith=self.q)
        return qs

class CreateOpinionView(LoginRequiredMixin, CreateView):
    form_class = OpinionForm
    template_name = "opinions/create.html"

    def get_initial(self):
        """
        When our view is instantiating the form, it will pass the result of get_initial() as the 'initial'
    argument and the POST data as the 'data' argument

    :return:
    """
    return {
        "user": self.request.user.id
    }

def form_valid(self, form):
    """
    If a form is valid, CreateView will call form_valid.
    If the form isn't valid, CreateView will re-render the template.

    :param form:
    :return:
    """
    action = self.request.POST.get("action")
    # when we want to save, we will call the original form_valid method
    # the original method saves the new opinion
    if action == "SAVE":
        # save and redirect as usual
        return super().form_valid(form)
    return HttpResponseBadRequest()

create.html

{% extends "base.html" %}
{% load static %}

{% load crispy_forms_tags %}

{% block title %}Dodaj opinię{% endblock %}

{% block content %}
    <div class="col-md-12">
        <h1>Dodaj opinię</h1>
        <form method="post">
            {{ form | crispy }}
            {% csrf_token %}
            <button class="btn btn-primary" type="submit" name="action" value="SAVE">Zapisz</button>
        </form>
    </div>
{% endblock %}
{% block footer %}
    <script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
    {{ form.media }}
{% endblock %}

Solution

  • Your code seems to work fine for me, so the error must be somewhere else, probably somewhere in your CSS.

    Your code had two errors that prevented it from running though:

    1. on_delete is a required argument for ForeignKey since Django 2.0. Are you sure about the versions you are running?
    - user = models.ForeignKey(to=settings.AUTH_USER_MODEL)
    + user = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    
    1. I assume this one was a copy-paste error when creating the question
    - path("country-autocomplete/", CountryAutocomplete.as_view(create_field="name"),
    + path("country-autocomplete/", CountryAutocomplete.as_view(create_field="name"), name='country_autocomplete'),
    

    Here are additional details of my setup, perhaps you can find what is different from yours:

    Versions:

    Django==3.0.3
    django-autocomplete-light==3.5.0
    django-crispy-forms==1.9.1
    

    base.html:

    <!DOCTYPE html>
    <html>
        <head>
            <title>{% block title %}{% endblock title %}</title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
            <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
        </head>
        <body>
            {% block content %}
            {% endblock %}
            {% block footer %}
            {% endblock %}
        </body>
    </html>
    

    settings.py:

    # ...
    INSTALLED_APPS = [
        # ...
        'dal',
        'dal_select2',
        'crispy_forms',
        'yourappname'
    ]
    # ...
    # (everything else left at defaults)