7

If I have a model like this:

class Article(models.Model):
    title = models.CharField(max_length=200)
    # ... rest of the code ...

    def get_absolute_url(self):
        return reverse('article-detail', args=[str(self.pk)])

and I have an url mapping like this:

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

In template should I use:

<a href="{{ article.get_absolute_url }}">{{ article.title }}</a>

or

<a href="{% url 'article-detail' article.pk %}">{{ article.title }}</a>

I'm still thinking both are good ideas, but which is the best?

In the first code I've written args=[str(self.pk)], why I must convert self.pk into string? URLs must be strings?

In my generic view, how do I use pk variable? I'm really confused with that slug_field, slug_url_kwarg, pk_url_kwarg, query_pk_and_slug.

Which matches which?

If I set query_pk_and_slug to True, slug_field = pk?

yierstem
  • 1,933
  • 5
  • 21
  • 42

2 Answers2

6

In my opinion,use

 <a href="{{ article.get_absolute_url }}">{{ article.title }}</a>

is better practice. If later on you want to change the url of this resource, you will do it once in your models function, and you would not search every template page for reference to this specific url. The philosophy behind this, is that the url for an article is a resource that belongs to the model of the article (django: Fat models and skinny controllers?)

A better approach, is to write

return reverse('article-detail', kwargs={'pk': self.pk})

This way, and when having multiple args in your url, you know every time the value of each arg (*args and **kwargs?)

I am not sure about the last part of your question. All in all, pk represents the primary key, which by default (and leave it as it) is the id (automatically produced by your database), and slug is a unique field in database (you specify it in your model definition) that represents a SlugField. Slug is used when you prefer more readable (seo) urls like /article/giannis-antetokounmpo-is-the-best, instead of /article/404.

For understanding how the class-based views work in django (better practice than function-based) take a look https://ccbv.co.uk/projects/Django/1.10/django.views.generic.detail/DetailView/ for example. When the GET (http method is called), the get function of the model is called as a result. If you notice, there is a self.get_object() function. In the definition of the get_object(), you can see the logic you are searching for. Specifically, in the comments, you can see all the ways, that View is trying to find the one and only object to return. You must choose one, by specifying the appropriate variables.

Community
  • 1
  • 1
  • About the last question, I'm just telling that I don't know how to use in generic view. In function-based views was simple, just specify it as arg: `def view(request, pk)` and use it to get articles in database like: `article = Article.objects.get(pk=pk)`. I don't understand how this works in class-based views. I must provide a `slug_field = pk` and `pk_url_kwarg = pk`, in this way, django knows that `Article.objects.get(slug_field=pk_url_kwarg)` or how this works? – yierstem Apr 21 '17 at 08:47
  • What `query_pk_and_slug` does? Check if there's `slug_url_kwarg`, if not, then check for `pk_url_kwarg`? – yierstem Apr 21 '17 at 08:54
1

url tag will do the reverse operation and generate a url path, where as get_absolute_url should be defined in a model as this is to get url for a particular object.

Here is a post explaining get_absolute_url

Sathish Kumar VG
  • 2,154
  • 1
  • 12
  • 19
  • I know what it does, I want to know which is the best method to do. Thanks. – yierstem Apr 21 '17 at 08:48
  • 1
    In an application life cycle the url and even models could change at any time, that's why to avoid changing the url (hardcoding) everywhere in the application `reverse` was introduced in Django. So that as long as the purpose of the url doesn't change, we don't have to worry about changing the name of the url. In your case there doesn't seem to be any need for using get_absolute_url as url tag will suffice your use case without making your app complex. [Simple is better than complex, complex is better than complexity - from zen of Python] – Sathish Kumar VG Apr 21 '17 at 12:28
  • @SathishKumarVG I believe this could use another discussion, as I do not see the benefits of using the url tag over get_absolute_url. For get_absolute_url to function, you're most likely anyway using reverse (... I assume) anyway. This means you're not using a hard-coded url, instead you're doing the exact same thing as with the url tag, but you saved yourself the hassle of writing out the arguments required for that url tag in the template. Therefore get_absolute_url seems like the cleaner solution to me. – Philipp Doerner Jul 23 '20 at 16:26