Search code examples
djangodjango-modelsdjango-urls

How can I create in Django a custom absolute url for a predefined class


I need to make a blog in Django and I have a Blog class declared as follows:

models.py

class Blog(models.Model):
name = models.CharField(max_length=200, help_text='Enter name')
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)

The User class is a predefined Django class.

As you can see for Blogger I don't create a class but I use a default one from Django class User. In the template blog_list.html I use the following line to display the blog author with a link to the author page:

blog_list.html

<a href="/blog/blogger/{{ blog.author.id }}">{{blog.author.first_name}} {{blog.author.last_name}}</a>

wiews.py

class BlogListView(generic.ListView):
    model = Blog
    ordering = ['-date']
    paginate_by = 5

class BloggerDetailView(generic.DetailView):
    model = User

urls.py

urlpatterns = [
    path('', views.index, name='index'),
    path('blog/<int:pk>', views.BlogDetailView.as_view(), name='blog-detail'),
    path('blogs/', views.BlogListView.as_view(), name='blogs'),
    path('blogger/<int:pk>', views.BloggerDetailView.as_view(), name='blogger-detail'),
]

My question is how can I declare an absolute_url for blog.author to NOT use the manual constructed /blog/blogger/{{ blog.author.id }}?


Solution

  • You can make a proxy model [Django-doc], this is not a new (real) model. Behind the curtains, it uses the User model, but it converts it to Author objects, and we can add logic to that Author object:

    from django.contrib.auth.models import User
    
    
    class Author(User):
        class Meta:
            proxy = True
    
        def get_absolute_url(self):
            return reverse('blogger-detail', args=(self.pk,))

    and then use that proxy model in the ForeignKey instead:

    class Blog(models.Model):
        name = models.CharField(max_length=200, help_text='Enter name')
        author = models.ForeignKey(
            Author, on_delete=models.CASCADE, null=True, blank=True
        )

    then in the template, you use:

    <a href="{{ blog.author.get_absolute_url }}">link</a>