0

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 class="container py-5">
        {% if article_list %}
            {% for article in article_list %}
                <div class="container">
                    <div class="row">
                        <div class="col">
                            {{article.author}}
                        </div>
                        <div class="col">
                            {{article.title}}
                        </div>
                        <div class="col">
                            {{article.pub_date}}
                        </div>
                        <a href=" {% url 'blog_app:detail' user_id = user.id %} ">
                            <div class="col">
                                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?

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
Davide
  • 93
  • 7

4 Answers4

2

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 %}
Davide
  • 93
  • 7
  • 2
    For kwargs, do `self.kwargs.get('Year')`, this way if none are returned on the filter, you can still render the page without error. (If you want that, at least. ) – nigel239 Aug 21 '22 at 10:08
1

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.)

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
nigel239
  • 1,485
  • 1
  • 3
  • 23
1

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.

NixonSparrow
  • 6,130
  • 1
  • 6
  • 18
  • @SunderamDubey Suggesting manipulating `get_queryset` when it needs multiple querysets is obviously wrong and is not a good thing ;) – NixonSparrow Aug 21 '22 at 12:15
  • Yes, you are right but I see it as another approach. What about [this](https://stackoverflow.com/questions/71763256/django-how-to-return-multiple-querysets-with-get-queryset-listview) question? – Sunderam Dubey Aug 21 '22 at 12:18
  • 1
    Even if I agree with the approach, It's still bad idea for unexperienced developer and I believe downvoting is created exactly for such situations. – NixonSparrow Aug 21 '22 at 12:25
  • Anyway, I agree with you :) – Sunderam Dubey Aug 21 '22 at 12:27
-1

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
Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
  • It would work if you wanted to show only one output between all articles and author articles. I tested it and in template for both cases I iterate **article_list** (check my answer above to see the original html structure). I see in both areas only author articles. Maybe I should do other changes? **N.B:** you forgot **.get** after kwargs. – Davide Aug 21 '22 at 10:34
  • @Davide Corrected thanks, haven't looked before. Also added link from docs. – Sunderam Dubey Aug 21 '22 at 10:39