Django cannot access all objects in a model - python

My view looks like this:
class PageView(DetailView):
queryset = Page.objects.all()
template_name = 'page.html'
def get_context_data(self, **kwargs):
context = super(PageView, self).get_context_data(**kwargs)
context['category'] = Category.objects.all()
context['categoryitem'] = CategoryItem.objects.all()
return context
When in template I try to execute the given context variables like so {{ category }} it prints out [<Category: Something not so interesting>] aka model name + it's title, I presume the title gets printed out because I've set __unicode__(self): return self.title in the model.py, but I cannot access any other fields from the given object. category.id is blank as so is everything else. How can I access those?

Your code is:
context['category'] = Category.objects.all()
So it should be:
context['categories'] = Category.objects.all()
And in your template:
{% for category in categories %}
{{ category.name }}
{% endfor %}
The output you got in your test makes sense:
[<Category: Something not so interesting>]
it's an array with only one entry, this entry is an object of the class Category, and the string representation of it is "Something not ..."

You need to iterate over the category, since it's queryset. E.g. in your template, you can do
<ul>
{% for c in category %}
<li> {{ c }} </li>
{% endfor %}
</ul>

category in template is queryset ( list of objects) not one single object. You need to iterate over it as
{%for c in category %}
{{c.id}} : {{ c.other_attribute }}
{%endfor%}

Related

How to get all the fields from my model in Django

Here is my Model.py
class BlogModel(models.Model):
blog_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=1000)
content = FroalaField()
user = models.ForeignKey(User, blank=True , null=True , on_delete=models.CASCADE)
image = models.ImageField(upload_to='public')
created_at = models.DateTimeField(auto_now_add=True)
upload_to = models.DateTimeField(auto_now=True)
Here is my View.py
def my_blogs(request):
d = BlogModel.objects.all().filter(user = request.user)
return render(request,"my_blogs.html",{'message' : d})
But when I try to get the blog_id and created_at fields then it will shows an error that the requested fields are not present in the respective table.
But you can see that the field is n the table itself.
Please help
Here is the error i am getting
enter image description here
Django Queryset d is a list of objects. You have to loop through it:
for each_blog in d:
each_blog.blog_id
This is how you access the data for a filter method query set.
BlogModel.objects.all().filter(user = request.user) returns a query set i.e. a list of blogs satisfying the conditions.
You might want to iterate through all the blogs in order to display it, which can be done as follows:
{% for blog in d %}
{{ blog.blog_id }}
{% endfor %}
Try in views.py:
from .models import BlogModel
def my_blogs(request):
blogs = BlogModel.objects.all()
return render(request, 'my_blogs.html', locals())
In your html template my_blog.html try this:
{% for b in blogs %}
{{ b.id }}: {{ b.created_at }}
{% endfor %}
You can write in views.py:
def my_blogs(request):
# filtered queryset for login user
queryset = BlogModel.objects.filter(user=request.user)
return render(request,"my_blogs.html",{'blogs': queryset})
and in template my_blogs.html:
{% for blog in blogs %}
{{ blog.id }}
{{ blog.created_at }}
{% endfor %}
The BlogModel.objects.filter(user=request.user) returns a queryset which is list of your model objects. You can access object by iterating the queryset in template.

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

How to display multiple ForeignKey filtered items in a single view in django?

