how to take input from form submission and use it to display an entry using django

Viewed 207

I'm trying to take the input from a form in Django and to then search storage and display any matches here is the code I have so far.

views.py

def search(request):
    input = request.GET.get('q')
    return render(request, "encyclopedia/search.html", {
        "entry": util.get_entry(input) == None,
        "display": util.get_entry(input)
    })

search.html

    {% extends "encyclopedia/layout.html" %}

    {% block title %}

    {% endblock %}

    {% block body %}



        {% if entry %}
            <div>No entry found</div>
        {% else %}
            <div>{{ display }}</div>
        {% endif %}


        {% endblock %}

layout.html

    <div class="row">
            <div class="sidebar col-lg-2 col-md-3">
                <h2>Wiki</h2>
                <form action="{% url 'search' %}" method="get">

                    <input class="search" type="text" name="q" placeholder="Search Encyclopedia">
                    <input type="submit">
                </form>
                <div>
                    <a href="{% url 'index' %}">Home</a>
                </div>
                <div>

urls.py

urlpatterns = [
    path("", views.index, name="index"),
    path("<str:name>", views.entry, name="entry"),
    path("search", views.search, name="search")

]

utils.py

def get_entry(title):
    """
    Retrieves an encyclopedia entry by its title. If no such
    entry exists, the function returns None.
    """
    try:
        f = default_storage.open(f"entries/{title}.md")
        return f.read().decode("utf-8")
    except FileNotFoundError:
        return None

It works with taking you to the search page but always displays no entry found even if the entry does exist.

This is my first project using Django so its pretty new, I'm assuming there is an issue with how I'm feeding in the form input to the util.get_entry() function.

After reading the documentation for forms in Django I still cant seem to find any reference about how to get this working. any help would be much appreciated.

After some further digging i've found that the line in views.py

input = request.GET.get('q')

is assigning the variable the value of 'search' each time instead of the user form input.

1 Answers

Django searches the urlpatterns in order.

if your urls.py look like this

urlpatterns = [
    path("", views.index, name="index"),
    path("<str:name>", views.entry, name="entry"),
    path("search", views.search, name="search")

]

then this line

path("<str:name>", views.entry, name="entry")

is telling django to match any url that is a string to be directed to the views.entry function. Because it is before

path("search", views.search, name="search")

when the url /search comes in it will always be directed to views.entry because it does match
"<str:name>" and 'search' will be assigned to name in that view function

# assuming your function looks something like this
def entry(request, name):
    ...

The search.html page is actually never being loaded and you are actually seeing entry.html every time as a result. This was probably unnoticeable because you've said both those pages have the same html.

The code

def search(request):
    input = request.GET.get('q')
    return render(request, "encyclopedia/search.html", {
        "entry": util.get_entry(input) == None,
        "display": util.get_entry(input)
    }) 

is never being run.

In order to fix this issue simply swap the paths in urlpatterns so that search comes first, like so.

urlpatterns = [
    path("", views.index, name="index"),
    path("search", views.search, name="search"),
    path("<str:name>", views.entry, name="entry")
    

]

also... a minor thing but I would rename input to something else like form_input. input is a built-in python function that you are overwriting with the query string.

also.. just a suggestion, rename {% if entry %} to {% if no_entry %} or something similar. It reads better logically, especially if someone else is going to be working with your code. again, just suggestions!

Related