I have 2 models and I got the IndexView working properly using the get_context_data method. However my DetailView using the same technique is not working. How do I simply get 2 models into the DetailView?
views.py
from .models import CharacterSeries, CharacterUniverse
class IndexView(generic.ListView):
template_name = 'character/index.html'
context_object_name = 'character_series_list'
def get_queryset(self):
return CharacterSeries.objects.order_by('name')
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['character_universe_list'] = CharacterUniverse.objects.order_by('name')
return context
class DetailView(generic.DetailView):
model = CharacterSeries
template_name = 'character/detail.html'
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context['character_universe_list'] = CharacterUniverse.objects.all()
return context
I am missing something; I need to get CharacterUniverse into the DetailView. I have tried using this page's information to no avail.
Thanks all.
UPDATE:
detail.html
<ul>
{% for series in characterseries.character_set.all %}
<li>{{ series.name }}</li>
{% endfor %}
</ul>
<ul>
{% for universe in characteruniverse.character_set.all %}
<li>{{ universe.name }}</li>
{% endfor %}
</ul>
index.html
{% load staticfiles %}
<link rel ="stylesheet" type="text/css" href="{% static 'character/style.css' %}" />
<h1>Character Series</h1>
<ul>
{% for character_series in character_series_list %} {# for MODEL in .. #}
<li>{{ character_series.name }}</li>
{% endfor %}
</ul>
<h1>Character Universe</h1>
<ul>
{% for character_universe in character_universe_list %} {# for MODEL in .. #}
<li>{{ character_universe.name }}</li>
{% endfor %}
</ul>
An example from the official documentation: This is not possible in my case?
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
Perhaps this is the final solution? This is not working though.. Naming wrong?
ALL THE UPDATES
views.py
from django.shortcuts import get_object_or_404, render
from django.views import generic
from django.views.generic import DetailView
from .models import CharacterSeries, CharacterUniverse
class IndexView(generic.ListView):
template_name = 'character/index.html'
context_object_name = 'character_series_list'
def get_queryset(self):
return CharacterSeries.objects.order_by('name')
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['character_universe_list'] = CharacterUniverse.objects.order_by('name')
return context
class SeriesDetail(DetailView):
model = CharacterSeries
template_name = 'character/series_detail.html'
class UniverseDetail(DetailView):
model = CharacterUniverse
template_name = 'character/universe_detail.html'
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.SeriesDetail.as_view(), name='series_detail'),
url(r'^(?P<pk>[0-9]+)/$', views.UniverseDetail.as_view(), name='universe_detail'),
]
index.html
{% load staticfiles %}
<link rel ="stylesheet" type="text/css" href="{% static 'character/style.css' %}" />
<h1>Character Series</h1>
<ul>
{% for character_series in character_series_list %}
<li>{{ character_series.name }}</li>
{% endfor %}
</ul>
<h1>Character Universe</h1>
<ul>
{% for character_universe in character_universe_list %}
<li>{{ character_universe.name }}</li>
{% endfor %}
</ul>
series_detail.html
<ul>
{% for series in characterseries.character_set.all %}
<li>{{ series.name }}</li>
{% endfor %}
</ul>
universe_detail.html
<ul>
{% for universe in characteruniverse.character_set.all %}
<li>{{ universe.name }}</li>
{% endfor %}
</ul>
Explanation of why you can't use one view for both models
A DetailView is meant to display details about an object from one model. It's fine to include extra context, but the view isn't designed to handle two possible models.
The example from the docs is showing the details for one publisher, and displaying all the books at the same time.
Your DetailView lets you show the details for one CharacterSeries, and display all of the CharacterUniverse at the same time.
However, you cannot use that same view to display details for one CharacterUniverse. You need a different view to display details for one CharacterUniverse
Solution
Therefore, you need two different detail views, one for each model.
You need a distinct url for each view. Otherwise, the request will always match the first regex (in this case series_detail. The following would work.
url(r'^series/(?P<pk>[0-9]+)/$', views.SeriesDetail.as_view(), name='series_detail'),
url(r'^universe/(?P<pk>[0-9]+)/$', views.UniverseDetail.as_view(), name='universe_detail'),
Related
I've been doing some django these past weeks and I'm having a problem.
I have a page where Articles are shown. No problem while reovering all articles from db. But now I'd like to get all categories (an Article has a category) that I have in my database.
So I can display like this in my page:
List of categories
-cat1
-cat2
-cat3
List of articles
-art1
-art2
-art3
But I don't know how to do with both queries.
Here's what I've tried.
class IndexView(generic.ListView):
template_name = 'eduardoApp/index.html'
context_object_name = 'article_list'
def get_queryset(self):
return Article.objects.order_by('article_name')
def get_categories(request):
category_list=Category.objects.all()
context = {'category_list':category_list}
return render(request,'eduardoApp/index.html',context)
And in my view:
<h2>List of categories</h2>
{% if category_list %}
{% for category in category_list %}
<p>{{ category.name }}</p>
{% endfor %}
{% else %}
<p>no categorys</p>
{% endif %}
<h2>List of articles</h2>
{% if article_list %}
<div class="flex-container">
{% for article in article_list %}
<div>{{ article.article_name }}</div>
{% endfor %}
</div>
{% else %}
<p>No articles...</p>
{% endif %}
{% endblock %}
In my view I keep seeing no categorys displayed (since category_list does not exist but don't know why and how to fix)
ListView is creating context with 'objects' as queryset get_queryset returns.
I suppose your custom method get_categories hasn't been used anywhere?
Best practice here is to override get_context_data method like...
class IndexView(generic.ListView):
...
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['category_list'] = ...
return context
in a view that allows you to filter by element such as searches and especially filters by category or by series is it possible to make a pagination? if yes you can give me a view which uses it
Yes. A ListView [Django-doc] can do this, since the pagination is done on the result of get_queryset. Hence you can implement this as:
from django.views.generic.list import ListView
from app.models import MyModel
class MyModelListView(ListView):
model = MyModel
paginate_by = 10
template_name = 'some_template.html'
def get_queryset(self, **kwargs):
qs = super().get_context_data(**kwargs)
return qs.filter(some_field__icontains=self.request.GET.get('search', ''))
If you both paginate and search, then there are two items in the querystring,, hence the pagination URLs are more cumbersome:
{% for object in object_list %}
{{ object }}
{% endfor %}
{% if page_obj.has_previous %}
previous
{% endif %}
{% if page_obj.has_next %}
Next
{% endif %}
With Django 1.10 I am building a blog/portfolio hybrid website. Besides Mysite, I have two apps, Blog and Portfolio. Within blog/templates/ I have an index.html that displays content from both Blog and Portfolio (the 15 most recent blog posts and 5 most recent portfolio projects).
So the index.html page looks like this:
http://imgur.com/y2UqBSS
As you can see data is not appearing. However, it does when I navigate to the Blog page and Portfolio page. For example, the Blog page:
http://imgur.com/7P922Ga
I am figuring that this issue is related to the mult-level extends that I have going on. Because the Blog and Portfolio pages both display content from the database, it makes me think that the models are O.K but something is up with the views. The index.html extends the base_generic.html template, and my recent_blog_posts.html and recent_portfolio_pieces.html extends the index.html.
I am not sure how to remedy this issue. Any suggestions what I'm doing wrong?
Project structure
mysite/
---blog/
------static/
---------css/
---------images/
------------blogpostimages/
------------favicon.ico
------templates/
---------blog/
------------blog_post.html
------------blog_list.html
------------recent_blog_posts.html
---------base_generic.html
---------index.html
---------bio.html
---------resume.html
------admin.py
------apps.py
------models.py
------tests.py
------urls.py
------views.py
---portfolio/
------static/
---------css/
---------images/
------------portfoliopieceimages/
------templates/
---------portfolio/
------------portfolio_piece.html
------------portfolio_list.html
------------recent_portfolio_pieces.html
------admin.py
------apps.py
------models.py
------tests.py
------urls.py
------views.py
---mysite/
------settings.py
------urls.py
------wsgi.py
manage.py
db.sqlite3
requirements.txt
blog/views.py
from django.shortcuts import render
from django.views import generic
# Create your views here.
from .models import Blog
def index(request):
"""
View function for home page of site.
"""
# Generate most recent blog post
title = Blog.objects.all()
post_date = Blog.objects.all()
get_absolute_url = Blog.objects.all()
# Render the HTML template index.html with the data in the context variable.
return render(
request,
'index.html',
context={'title': title,
'post_date': post_date,
'get_absolute_url': get_absolute_url,
}
)
def recent_blog_posts.html(request):
blog = Blog.objects.order_by('-post_date')[0:11]
return render(request, 'index.html', {'blog': blog})
class BlogListView(generic.ListView):
"""
Generic class-based view for a list of blog posts.
"""
model = Blog
paginate_by = 20
def get_queryset(self):
return Blog.objects.order_by('-post_date')
class BlogDetailView(generic.DetailView):
"""
Generic class-based detail view for a blog post.
"""
model = Blog
def bio(request):
return render(
request, 'bio.html'
)
def resume(request):
return render(
request, 'resume.html'
)
index.html
<div>
<h2>Recent Blog Posts</h2>
<div>
{% block blogs %}
{% if blog_list %}
{% for blog in blog_list %}
<article>
<header>
<h4><small>{{blog.post_date}} ยป </small>{{ blog.title }}</h4>
</header>
</article>
{% endfor %}
{% else %}
<p>Unfortunately, there are no blog posts yet.</p>
{% endif %}
</div>
{% endblock %}
</div>
<div>
<h2>Portfolio</h2>
{% if portfolio %}
{% for portfolio in portfolio %}
<div class="col-xs-12 col-sm-6 thumb">
<a class="thumbnail" href="{{ portfolio.get_absolute_url }}">
{% load static %}
<img class="img-responsive" src="{{ portfolio.cover_image }}" alt="">
<p>{{ portfolio.title }}</p>
<p>{{ portfolio.client_name }}</p>
</a>
</div>
{% endfor %}
{% else %}
<div>
<p>Unfortunately, there are no portfolio pieces yet.</p>
</div>
{% endif %}
You must use the variable pass to your context, in your template.
So you have to pass the variable blog_list to your context to iterate on it in your template.
Example below: (only for blog_list)
def index(request):
"""
View function for home page of site.
"""
blog_list = Blog.objects.all()
# Render the HTML template index.html with the data in the context variable.
return render(request, 'index.html', context={'blog_list': blog_list})
You need to pass the data to the template in the context. I don't really understand what you're trying to do in the index by setting and passing the variables in the context:
# Generate most recent blog post
title = Blog.objects.all()
post_date = Blog.objects.all()
get_absolute_url = Blog.objects.all()
Blog.objects.all() returns a queryset with all blog instances, not a title/post_date/get_absolute_url of a single blog instance.
In the template you refer to two context variables: blog_list and portfolio. You don't set the variables in the index. I would also avoid a statement like that:
{% for portfolio in portfolio %}
Don't use the same variable name as the variable you iterate over, change the latter to portfolio or portfolio_list.
To make it work you might try this:
index.py
def index(request):
blog_list = Blog.objects.all()
portfolio_list = Portfolio.objects.all()
return render(request, 'index.html',
context={'blog_list': blog_list, 'portfolio_list': portfolio_list}
)
In the index.html file change:
{% for portfolio in portfolio %}
to
{% for portfolio in portfolio_list %}
I'm a django newbie and wanted to integrate Singly into the django Polls application. I have used class based views to allow for models from the singly app to be passed along with the Polls models.
The problem is, I'm unable to get data from the Singly model even when data is present inside the database.
For now I simply want to display the access_token and profile ID of the user profile.
Here is my Views.py code: (only the view in question)
class IndexView(ListView):
context_object_name='latest_poll_list'
queryset=Poll.objects.filter(pub_date__lte=timezone.now) \
.order_by('-pub_date')[:5]
template_name='polls/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['user_profile'] = UserProfile.objects.all()
return context
This is my urls.py:
urlpatterns = patterns('',
url(r'^$',
IndexView.as_view(),
name='index'),
url(r'^(?P<pk>\d+)/$',
DetailView.as_view(
queryset=Poll.objects.filter(pub_date__lte=timezone.now),
model=Poll,
template_name='polls/details.html'),
name='detail'),
url(r'^(?P<pk>\d+)/results/$',
DetailView.as_view(
queryset=Poll.objects.filter(pub_date__lte=timezone.now),
model=Poll,
template_name='polls/results.html'),
name='results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote', name='vote'),
)
And here is my index.html:
{% load staticfiles %}
<h1>Polls Application</h1>
<h2>Profile Info:</h2>
<div id="access-token-wrapper">
<p>Here's your access token for making API calls directly: <input type="text" id="access-token" value="{{ user_profile.access_token }}" /></p>
<p>Profiles: <input type="text" id="access-token" value="{{ user_profile.profiles }}" /></p>
</div>
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li>{{ poll.question }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Its able to fetch Polls correctly but it doesn't print anything in either textboxes i.e. the user_profile.access_token and the user_profile.profiles.
I think the problem is incorrect rendering of the template. It should pass the context 'user_profile' but its not. Or for some reason its not taking the data from the database, because there is an entry in the UserProfile database.
I would be grateful for your help, people.
The user_profile context variable contains list of UserProfile objects. From code:
context['user_profile'] = UserProfile.objects.all() # will return a QuerySet, that behaves as list
And in template it is accessed as if it is a single object:
{{ user_profile.access_token }}
{{ user_profile.profiles }}
So either put to this variable a single UserProfile object in a view. For example:
if self.request.user.is_authenticated()
context['user_profile'] = UserProfile.objects.get(user=self.request.user)
else:
# Do something for unregistered user
Either iterate over profiles in template:
{% for up in user_profile %}
{{ up.access_token }}
{% endfor %}
Either access to profile by index in template:
{{ user_profile.0.access_token }}
I'm trying to get to grips with class based views.
I have urls.py as follows:
urlpatterns = patterns('homework.views',
(r'^index/$', 'index'),
url(r'^(?P<sub_slug>\w+)/$', NavListView.as_view(), name='nav'),
url(r'^(?P<sub_slug>\w+)/(?P<class_grp_slug>\w+)/$', SubNavListView.as_view(), name='subnav'),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),)
I have my views.py:
# Subject navigation
class NavListView(ListView):
template_name = 'templates/home.html'
def get_queryset(self):
self.subject = Subject.objects.all()
return self.subject
def get_context_data(self, **kwargs):
context = super(NavListView, self).get_context_data(**kwargs)
context['subjects'] = self.subject
return context
# Class group navigation
class SubNavListView(NavListView):
def get_queryset(self):
self.group = Group.objects.filter(subject__name__iexact=self.kwargs['sub_slug'])
return self.group
def get_context_data(self, **kwargs):
context = super(NavListView, self).get_context_data(**kwargs)
context['groups'] = self.group
return context
In my 'templates/home.html' I have:
{% extends 'templates/base.html' %}
{% load url from future %}
{% block nav-menu-items %}
<ul class="nav">
{% for sub in subjects %}
<li class="">{{ sub }}</li>
{% endfor %}
<li class="active">Add Subject</li>
</ul>
{% endblock nav-menu-items %}
{% block class_groups_nav %}
<div class="tabbable">
<ul class="nav nav-tabs">
{% for group in groups %}
<li>
<a data-toggle="tab" href="{% url 'subnav' sub_slug class_grp_slug %}">{{ group }}</a>
</li>
{% endfor %}
<li>Add</li>
</ul>
{% endblock class_groups_nav %}
I'm trying to achieve a 'nav' of subjects, then a 'subnav' below showing a tab for each class group for the subject selected in the navigation above.
I've tried different ways of doing this such as making Subject.objects.all() available as context processors. I have also attempted to subclass NavListView so I can inherit the previous context, making them available in SubNavListView.
At the moment, I'm getting a NoReverseMatch error where the url named 'nav' is not passing the sub_slug and so I can't use it in the url in the template.
Any thoughts on getting this working?
Many thanks,
Assuming your Subject model has field named slug in it, you need to update your code to
<li class="">{{ sub }}</li>
ie. pass an appropriate parameter to {%url ... %}. Change sub.slug to whatever field name you want to refer to.
If you want to, you can also do {% url 'nav' sub_slug=sub.slug %}.
You are trying to pass sub_slug, but which is not defined in the template context, and result in empty string. So nav url will not get any parameter.
I see similar problem in your other {%url ...%} tags in the template.