Home > Back-end >  How to get different querysets in Django templates from Django views
How to get different querysets in Django templates from Django views

Time:08-22

In my blog app I want to allow unkown users to see articles, but I also want to allow logged users to see in the same page (somewhere else) their own articles; something like:

YOUR ARTICLES: list (only if user is logged)

ALL ARTICLES: list

Note that I need to show articles based on the user logged in because the url must be this:

path('<int:user_id>/', views.IndexView.as_view(), name='index'),

index.html:

{% if user.is_authenticated %}
   Your articles:
   <div >
        {% if article_list %}
            {% for article in article_list %}
                <div >
                    <div >
                        <div >
                            {{article.author}}
                        </div>
                        <div >
                            {{article.title}}
                        </div>
                        <div >
                            {{article.pub_date}}
                        </div>
                        <a href=" {% url 'blog_app:detail' user_id = user.id %} ">
                            <div >
                                Open article
                            </div>
                        </a>
                    </div>
                </div>
            {% endfor %}
        {% else %}
                <b>No articles!</b>
        {% endif %}
    </div>
{% endif %}

views.py:

class IndexView(ListView):
    model = Article
    template_name = 'blog_app/index.html'
    context_object_name = 'article_list'

    #return articles of a particular author
    def get_queryset(self):
        self.article = get_object_or_404(Article, author_id=self.kwargs['user_id'])
        return Article.objects.filter(
            author = self.article.author
        )

My question is: How can I get from IndexView two different querysets? One with all articles and one with articles filtered by author?

Bonus question:

Can I allow unkown users to reach the articles page if the url needs to specify the user id?

CodePudding user response:

Just use a standard context. Add this metod to you view (changing names, obviously):

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['book_list'] = Book.objects.all()
    return context

Bonus answer:

Well, anyone can enter every instance of such view. The only thing would be to change manually number in the browser, i.e. anyone can access this link:

http://example.com/1/

But if someone is not authenticated, that link: <a href=" {% url 'blog_app:detail' user_id = user.id %} "> would raise error, but of course cause of {% if user.is_authenticated %} it's not rendered anyway.

You need to set proper permissions to your view.

CodePudding user response:

After answers, this is one possible correct solution (don't focus on year and month filters, I added them but obviusly aren't related to the solution):

class IndexView(ListView):
    model = Article
    template_name = 'blog_app/index.html'
  
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['all_article_list'] = Article.objects.all()
        context['author_article_list'] = Article.objects.filter(
            pub_date__year = self.kwargs['year'],
            pub_date__month = self.kwargs['month'],
            author = self.kwargs['user_id']
        ).order_by('-pub_date')
        return context

In django templates I used these context names to iter articles:

Author articles:
{% if user.is_authenticated %}
   {% if author_article_list %}
            {% for article in author_article_list %}
             ...
            {% endfor %}
   {% endif %}
{% endif %}

All articles:
{% if all_article_list %}
            {% for article in all_article_list %}
             ...
            {% endfor %}
{% endif %}

CodePudding user response:

You need to specify:

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['all_articles'] = Article.objects.all()
    return context

Then you can also use an if statement in th template, to check if the {{all_articles}} exists.

"Can I allow unkown users to reach the articles page if the url needs to specify the user id?"

Unauthenticated users do not have an ID, this will result in an error. If you want users to go to the author of the current article being viewed, wouldn't it be {{article.author.id}}? (Not sure if this is what you want.)

CodePudding user response:

I think you can also override the get_queryset() method according to different conditions, so:

class IndexView(ListView):
    model = Article
    template_name = 'blog_app/index.html'
    context_object_name = 'article_list'

    
    def get_queryset(self):
        qs=super().get_queryset()
        if self.request.user.is_authenticated:
            article=get_object_or_404(Article,author_id=self.kwargs['user_id'])
            return qs.filter(author=article.author) #filtered queryset
        else:
            return qs #default queryset
  • Related