I'm trying to understand the best way to display ForeignKey filtered data in a Django model.
I have three models reduced to this:
// models.py
class Publisher(models.Model)
def publisher_name = models.TextField()
def publisher_slug = models.SlugField()
def founded_year = models.IntegerField()
class Album(models.Model)
def album_name = models.TextField()
def publisher = models.ForeignKey('Publisher', related_name='albums')
class Song(models.Model)
def song_name = models.TextField()
def album = models.ForeignKey('Album', related_name='songs')
def published_year = models.IntegerField()
I have a URL that is composed of: /<publisher>/<published_year>/
The view I'm having trouble composing is supposed to be details like this:
Title of: Publisher.publisher_name
List of All Albums by the publisher: List of All songs from that album published the same year as the publisher__published_year: List of All songs from that album published as the url
The way, I've tried to do this that works right now is similar to this:
// views.py
class SongYearView(TemplateView):
def get_context_data(self, **kwargs):
context = super(SongYearView, self).get_context_data(**kwargs)
context['publisher'] = Publisher.objects.get(slug=kwargs['publisher_slug']
album_list=[]
for album in context['publisher'].albums.all():
single_album = dict()
single_album['album'] = album
single_album['publisher_year_song'] = album.songs.filter(published_year=context['publisher'].published_year)
single_album['filtered_year_song'] = album.songs.filter(published_year=kwargs['published_year']
album_list.append(single_album)
context['albums'] = album_list
return context
Then in the template I'm doing (with stripped out formatting)
// template.html
{{ publisher.name }}
{% for album in albums %}
{{ album.album.album_name }}
{% for song in album.publisher_year_song %}
{{ song.song_name }}
{% endfor %}
{% for song in album.filtered_year_song %}
{{ song.song_name }}
{% endfor %}
{% endfor %}
While this does work, it's not pretty and I'm pretty sure there are better ways of doing this.
This is an odd example, but just a basic example of my more detailed models. The way to think about it is Publisher -> Album -> Song or A -> B -> C. And I'm trying to get a view of all B items, that are only linked with a specific A item and then get two sets of C items for each B item, where one set is filtered on an A property and the other set is filtered on a passed argument from a URL.
I tried to get a custom model.Manager to help get this constructed, but didn't have much luck.
You could do add a custom template filter of_year:
#register.filter
def of_year(songs, year):
return songs.filter(published_year=year)
And change your template to
// template.html
{{ publisher.name }}
{% for album in publisher.albums %}
{{ album.album.album_name }}
{% for song in album.songs|of_year:publisher.founded_year %}
{{ song.song_name }}
{% endfor %}
{% for song in album.songs|of_year:filtered_year %}
{{ song.song_name }}
{% endfor %}
{% endfor %}
And clean your view:
// views.py
class SongYearView(TemplateView):
def get_context_data(self, **kwargs):
context = super(SongYearView, self).get_context_data(**kwargs)
context['publisher'] = Publisher.objects.get(slug=kwargs['publisher_slug'])
context['filtered_year'] = kwargs['published_year']
return context
Edit: rename the template filter

Haystack search on a many to many field is not working

I'm trying to run a search on a model that has a many to many field, and I want to filter the search using this field.
here is my current code:
search_indexes.py
class ListingInex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
business_name = indexes.CharField(model_attr='business_name')
category = indexes.MultiValueField(indexed=True, stored=True)
city = indexes.CharField(model_attr='city')
neighborhood= indexes.CharField(model_attr='neighborhood')
state = indexes.CharField(model_attr='state')
address = indexes.CharField(model_attr='address')
zip_code = indexes.CharField(model_attr='zip_code')
phone_number = indexes.CharField(model_attr='phone_number')
def get_model(self):
return listing
def index_queryset(self, using=None):
return self.get_model().objects.all()
def prepare_category(self, obj):
return [category.name for category in obj.category_set.all()]
listing_text.txt
{{ object.business_name }}
{{ object.state }}
{{object.city}}
{{object.zip_code}}
{{object.phone_number}}
{{object.neighborhood}}
{% for category in obj.category.all %}
{{ category.name }}
{% endfor %}
I'm trying to do a simple search like:
search_results = SearchQuerySet().filter(category=query_text).filter
it returns an empty list. Thanks in advance.
Reading your code I think the problem is here:
{% for category in obj.category.all %}
{{ category.name }}
{% endfor %}
Category is not an object, is a MultiValueField. Maybe if you try something like:
{% for category in object.category.all %}
{{ category.name }}
{% endfor %}
object.category.all instead of obj.category.all. I'm not sure the solution is this, but I'm pretty sure the error could be in this 3 lines.

how to do a loop within a loop

Im trying to create a section in my application which contains a loop of catagories, and then the forms within that category. For example it should display like this:
Category 1
form 1
form 2
Category 2
form 3
But what im actualy getting is:
Category 1
form 1
form 2
form 3
Category 2
form 1
form 2
form 3
How can i fix this?
My view is:
def homepage (request):
Categories = Category.objects.all()
Forms = Form.objects.all()
output = {
'Category_Name': Categories,
'Form_Title': Forms,
}
return render_to_response('forms/home.html', RequestContext(request, output))
And my HTML is:
<ul>{% for c in Category_Name %}<li>{{ c.Name }}<ul>{% for c in Form_Title %}
<li>{{ c.Title }}</li>{% endfor %}</ul></li>{% endfor %}</ul>
if your forms are associated to a category via a foreignkey
class Form(models.Model):
...
category = models.ForeignKey(Category)
you could do something like this:
<ul>
{% for c in Category_Name %}
<li>{{ c.Name }}
<ul>
{% for form in c.form_set.all %}
<li>{{ form.Title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
take a look at the foreignkey documentation.
also note its not a good idea to use the same variable (c) in the outer and the inner loop,even if it works like in your example
and in python variable names are usually written lowercase
from django.shortcuts import render
def homepage (request):
categories = Category.objects.all()
return render(request, 'forms/home.html',
{'categories': categories})
There is a regroup template tag for this use case: https://docs.djangoproject.com/en/1.4/ref/templates/builtins/?from=olddocs#regroup
An additional advantage to use regroup is, that there is only ONE sql call involved. This might be an issue if you have many categories.

Categories