0

I have the below urlpatterns in the root's url.py:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls'), name="api_app"),
]

where api app contains:

app_name="api_app"

urlpatterns = [

    url(r'^users/', views.UserList.as_view()),
    url(r'^users/(?P<user_type>[a-zA-Z_]+)$', views.UserList.as_view(), name="filter_type"),

    ...,
]

the first url displays a list of users and the second url accepts a user type and filters the user list with the user_type

These both work fine when I put the urls in a browser's address bar. However when I try to reference the second url from a django template like so:

<form action="{% url "api_app:filter_type" user_type %}" method="GET">
    <select name="user_type" class="userType">
        <option value="none">Select user type</option>
        <option value="A">A/option>
        <option value="B">B</option>
        <option value="C">C</option>
    </select>

            <input type="submit" value="Submit">

        </form>

The below error occurs:

NoReverseMatch at /api/users/
Reverse for 'filter_type' with arguments '('',)' not found. 1 pattern(s) tried: ['api/users/(?P<user_type>[a-zA-Z_]+)$']

why is that? aren't the namespaces configured correctly?

The problem apparently is that user_type is not defined anywhere which I understand. But with the above <Select> tag how can I define user_type to be the selected option in html?

update

This is my view that I want to pass the user_type data to:

class UserList(APIView):

    renderer_classes = [TemplateHTMLRenderer]

    def get(self, request, user_type=None):
        filters = {}
        if user_type:
            filters['user_type'] = user_type

        users = User.objects.filter(**filters)

        serializer = UserSerializer(users, many=True)

        return Response({"data": json.dumps(serializer.data)}, template_name="users.html")
Community
  • 1
  • 1
bcsta
  • 1,963
  • 3
  • 22
  • 61
  • It seems to me that you are passing the wrong kind of argument to `'filter_type'`, since it is recognised. What is the value of user_type here? – Nico Griffioen Oct 17 '19 at 07:29

2 Answers2

0

The problem is not the namespacing; it's the parameters. You are passing user_type, but that is either empty or (more likely) not defined where you are using it, so it doesn't match against the expected parameter.

Edit You're confused. You're putting /api/users into the browser and going to that page. On that page, you have a call to {% url "api_app:filter_type" user_type %} which is trying to generate a link; but user_type is empty so that cannot work.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • the probem is that the error is being called when I run `/api/users` in the url which should call the first url pattern and work normally right? – bcsta Oct 17 '19 at 07:33
  • But your first URL doesn't have a name. `filter_type` only refers to the pattern with a parameter. – Daniel Roseman Oct 17 '19 at 07:33
  • why do I need to put a name for the first url pattern? I am not referencing it from anywhere, I am just putting `api/users/` in the browser and the error occurs – bcsta Oct 17 '19 at 07:35
  • how can I define user type to be the selected option in the dropdown list? (updated question) – bcsta Oct 17 '19 at 08:48
  • user_type is be default empty when I first go to the url `api/users/` in that url then, there is a form to actually populate user_type and submit `api/user/`. I might be populating user_type wrong. How should I do that? . . . On the other hand, why can't I go to `api/users/` without any error and then when I submit the form, the error occurs if I am populating `user_type` badly? – bcsta Oct 17 '19 at 08:53
0

You have defined your url like this

url(r'^users/(?P<user_type>[a-zA-Z_]+)$', views.UserList.as_view(), name="filter_type")

Therefore when you do a reverse lookup of the url, it requires parameters which match the regex pattern [a-zA-Z_]+

Looking at your code, you are passing user_type to the url

<form action="{% url "api_app:filter_type" user_type %}" method="GET"></form>

However, it is throwing this error

NoReverseMatch at /api/users/
Reverse for 'filter_type' with arguments '('',)' not found. 1 pattern(s) tried: ['api/users/(?P<user_type>[a-zA-Z_]+)$']

This means user_type is either an empty string or undefined. user_type needs to be a string which matches the pattern [a-zA-Z_]+ for you to be able to perform a reverse match on the url.

EDIT This is how I would do it using a view

<form action="view_user_type" method="POST">
    <select name="user_type" class="userType">
        <option selected="selected" disabled>Select user type</option>
        <option value="A">A/option>
        <option value="B">B</option>
        <option value="C">C</option>
    </select>
    <input type="submit" value="Select"
</form>


# forms.py

class UserTypeForm(forms.Form):
    USER_TYPE_CHOICES = (
        ('A', 'A'),
        ('B', 'B'),
        ('C', 'C'),
    )

    user_type = forms.ChoiceField(choices = USER_TYPE_CHOICES)


# views.py

from django.core.urlresolvers import reverse
from .forms import UserTypeForm

def view_user_type(request):
    if request.method == 'POST':
        form = UserTypeForm(request.POST)
        if form.is_valid():
            user_type = form.cleaned_data.get('value')
            return redirect(reverse('api_app:filter_type', args=(user_type,)))
Mikey Lockwood
  • 1,258
  • 1
  • 9
  • 22
  • I updated the question with what the form is accepting. How can I define user_type to be the selected option in the dropdown list? – bcsta Oct 17 '19 at 08:47
  • @user7331538 What functionality are you trying to achieve? For example do you want it to redirect to that user_type page when selecting A from the dropdown? – Mikey Lockwood Oct 17 '19 at 09:01
  • when selecting A from the dropdown and then submit, All I want is to redirect to `api/users/A`. Somehow this simple task is proving to be not so simple. – bcsta Oct 17 '19 at 09:06
  • @user7331538 I have updated my answer. You should pass the selection to a view and handle the redirect there – Mikey Lockwood Oct 17 '19 at 09:44
  • but what if I have to use GET? – bcsta Oct 17 '19 at 09:54
  • POST is just used to pass data to the view. The redirect from the view will be a GET – Mikey Lockwood Oct 17 '19 at 09:56
  • But I can still pass data to a get right? why cant I do that. I already have a class based view with a `def get(self, request, user_type=None)`. Can I pass the data to the this parameter in the get function? (i'll show this in the question) – bcsta Oct 17 '19 at 10:00
  • I don't know if this works, but you may be able to change your current implementation to `` so it doesn't try to do a get request on the `None` option when loading the page. I've added this to the answer – Mikey Lockwood Oct 17 '19 at 10:23
  • but this is still using a POST method. i am using a get in the class based view – bcsta Oct 17 '19 at 10:34