JohnnyQ
JohnnyQ

Reputation: 543

return a queryset just for the row in the database to loop through

I have 2 lists of equal size elements that I want to join and then output to my Django template.

But I'm having trouble identifying the row so just that row is printed.

I am trying to zip the two lists and then create a new list that will loop through onto the template page.

When I use the variable on the template like the code below It works fine but I want to be able to loop through the list.

I know this is incorrect as not all the elements are printed to the template but it creates the desired result.

                    <p> {{ news.esp_article.0 }}</p>
                    <p> {{ news.eng_article.0 }}</p>
                    <hr>
                    <p> {{ news.esp_article.1 }}</p>
                    <p> {{ news.eng_article.1 }}</p>
                    <hr>
                    <p> {{ news.esp_article.2 }}</p>
                    <p> {{ news.eng_article.2 }}</p>
                    <hr>
                    <p> {{ news.esp_article.3 }}</p>
                    <p> {{ news.eng_article.3 }}</p>
                    <hr>
                    <p> {{ news.esp_article.4 }}</p>
                    <p> {{ news.eng_article.4 }}</p>

To try to solve it here is my views.py And I'm almost certain my problem is my queryset result.

class ArticleViewPage(DetailView):
       model = Newspapers
       template_name = 'rtves/article.html'
       context_object_name = 'news'

       eng_articles = Newspapers.objects.values_list('eng_article') 
       esp_article =  Newspapers.objects.values_list('esp_article')

       zip_scripts = list(zip(eng_article,  esp_article))

       context.update(
                 zip_scripts = zip_scripts

          )          

Then I get the full raw data of every row in the database enter image description here

here is my template file:

 {% for text1, text2 in zip_scripts %}

     <p>{{ text1 }}</p>
     <p>{{ text2 }}</p>                           

 {% endfor %}

Here is my URL pattern file which is working correctly

path('newspapers/articles/<slug:pk>/', ArticleViewPage.as_view(), name='Articles'),

I know the problem is my queryset and it's pulling in too much detail but I have tried filtering and about 20 other things

here is my models both objects I'm trying to print to the template are saved ass ArrayFields

class Newspapers(models.Model):

   esp_article = ArrayField(models.CharField(max_length=8000, blank=True))**
   eng_article = ArrayField(models.CharField(max_length=8000, blank=True))**

Thanks

Upvotes: 0

Views: 97

Answers (3)

Nikolai R Kristiansen
Nikolai R Kristiansen

Reputation: 617

You are running zip on the top level list, the Newspapers queryset in a list of lists, instead of the two lists of articles (eng_articles and esp_articles).

class ArticleViewPage(DetailView):
    model = Newspapers
    template_name = 'rtves/article.html'
    context_object_name = 'news'

    def get_context_data(self, **kwargs):
        zip_scripts = zip(self.object.eng_articles, self.object.esp_articles)

        context = super().get_context_data(**kwargs)
        context.update(zip_scripts=zip_scripts)
        return context

This is assuming ArticleViewPage should only show English and Spanish articles for a single newspaper at a time.

As an alternate solution you could instead of zipping the articles in the view's get_context_data method, make the zipped articles available on the model like so:

class Newspapers(models.Model):
   esp_articles = ArrayField(models.CharField(max_length=8000, blank=True))
   eng_articles = ArrayField(models.CharField(max_length=8000, blank=True))

    @property
    def articles_zipped(self):
        return zip(self.esp_articles, self.eng_articles)

and update your template to use the new model property:

{% for article_spanish, article_english in news.articles_zipped %}
  <p>{{ article_spanish }}</p>
  <p>{{ article_english }}</p>
{% endfor %}

Upvotes: 1

Nikolai R Kristiansen
Nikolai R Kristiansen

Reputation: 617

In your querysets you should use values() to get a list of dicts with each dict corresponding to a row in the database. Then, in your template, you can use . to access a single column value (for each row).

views.py:

class ArticleViewPage(DetailView):
    model = Newspapers
    template_name = 'rtves/article.html'
    context_object_name = 'news'

    def get_context_data(self, **kwargs):
        eng_articles = Newspapers.objects.values('eng_articles')
        esp_articles = Newspapers.objects.values('esp_articles')

        zip_scripts = zip(eng_articles, esp_articles)

        context = super().get_context_data(**kwargs)
        context.update(zip_scripts=zip_scripts)
        return context

rtves/article.html:

{% for article_eng, article_esp in zip_scripts %}
  <p>{{ article_eng.text }}</p>
  <p>{{ article_esp.text }}</p>
{% endfor %}

I'm not sure what your models.py looks like. Are you fetching a list of related articles in English and Spanish for a single newspaper or all newspapers? Note: It is recommended to use singular nouns as model names, that is Newspaper without the s at the end.

Upvotes: 0

engin_ipek
engin_ipek

Reputation: 917

You need to add a simple code to fix your queryset. values_list returns a tuple. In order to make it return a list, you need to add flat=True.

Try this:

eng_articles = Newspapers.objects.values_list('eng_article', flat=True) 
esp_article =  Newspapers.objects.values_list('esp_article', flat=True)

Upvotes: 0

Related Questions