Having a bit of trouble getting my Django app to display how I'd like it. My model looks like this:
class City (models.Model):
city_name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.city_name
class Portfolio(models.Model):
portfolio_name = models.CharField(max_length=20, unique=True)
city = models.ForeignKey(City, db_constraint=False, on_delete=models.CASCADE)
def __str__(self):
return self.portfolio_name
class Property (models.Model):
portfolio = models.ForeignKey(Portfolio, db_constraint=False, on_delete=models.CASCADE)
prop_name = models.CharField(max_length=250, unique=True)
def __str__(self):
return self.prop_name
I want my template to display each City, and under each City have its Portfolios, and under each portfolio have its Properties. I'm a bit new to Django, coming from AngularJS where I could do it like this to throw filters in my loops(obviously doesn't work in Django, at least how I'm doing it):
<ul>
{% for city in all_cities %}
<li>
{{ city.city_name }}
<ul>
{% for portfolio in all_portfolios| portfolio.city = city %}
<li>
{{ portfolio.portfolio_name }}
<ul>
{% for property in portfolio.all_properties| property.portfolio = portfolio%}
<li>
{{ property.prop_name }}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Any ideas? There is probably a simple solution that I just can't verbalize yet. The only thing I've found to do it like this is to create a custom queryset for each city, then for each portfolio, but there has to be a better way to do this.
Ignoring the fact that it is not database efficient to do this, the easiest way is to just make sure you are accessing the reversed Foreign Key relationships correctly.
Do something like this:
{% for city in all_cities %}
...blah blah blah
{% for portfolio in city.portfolio_set.all %}
... Blah blah
{% for property in portfolio.property_set.all %}
... More blah
And you should be good to go
Related
Can you please help. That's the question. I have a menu, the name of the menu is 'catr' and there is a submenu 'subcat' , I want to make the entire menu list output, and if the menu id matches the menu, then a subcategory is output, but I don't understand how to implement it.Help please.Sorry if I didn't explain it clearly, I hope you will understand, thank you in advance
Here's what I tried to do
enter image description here
enter image description here
From what I can understand you can do this using functions in your models like this...
class Category(models.Model):
name = models.CharField(max_length=100 db_index=True)
slug= models.SlugField(max_length=255, unique=True, db_index=True, verbose_name = 'URL')
def ___str__(self):
return self.name
def get_absolute_url(self):
return reverse('category' kwargs={'cat_slug':self.slug})
def get_sub_category(self):
return Subcategory.objects.filter(parent_category=self)
class Meta:
verbose_name = 'Kатегоpии'
verbose_name_plural = 'Kaтегоpии'
ordering = ['id']
and in your templates do this...
{% for item in catr %}
<li>
{{item.name}}
{% if item.get_sub_category %}
<ul>
{% for child in item.get_sub_category %}
<li>{{ child.sub }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
Suppose that we have following models
class Category(models.Model):
name = models.CharField(max_length=254)
class Item(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="items")
name = models.CharField(max_length=254)
state = models.ForeignKey(State, on_delete=models.CASCADE)
Categories and their items are listed like so
def view(request):
categories = Category.objects.all()
pass
{% for category in categories %}
{{ category.name }}
{% for item in category.items.all %}
{{ item.name }}
{% endfor %}
{% endfor %}
In this structure, I want to write on-request filtering for listed 'items'.
def view(request):
...
queryset = ???
state = request.GET.get('state')
if state:
queryset = queryset.filter(state__name=state)
The problem is defining 'queryset'. Because, Items are listed as related objects of category.
Can it be done properly? or Do I need to change design?
You can take a look at my design to be more clear.
Low fidelity design
Your related_name in the Item object for category field should be named "items". Then category.items.all will give you the list of items in that category. Look at the example in the documentation.
class Tag(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name="tags",
)
name = models.CharField(max_length=255)
To filter items depending on category you can pass the PKs of the category in the request and filter according to those specific categories.
views.py
def your_view(request):
...
list_of_your_category_ids = [1,4] #get them as a list from frontend
list_of_your_state_names = [1,2]
queryset = Item.objects.filter(
category__in=list_of_your_category_ids,
state__code__in=list_of_your_category_names
)
This will give you the queryset you wanted. Now all you need is to regroup this queryset with their categories.
Django provides a regroup template tag that does exactly this.
{% regroup queryset by category as categories_list %}
<ul>
{% for category in categories_list %}
<li>
{{category.grouper}}
<ul>
{% for item in category.list %}
<li>
{{item}}: state - {{item.state.code}}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
https://i.stack.imgur.com/TbTpz.png
I'm trying to display a photographic session with all of it photos, so I have the session name in one model and I have the pictures in
another model linked by a foreign key. I'm not able to display it in
the HTML I'm not sure if I'm using the ListView get_context_data
correctly and I'm certainly sure the the html code is not correct but
I have not found how to do it.
views.py
class SessionPictures(generic.ListView):
model = PostSession
template_name = 'photoadmin/gallery.html'
def get_context_data(self, **kwargs):
context = super(SessionPictures, self).get_context_data(**kwargs)
context['picture'] = Images.objects.all()
return context
models.py
class PostSession(models.Model):
session_name = models.CharField(max_length=25)
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.session_name)
class Images(models.Model):
name = models.ForeignKey(
PostSession, related_name='images', on_delete=models.CASCADE, null=True, blank=True)
picture = models.ImageField(upload_to='pictures')
html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h2>Images</h2>
<ul>
{% for session in object_list %}
<li>{{ session.session_name }}</li>
<ul>
<li>{{session.picture_set.all.url}}</li>
</ul>
{% endfor %}
</ul>
{% endblock %}
I'm expecting this:
Woods
picture1.url
picture2.url
picture3.url
Beach
Picture4.url
picture5.rul
As you already defined related_name="images" in Images model, so, session.images_set attribute won't work with PostSession.
class Images(models.Model):
name = models.ForeignKey(
PostSession,related_name='images', on_delete=models.CASCADE, null=True, blank=True)
Instead, use session.image.all in template(FYI: it returns a queryset, so you need to iterate through it to get the image object):
{% for session in object_list %}
<li>{{ session.session_name }}</li>
<ul>
{% for i in session.images.all %}
<li> i.picture.url </li>
{% endfor %}
</ul>
{% endfor %}
More information on reverse relation can be found in documentation.
This is mainly working (thanks to a lot of help on a previous question. Sort children into parent in django template
Now I would like to sort sub-children objects into the children objects and then sort the children into their parent. Specifically, I want to sort schools into cities into their respective state. Then, I want the schools to display into the right city in its correct state. What I am looking for would like like this:
State
--- City
-----School
-----School
-----School
--- City
-----School
-----School
-----School
--- City
-----School
-----School
-----School
Right now, I have the cities sorting into the state. However, I cannot figure out to make the schools sort into the city. I am reading up on filters in the documentation. I think the answer lies there. However, I when try to filter the schools into the city, no objects come back.
Is there a way to retrieve the 'school_list' as a child of 'city_list' while still keeping the 'city_list a child of the states ? I would love to learn how.
Edit: Added the School model. Sorting the schools by name inside a city would be ideal.
Any and all help would be appreciated.
Edit: dkarchmer's solution worked perfectly. Thanks again. Hopefully, this will be useful to someone else in the future.
models.py
class State(models.Model):
state_name = models.CharField(max_length=20, default='')
state_slug = models.SlugField()
state_image = models.ForeignKey(Image, null=True)
state_summary = models.TextField(null=True)
def __str__(self):
return self.state_slug
class City(models.Model):
city_name = models.CharField(max_length=55, default='')
city_slug = models.SlugField()
state_image = models.ForeignKey(Image, null=True)
school_image = models.ForeignKey(Image, null=True, related_name='+')
state = models.ForeignKey(State, null=True)
def __str__(self):
return self.city_slug
def def sorted_schools(self):
return self.school_set.all().order_by('school_name')
class School(models.Model):
school_name = models.CharField(max_length=55, default='')
school_slug = models.SlugField()
city = models.ForeignKey(City, null=True)
def __str__(self):
return self.school_slug
views.py
class CityInStateView(ListView):
model = City
template = 'template.html'
slug_field = 'state_slug'
context_object_name = 'city_in_state_list'
def get_context_data(self, **kwargs):
context = super(CityInStateView, self).get_context_data(**kwargs)
context['state'] = self.object
context['city_list'] = self.object.city_set.all().order_by('city_name')
return context
urls.py
urlpatterns = [
url(r'^$', SchoolIndexView.as_view(), name='school_index'),
url(r'^(?P<state_slug>[\w-]+)/$', CityInStateView.as_view(), name='state_index'),
]
template.html
{% block main_content %}
<div class="row body">
<div class="main_content">
<div class="row">
<h1>{{ state.state_name }}</h1>
{% for city in city_list %}
<h2>{{ city.city_name }}</h2>
{% for school in city.sorted_schools %}
<h3>{{ school.school_name }} </h3>
{% endfor %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
This has been kicking my butt for a week. Please explain it to me like I a m five. I appreciate all of your help in advance.
The easiest is to just add a method to the City model to return Schools:
class City(models.Model):
...
def sorted_schools(self):
return self.school_set.all().order_by('school_name')
And then use that directly from the template:
<div class="row body">
<div class="main_content">
<div class="row">
<h1>{{ state.state_name }}</h1>
{% for city in city_list %}
<h2>{{ city.city_name }}</h2>
{% for school in city.sorted_schools %}
<h3>{{ school.school_name }} </h3>
{% endfor
{% endfor %}
</div>
</div>
</div>
If you don't want to add that method to the Model, the second alternative is to use a templatetag to basically do the same.
So I am just now getting to grips with Django,
I want to something relatively straughtforward. I have a model thus:
class Article(models.Model):
id = models.IntegerField(primary_key=True)
volnumber = models.IntegerField(db_column='volNumber')
title = models.TextField()
keywords = models.TextField(blank=True)
start_page = models.IntegerField(null=True, blank=True)
end_page = models.IntegerField(null=True, blank=True)
author_1 = models.TextField(blank=True)
author_2 = models.TextField(blank=True)
author_3 = models.TextField(blank=True)
author_4 = models.TextField(blank=True)
author_5 = models.TextField(blank=True)
author_6 = models.TextField(blank=True)
author_7 = models.TextField(blank=True)
author_8 = models.TextField(blank=True)
author_9 = models.TextField(blank=True)
author_10 = models.TextField(blank=True)
in my view:
def index(request):
article_list = Article.objects.all()
volume_list = Volume.objects.all()
auth_list = ['author_1', 'author_2', 'author_3', 'author_4', 'author_5', 'author_6', 'author_7', 'author_8', 'author_9', 'author_10', ]
return render_to_response('index.html', {
'article_list': article_list,
'volume_list': volume_list,
'auth_list' : auth_list,
})
and I want to iterate over the first articles authors, as well as eliminating empty entries for the list in the template:
<ul class="articleList">
{% for article in article_list %}
<li>
{% for author in auth_list %}
<i>{{ article."author" }}</i>
{% endfor %}
{{ article.title }}{{ article }}
</li>
{% endfor %}
</ul>
obviously that doesn't work, and I'm not sure the template is the place for this logic, but I hope from this it is clear what I am trying to achieve.
Any assistance much appreciated.
I am not sure you want to design a list of authors that way. If you want multiple authors, consider using a new model for Author and then using a ManyToManyField in your Article class to link articles to authors. Then, you can loop through authors in your template like so:
{% for author in article.authors.all %}
<!-- blah blah -->
{% endfor %}
Here is the Author model:
class Author(models.Model):
first_name = models.TextField(...) # don't copy to ..., put whatever params you need
last_name = models.TextField(...)
and the adjusted Article model:
class Article(models.Model):
# add this line
authors = models.ManyToManyField(Author)
Now you do not need to return an auth_list in your view code.
If you don't want to change your data model (although I strongly advice you to follow #andrew-lee suggestion) you are not allowed to call-by-name attributes in the templates. You should do:
# in the view
return render_to_response('index.html', {
'article_list': article_list,
'volume_list': volume_list,
'auth_list' : [getattr(article, name) for name in auth_list],
})
# in the template
{% for author in auth_list %}
<i>{{ author }}</i>
{% endfor %}
Building on what has already been said, it makes the most sense to change your model, but if you want to keep it as-is and display a list of only the author fields which have been filled in, you might do this in the template:
<ul class="articleList">
{% for article in article_list %}
<li>
{% for author in auth_list %}
{% if author %}
<i>{{ author }}</i>
{% endif %}
{% endfor %}
{{ article.title }}{{ article }}
</li>
{% endfor %}
</ul>