3

I am using Django 1.10.6 and trying to generate a url from a javascript function in datatables

under url.py I have an page called profile setup like:

app_name = 'myapp'

urlpatterns = [
    url(r'^profile/(?P<pk>[0-9]+)/$', views.ProfileView.as_view(), name='profile'),
]

In javascript I have a django query send data to a variable and the data is displayed on a table with name and id fields:

var django_dat =[
    {
        "id": 1,
        "name":       "Jack Spicer",
    },
    {
        "id":2,
        "name":       "Ted Cracker",
    }
    {
        "id":3,
        "name":       "Justin Rollin",
    }
    {
        "id":4,
        "name":       "Boaty Boat",
    }
];

$(document).ready(function() {
    var table = $('#dattable').DataTable({
        data: django_dat,
        columns: [{
          'data': null,
          'render': function(data, type, row, meta)  {
            //Django URL
            return '<a href={% url 'myapp:profile' 2 %}>' + data.name + '</a>';}},
             {
          data: 'id'
        }]
    });
});

I am trying to change the URL so it link the name to a url like {% url 'myapp:profile' data.id %}. The above code is hardcoded to id=2 and works.

Tried changing it to:

return '<a href={% url 'myapp:profile' '+ data.id+ ' %}>' + data.name + '</a>' 

But that gave an No Reverse match error Reverse for 'profile' with arguments '('+ data.id+ ',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['profile/(?P<pk>[0-9]+)/$']

Also tried using the replace function:

return '<a href={% url 'myapp:profile' uid %}>'.replace('uid', data.id) +  data.name + '</a>'

but got the same error

3 Answers 3

7

This is not a technical problem but a problem with understanding how urls work in Django and JavaScript. Remember, the template html file is parsed and rendered by Django first. Django doesn't care about JavaScript syntax - it just views it as more text. Once the page is rendered, it's sent to the browser where it's interpreted and the JavaScript run. And when that process is underway, Django is totally out of the picture. The browser never gets to see Django template tags. So there are two distinct phases to the process - Django template rendering, followed by JavaScript running in the browser.

When you use the Django {% url %} tag, you are asking Django to parse and render a URL which it will look up using its inbuilt URL resolvers. Your profile url requires an id variable, and the error message you are getting is telling you that Django is trying and failing to resolve the url with the variable you have given it - which looks to be a JavaScript string concatenation. Again, Django doesn't understand JS, so you're effectively giving it a bunch of junk characters.

So, the only way to get your {% url %} tag to work is to give it a real user id, which is what Django needs to look up a relevant URL. But in your case, Django won't know what that user id is until you select the user in JavaScript.

Some possible ways to get a valid url in JavaScript are:

  1. To build it dynamically (using string concatenation of a hard-coded url pattern). You lose maintainability with this method but it will be the fastest to implement. If you change your url structure in future you'll have to remember to come back and change it here.
  2. To initially deliver from Django a list of valid urls and then select from that list when you select a user. This will be a good solution if your list of users is small and will avoid the problem of hard coding the url.
  3. To have a get_profile_url_for_user (or whatever) API endpoint, where upon selecting a user in JS, an ajax request is sent with that user id to a generic url which will do the url resolution in Django and return the specific url for that user's profile. This would be my preferred method if you have potentially hundreds of users on the page.

Edit - Coming back to this after 3 years - I guess I have learned something in the meantime! There is a fourth option which seems a lot better: 4. Assuming your list of user data originates from your Django application in the first place - you could include in that object the profile url for each user by reversing the url wherever in your Django app the users are being serialised to JSON.

{
    "id":4,
    "name": "Boaty Boat",
    "profile_url": "http://django-host/profile/4"
}
Sign up to request clarification or add additional context in comments.

1 Comment

I guess I am stuck with option 1, Thanks
0

If I'm understanding this right, I think you might just want to do this:

return "<a href={% url 'myapp:profile' " + data.id + ' %}>' + data.name + '</a>' 

In your current form, myapp:profile would be interpreted as a javascript variable because you are unquoting due to your nested single quotes ( and it is not a valid javascript variable name).

3 Comments

Unless you give the url tag a valid user id as an argument in python, it will fail. The quotes don't make any difference, in fact the correct syntax doesn't use any quotes around the variable - it would just be {% url 'myapp:profile' data.id %} if data was a python object.
@P Ackerman forgot to mention I tried that too and got an error Could not parse the remainder: '"' from '"'
oh, then you probably just need to generate the URL path as it would be used in the browser, rather than this Django string interpolation pattern.
0

So I tried 2 solutions for generating the URL using JavaScript function:

function linkgen(app_page, link_id, display_txt){
    let tag_head ="<a href={% url '",
        tag_head2 =" %}>",
        tag_tail ='</a>'
    return tag_head.concat(app_page,"' ", link_id, tag_head2, display_txt, tag_tail )
}

function hardgen(app_page, link_id, display_txt){
    let tag_head ="<a href='http://localhost:8000/",
        tag_head2 ="/'>",
        tag_tail ='</a>'
    return tag_head.concat(app_page,"/", link_id, tag_head2, display_txt, tag_tail )
}

The first one generates a Django style {% URL link %} the second generates a hard http:// link. The hard link works fine. But you must be sure to change the base url when doing production.

return hardgen('profile', data.id, data.name)

But the django generated link is does some funny stuff.

{ data: null, "render": function(data, type, row, meta) {
                console.log(linkgen('myapp:profile', data.id, data.name))
            return  linkgen('myapp:profile', data.id, data.name)
             ; }},

The console log returns the correct link if you paste it in the return it will work but the generated string does not due to how django is set up.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.