0

I am writing a very basic web page in Python which has a text box where a user can type in a username, then hit the Ok button which submits a form using a GET request. The GET passes the username as an argument and searches the auth_user table in the database.

My problem is I am not able to pass the username argument, please help if you can Django 2.0 url patterns

urls.py

app_name = 'just_gains'
    urlpatterns = [
        path('lifecoaching', views.LifeCoach, name='life_coaching'),
        path('lifecoaching/resultslifecoaching/<str:user_name>', views.LifeCoachSearchResults, name='results_life_coaching'),
    ]

forms.py

class LifeCoachSearch(forms.Form):
    user_name = forms.CharField(label='Username', max_length=100, required = False)

views.py

def LifeCoach(request):
    if request == 'GET':
        form = LifeCoachSearch(request.GET)
        if form.is_valid:
            user_name = form.cleaned_data['user_name']
            LifeCoachSearchResults(request,user_name)

    else:
        form = LifeCoachSearch()
        return render(request, 'just_gains/life_coaching.html', {'form': form})

def LifeCoachSearchResults(request, user_name):

    testUser = User.objects.filter(username__startswith=user_name)
    context = {'TestUser': testUser}
    return render(request, 'just_gains/results_life_coaching.html', context)

HTML (lifecoaching)

<form action="{% url 'just_gains:results_life_coaching' %}" method="GET" >
    {% csrf_token %}
    {{ form }}     
    <input type="submit" value="OK">
</form>

HTML (resultslifecoaching)

<ul>
    <li><a>print usernames that match the argument</a></li>
</ul>
DManDev
  • 33
  • 1
  • 5
  • re_path('lifecoaching/resultslifecoaching/(?P[\w.@+-]+)/', views.LifeCoachSearchResults, name='results_life_coaching'), ofc you have to import re_path next to path – LeLouch Jan 28 '18 at 22:15

2 Answers2

1

Forgive me for the short response as I am on mobile. Try passing your username as a string in the path using <str:user_name>

jdewerth
  • 564
  • 3
  • 9
  • Thanks for your response @Riptide34, I have updated my issue to reflect the "str:", however this does not fix the issue. – DManDev Jan 28 '18 at 22:10
0

Usually I think the form should submit via POST rather than GET, and the value of the submitted username would then be available in the dictionary request.POST['username']. GET should be used to get forms from the server; POST posts information back to the server. POST ensures that the browser bundles everything in the form and sends it complete, but GET tries to encode it in the URL and makes no guarantees.

Using forms, its helpful to have the View divide so that GET requests pull up blank or prepopulated forms (the empty search box) and POST requests are processed and redirected to the parameterized results screen you have.

You would then create a httpRedirect to re-assign the request to your URL with a parameter. I think this link, example 2 is the right way to go.

https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#redirect

So your function would look like:

def LifeCoach(request):
    if request.method = 'GET':
       return render(request, 'just_gains/life_coaching.html', context)
    elif request.method = 'POST':
       # I have skipped form validation here for brevity        
       return redirect('results_life_coaching',request.POST['username'])

It's possible that having a field called username may clash with or confuse you later when using request.USER['username']. Don't forget to change your form html! All the best!

[Edit 1] My code was wrong; GET should call the lifecoaching form, POST should redirect to the results_life_coaching page.

[Edit 2] My suggestions for your templates:

HTML (lifecoaching.html)

<form action="{% url 'just_gains:life_coaching' %}" method="POST" >
    {% csrf_token %}
    {{ form }}     
    <input type="submit" value="OK">
</form>

HTML (resultslifecoaching.html)

<ul>
 {% for item in username_list %}
    <li>{{item.user_name}} - {{item.achievement}} </li>
 {% endfor %}
</ul>
Atcrank
  • 439
  • 3
  • 11
  • Thanks @Atcrank, should i be putting the name of my argument (user_name) in my form html - where it has
    – DManDev Jan 28 '18 at 23:22
  • Sorry, I just looked back at my answer and had to make a correction. – Atcrank Jan 29 '18 at 00:00
  • because I had made GET go to 'results' instead of the input form. You don't need to put the parameter name in the URL first time round - instead POST it in the request to the View. Named URL parameters are used to create a more specific page for a user that you can send the browser to from anywhere. For example, you could just always send users to their own page by making the results view filter on username=request.USER['username']. Your line in the comment won't work, 'user_name' would need to be rendered into the url, but can't be because its not part of the context available to render – Atcrank Jan 29 '18 at 00:11
  • Getting there, @Atcrank I made all the changes, getting this exception though: Exception Type: NoReverseMatch Exception Value: Reverse for 'results_life_coaching' not found. 'results_life_coaching' is not a valid view function or pattern name. It's in my url patterns as above with the name = 'results_life_coaching' – DManDev Jan 29 '18 at 01:05
  • It might be that the view name should be called with the app namespace, like so: 'just_gains:results_life_coaching.' You will find you usually need to do this in templates too. – Atcrank Jan 29 '18 at 03:12