user2170928
user2170928

Reputation: 247

django reverse not found

I just want to call a view funciton from a template, and I've seen that I have to do it with the reverse function. I want to pass a parameter to the view function, but I don't want to show it in the url. Is it possible? Here is my code and the error:

urls.py

url(r'^perfil/deleteDownloadedTrack/$','principal.views.delete_downloaded_track', name='delete_downloaded_track'),

views.py

def delete_downloaded_track(request, track):    
    ...
    return HttpResponseRedirect(reverse('profile_detail'))

template.html

{% for track in downloadedTracks %}
    <tr> 
        <td>
            {{track.name}} 
        </td>
        <td> 
            <div class="botoForm" onclick="location.href='{% url "principal.views.delete_downloaded_track" track %}'"> Eliminar </div>
        </td>
{% endfor %}

and the error:

Reverse for 'principal.views.delete_downloaded_track' with arguments '(<DownloadedTrack: DownloadedTrack object>,)' and keyword arguments '{}' not found.

Thanks!!

Upvotes: 0

Views: 1005

Answers (2)

knbk
knbk

Reputation: 53719

The recommended way by the HTML standard to handle any request that changes data on the server, is to use a POST request.

{% for track in downloadedTracks %}
    <tr> 
        <td>
            {{track.name}} 
        </td>
        <td> 
            <form method="POST" action="{% url principal.views.delete_downloaded_track %}" id="delete-form-{{ track.id }}">
                {% csrf_token %}
                <input type="hidden" name="track_id" value="{{ track.id }}" />
                <div class="botoForm" onclick="document.getElementById('delete-form-{{ track.id }}').submit()"> Eliminar </div>
            </form>
        </td>
{% endfor %}

The {% csrf_token %} prevents cross-site forgery requests by validating that the person you send this form to is also the person sending it back through a POST request. Just retrieve the id in your view by using:

if request.method == 'POST':
    id = request.POST.get("track_id", None)
    track = Track.objects.get(id=id)

Data send through POST will not show in the url.

Upvotes: 2

quekshuy
quekshuy

Reputation: 638

If you don't wish to show the parameter in your URL, then you probably want to pass it in as a query parameter, e.g.

<host_and_path>/perfil/deleteDownloadedTrack/?track_id=<some_track_id>.

So your view would look like this:

def delete_downloaded_track(request):
    track_id = request.GET.get('track_id')
    # get track based on track_id and delete it.

and your template like this (assuming you pass in the reverse of delete_downloaded_track as delete_url in the template context):

{% for track in downloadedTracks %}

    <!-- template code -->

    {% with delete_url|add:"?track_id="|add:track.id as url_with_id %}
        <a href="{{url_with_id|safe}}">Delete</a>
    {% endwith %}

{% endfor %}

Upvotes: 1

Related Questions