Profile features are a central part of our app: users should be able to customize their profile, to visit other profiles, and to view the articles written by a given user.
In the templates folder, create profile_detail.html:
1 2 3 4 5 6 7 8 910111213141516171819
{% extends 'base.html' %}
{% block title %}
<title>{{ profile.user.username }} - Conduit: Django + HTMX</title>
{% endblock %}
{% block content %}
<divclass="profile-page"><divclass="user-info"><divclass="container"><divclass="row"><divclass="col-xs-12 col-md-10 offset-md-1"><imgsrc="{{ profile.image }}"class="user-img"alt="{{ profile.user.username }}"/><h4>{{ profile.user.username }}</h4><p>{{ profile.bio|default:"This user doesn't have a bio for now" }}</p></div></div></div></div></div>
{% endblock %}
Everything should be working now, right? Let's check by going to localhost:8000/profile/@admin, for example. Welp, we're getting an error:
The error tells us that our ProfileDetailView wants to be called with an object primary key or a slug, while we're calling it with a username. The solution is simple: we just change how the view decides which objects to show.
We override the view's get_object method by adding the following to users/views.py:
1 2 3 4 5 6 7 8 9101112
# ...fromdjango.shortcutsimportredirect,get_object_or_404# ...classProfileDetailView(DetailView):model=Profiletemplate_name="profile_detail.html"defget_object(self,queryset=None):# newusername=self.kwargs.get("username",None)# newprofile=get_object_or_404(User,username=username).profile# newreturnprofile# new
Let's try again: we should see an actual profile page (though there isn't much on it yet). Make sure to set a profile image for your admin user, as everyone else should have a default already set.
Whenever we visit a user's profile, we want to see all the articles written by that specific user. We could make a ListView, but passing the list to our DetailView's context is simpler.
In users/views.py, override the get_context_data method of ProfileDetailView:
This will return all the articles written by the user whose username is specified in the URL: for example, /profile/@admin will return all the articles written by admin. Technically, we could have obtained this queryset directly in the template with something like {{ profile.articles.order_by|dictsortreversed:"created_at" }}, but dealing with logic in views makes for clearer code and easier debugging.
Expose the article_list.html template in templates/profile_detail.html:
{% extends 'base.html' %}
{% block title %}
<title>{{ profile.user.username }} - Conduit: Django + HTMX</title>
{% endblock %}
{% block content %}
<divclass="profile-page"><divclass="user-info"><divclass="container"><divclass="row"><divclass="col-xs-12 col-md-10 offset-md-1"><imgsrc="{{ profile.image }}"class="user-img"alt="{{ profile.user.username }}"/><h4>{{ profile.user.username }}</h4><p>{{ profile.bio|default:"This user doesn't have a bio for now" }}</p></div></div></div></div><divclass="container"><!-- new from here --><divclass="row"><divclass="col-xs-12 col-md-10 offset-md-1"><divclass="articles-toggle"><ulclass="nav nav-pills outline-active"><liclass="nav-item"><spanclass="nav-link"> My Articles
</span></li></ul></div> {% include 'article_list.html' with articles=my_articles %}
</div></div></div><!-- new to here --></div>
{% endblock %}
{% if user.is_authenticated %}
<liclass="nav-item">
{% url 'editor_create' as editor_create %}
<ahref="{{ editor_create }}"rel="prefetch"class="nav-link {% if request.path == editor_create %}active{% endif %}"><spanclass="ion-compose"> New Post </span></a></li><liclass="nav-item"><!-- new from here --> {% url 'profile_detail' username=user.username as profile %}
<ahref="{{ profile }}"rel="prefetch"class="nav-link {% if request.path == profile %}active{% endif %}"><imgsrc="{{ user.profile.image }}"class="user-pic"alt="{{ user.username }}"> {{ user.username }}
</a></li><!-- new to here --><liclass="nav-item"><arel="prefetch"href="{% url 'logout' %}"class="nav-link"><spanclass="ion-log-out"></span></a></li>
{% else %}
In templates/article_detail.html:
1 2 3 4 5 6 7 8 9101112
<divclass="article-meta"><ahref="{% url 'profile_detail' username=article.author.user.username %}"><!-- new --><imgsrc="{{ article.author.image }}"alt="{{ article.author.user.username }}"/><!-- new --></a><!-- new --><divclass="info"><ahref="{% url 'profile_detail' username=article.author.user.username %}"class="author"><!-- from <span class="author"> --> {{ article.author.user.username }}
</a><!-- from </span> --><spanclass="date">
{{ article.created_at|date:"D M d Y" }}
</span></div>
In templates/comment_container.html:
1 2 3 4 5 6 7 8 9101112
<divclass="card-footer"><ahref="{% url 'profile_detail' username=comment.author.user.username %}"class="comment-author"><!-- new --><imgsrc="{{ comment.author.image }}"class="comment-author-img"alt="{{ comment.author.user.username }}"/><!-- new --></a><!-- new --><ahref="{% url 'profile_detail' username=comment.author.user.username %}"class="comment-author"><!-- from <span class="comment-author"> --> {{ comment.author.user.username }}
</a><!-- from </span>--><spanclass="date-posted">
{{ comment.created_at|date:"D M d Y" }}
</span>
{% include 'comment_delete.html' %}
</div>