I'm struggling to show on a webpage some model objects I created from the admin pages on my site.
I combed through the relevant django tutorial page but nothing I've tried works to show the model objects on the page.
Here is my models.py:
from django.db import models
from datetime import datetime
from datetime import timedelta
# Create your models here.
def get_deadline():
return datetime.today() + timedelta(days=3)
class JobPost(models.Model):
created_at = models.DateTimeField(auto_now_add=True, blank=True)
deadline = models.DateField(default=get_deadline)
wordcount = models.IntegerField()
jobtaken = models.BooleanField(default=False)
# client = models.User.username
class Meta:
ordering = (
# ("jobtaken"),
("-created_at"),
)
def publish(self):
self.pub_date = timezone.now()
self.save()
def __str__(self):
return "Job #{}".format(self.pk)`
views.py:
from django.shortcuts import render
from django.views.generic import TemplateView
#from django.contrib.auth.decorators import staff_member_required
from .models import JobPost
from django.utils import timezone
# Create your views here.
# #staff_member_required()
# class JobBoardView(TemplateView):
# template_name = "jobs.html"
# posts = JobPost.objects.filter(published_date__lte=timezone.now()).order_by('pub_date')
#changed published_date to pub_date in .models
def jobs(request):
#posts = JobPost.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
latest_post_list = JobPost.objects.order_by('-pub_date')
context = {
'deadline': deadline,
'created_at': created_at,
'wordcount':wordcount,
'jobtaken':jobtaken,
'JobPost':JobPost,
'latest_post_list':latest_post_list,
}
return render(request, 'jobs.html', context=context)
urls.py:
from django.contrib import admin
from django.urls import path, re_path, include
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from jobboard import views
from login import views
urlpatterns = [
path('admin/', admin.site.urls),
#re_path(r'^login/$', auth_views.login(template_name = 'accounts/login.html'), name='login'),
re_path(r'^signup/$', views.signup, name='signup'),
path('login/', include('login.urls')),
path('', views.index, name='index'),
path('accounts/', include('django.contrib.auth.urls')),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
path('jobs/', views.jobs, name='jobs')
]
Here is my template(jobs.html):
{% extends "base.html" %}
{% block content %}
{% if latest_post_list %}
<ul>
{% for post in latest_post_list %}
<li>{{ JobPost }}</li>
{% endfor %}
</ul>
{% else %}
<p>No posts are available.</p>
{% endif %}
{% endblock content %}
I tried various templates, including some really simple ones to test, e.g.
{% if latest_post_list %}
<p>hello</p>
{% else %}
<p>No posts are available.</p>
{% endif %}
but everything I try returns the 'else' part of the if statement. Nothing will show the objects on the webpage.
You have a made a few mistakes which I will list below:
Your query method is wrong. It should be:
latest_post_list = JobPost.objects.all().order_by('-pub_date')
or
latest_post_list = JobPost.objects.filter(something=something).order_by('-pub_date')
2. latest_post_list is not an object, it is a query of JobPost objects. If you wish to iterate them in the template, you can just pass it to the template and do the iteration from the query. However,
context = {
'deadline': deadline, # you cannot access deadline (which deadline?)
'created_at': created_at, # same as above
'wordcount':wordcount, # same as above
'jobtaken':jobtaken, # same as above
'JobPost':JobPost, # You are sending the class to the template which is wrong
'latest_post_list':latest_post_list, # the only thing you need!
}
If you wish to loop through the objects of the query in the back-end, you have to do the following:
for post in latest_post_list:
print(post.deadline) # will print the deadline of each JobPost one by one
If you wish to loop through the objects of the query and display them in the template, you have to do this:
{% for post in latest_post_list %}
<p>{{ post.deadline }} - {{ post.created_at }}</p>
{% empty %}
<p>There is no post yet!</p>
{% endfor %}
There is no need to user if in the backend or use {{ JobPost }}. if the query is empty, the {% empty %} will be effective.
RoboBear was correct, it was a name collision in the urls.py file. This fixed the error:
change to from jobboard import views as job_views and change the url line to path('jobs/', job_views.jobs, name='jobs').
Changing this raised exceptions in the views.py file for all the context dictionary entries except for
context = {
'latest_post_list':latest_post_list,
}
as Ramtin suggested.
Then I changed the template to
<ul>
{% for post in latest_post_list %}
<li>{{ post }}</li>
</ul>
{% empty %}
<p>No posts are available.</p>
{% endfor %}
as Ramtin suggested.
Related
I want to make elided page pagination like 1,2,3...8,9,10. So here is my code
in models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
in views.py
from django.shortcuts import render
from .models import Author
from django.core.paginator import Paginator
def author(request):
authors = Author.objects.all()
paginator = Paginator(authors, 2)
page_number = request.GET.get("page")
authors_data = paginator.get_page(page_number)
elided_page = paginator.get_elided_page_range(page_number, on_each_side=3,on_ends=2)
context = {
"authors" : authors_data,
"elided_data" : elided_page,
}
return render (request, "authors.html", context)
in author.html
# all authors
{% for author in authors %}
<p> {{author}}</p>
{% endfor %}
# pagination part
{% for i in elided_data %}
{{i}}
{% endfor %}
this way I get elided pagination like 1,2,3...9,10 perfectly. But problem is when i click on three dot (...) then it shows me pageNotAnInteger error. Is there any way to disable the link of that three dot?
After spending so much time and research I discovered the answer.
so in views.py remove elided_page variable and elided_data key from context dict.
from django.shortcuts import render
from .models import Author
from django.core.paginator import Paginator
def author(request):
authors = Author.objects.all()
paginator = Paginator(authors, 2)
page_number = request.GET.get("page")
authors_data = paginator.get_page(page_number)
context = {
"authors" : authors_data,
}
return render (request, "authors.html", context)
and in author.html
# retrive all authors
{% for author in authors %}
<p> {{author}}</p>
{% endfor %}
# pagination part
{% for i in authors.paginator.get_elided_page_range %}
{% if i == authors.paginator.ELLIPSIS %}
<span class="page-link">...</span>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
I had another post related to this but my code was complex so the communication was difficult. I completely stripped off the issue from the unnecessary details and came up with a very minimal example shown below:
templates/base.html:
<html>
<body>
<p>I am base.html</p>
{% block content %}
{% endblock content %}
</body>
</html>
templates/blog.html:
{% extends 'base.html' %}
{% block content %}
<p>I am blog.html</p>
{{ blog_list }}
{% for blog in blog_list %}
{{ blog.title }}
{% endfor %}
{% endblock %}
And blog/views.py
from django.views import generic
from .models import Blog
class BlogList(generic.ListView):
queryset = Blog.objects.filter()
template_name = 'blog.html'
# context_object_name = 'blog_list'
class BlogDetail(generic.DetailView):
model = Blog
template_name = 'blog.html'
That outputs this:
I was expecting the list of blog titles to be rendered there. I debugged the BlogList class and queryset value was this:
<QuerySet [<Blog: First Page>, <Blog: Intro>]>
So, the query is not empty. I have been completely frustrated by this issue. Anyone know what's going on?
Edit: Here is blog/urls.py:
urlpatterns = [
path('<str:parent>/<slug:slug>/', views.BlogDetail.as_view(), name='blog'),
]
And project urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('qa.urls')),
path('blog/', include('blog.urls')),
]
After some clues given by #Abdul Aziz Barkat, I realized the problem is I should be linking to the BlogDetail view instead of BlogList view. So, I changed urlpatterns of blog/urls.py to:
urlpatterns = [
path('<str:parent>/<slug:slug>/', views.BlogDetail.as_view(), name='blog_list'),
]
The problem now is BlogList is not being rendered anymore, but we don't need BlogList anymore - we can create a queryset inside BlogDetail and provide the queryset as a context. To achieve that I added a queryset variable and a get_context_data method to BlogDetail:
class BlogDetail(generic.DetailView):
model = Blog
template_name = 'blog.html'
queryset = Blog.objects.filter()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['blog_list'] = self.queryset
return context
I am trying to populate a navbar "dropdown-menu" with individual "dropdown-item"'s populated from data in the sqlite3 DB.
I have something similar working on other pages but I cant get it to work in my navbar.
I am creating a record label, and want the list of artists populated from entries in the DB. I have found one tutorial on doing something similar in php, but doesn't translate, and there doesn't seem to be anything either on youtube or here other than populating form data.
Any help is greatly appreciated, as I have been trying to get it working for about a week now. I know it should be simple, but im missing something.
the app is called "music"
models.py
class Artist(models.Model):
artist_name = models.CharField(max_length=250, default='')
artist_logo = models.FileField()
artist_url = models.URLField(blank=True)
def __str__(self):
return self.artist_name
class Release(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
release_title = models.CharField(max_length=500)
release_cover = models.FileField()
release_duration = models.IntegerField()
def __str__(self):
return self.release_title
class Track(models.Model):
release = models.ForeignKey(Release, default='', on_delete=models.CASCADE)
artist = models.ForeignKey(Artist, default='', on_delete=models.CASCADE)
track_title = models.CharField(max_length=200)
track_version = models.CharField(max_length=200)
track_genre = models.CharField(max_length=100)
track_duration = models.IntegerField()
track_number = models.SmallIntegerField()
class Meta:
ordering = ["track_number"]
def __str__(self):
return self.track_title
views.py
from django.contrib.auth import authenticate, login
from django.views import generic
from django.views.generic import ListView, View
from .models import Artist, Track, Release
from .forms import UserForm
# class IndexView(ListView):
# template_name = 'music/index.html'
class ReleaseView(generic.ListView):
template_name = 'music/releaselist.html'
context_object_name = 'all_releases'
def get_queryset(self):
return Release.objects.all()
class ArtistView(generic.ListView):
model = Artist
template_name = 'music/artistlist.html'
context_object_name = 'all_artists'
def get_queryset(self):
return Artist.objects.all()
class DetailView(generic.DetailView):
model = Release
template_name = 'music/detail.html'
urls.py (Main)
from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
# include urls from the music app
path('music/', include('music.urls'))
urls.py ("music" aka the app urls)
from django.contrib import admin
from django.urls import path, include, re_path
from . import views
# defined the app name in case the same fields are used in other apps
app_name = 'music'
urlpatterns = [
# no info past music return index EG /music/
# path('', views.IndexView.as_view(), name='index'),
# albums/releases
re_path(r'^release/$', views.ReleaseView.as_view(), name='release'),
# looking for music page with album id afterwards /music/1
re_path(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name="detail"),
re_path(r'^(?P<pk>[0-9]+)/$', views.ArtistView.as_view(), name="artist"),
base.html
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Artists
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
{% for artist in all_artists %}
<li><a class="dropdown-item" href="#">{{ artist.artist_id }}</a></li>
{% endfor %}
</div>
</li>
Update:
Here is my releases.html which works using similar code, and at the bottom has a test which looks like the for loop is incorrect
{% extends 'music/base.html' %}
{% block title %}KOLD FUZEON: Releases{% endblock %}
{% block body %}
{% if all_releases %}
<ul>
{% for release in all_releases %}
<div class="releaseitem">
<li>{{ release.artist }} - {{ release.release_title }}</li>
<li><a href="{% url 'music:detail' release.id %}"</a><img src="{{ release.release_cover.url }}" style="width: 300px"></li>
</div>
{% endfor %}
</ul>
{% else %}
<h3>We currently dont have any releases yet.</h3>
{% endif %}
{#basic test for the artist list to be printed to screen#}
<ul>
<li>test1</li>
{% for artist in all_artists %}
<li>test2</li>
{% endfor %}
</ul>
{% endblock %}
In your View.py you have ArtistView where template is artistlist.html and your context is all_artist & you get all objects from db.
Code:
class ArtistView(generic.ListView):
model = Artist
template_name = 'music/artistlist.html'
context_object_name = 'all_artists'
def get_queryset(self):
return Artist.objects.all()
Now i believe you have a template named artistlist.html. If not create it in templates in which you will use for Loop
to render artist list so the code should be this for artistlist.html:
{% extends 'music/base.html' %}
{% block body %}
<h1>Artists!</h1>
<ul>
{% for artist in all_artists %}
<li class="artist">
<h1>
<a href='/music/{{ artist.id }}'>{{artist.artist_name }}</a>
</h1>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}
You can Render Artist list in Base.html.
Using: Context Processor
First Create a file named context_processors.py in your App.Then add this code in that file.
from .models import Artist
def basetest(request):
hello = Artist.objects.values_list("artist_name", flat=True)
return {
'testname': hello
}
After that, open Settings.py and find context_processors and add the following settings 'yourapp.context_processors.add_variable_to_context'.
Settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
#This one is from my code so set it according to you
#appname.context_processors.function_name_context_processor.py',
'blog.context_processors.basetest',
],
},
},
]
After this just place {{ testname }} in your base.html according to your need. it will work. No need for looping just the interpolation will render you a list. Format it according to your need by following this doc
I believe there is some problem in the name of the 'key' that you are passing in the context.
In ReleaseView the context object name is all_releases, while you are trying to iterate on "all_artists".
Even if these changes not work, you can always try running your code on a normal view instead of the a generic view and pass the context in the template.
I'm creating a website which has two list views and a details view. I have no problem getting from the first listview to the second, but I'm unsure of how to make the url for the details view
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.ItemsView.as_view(), name='items'),
url(r'^(?P<category_id>[0-9]+)/(?P<products_id>[0-9]+)/$', views.DetailView.as_view(), name='details'),
]
im not sure what to replace "category_id" and "products_id" with on the bottom url
from django.http import Http404
from django.shortcuts import render
from django.views import generic
from .models import Category, Products
class IndexView(generic.ListView):
template_name = 'products/index.html'
context_object_name = 'all_categories'
def get_queryset(self):
return Category.objects.all()
class ItemsView(generic.ListView):
template_name = 'products/items.html'
context_object_name = 'all_items'
def get_queryset(self):
return Products.objects.all()
class DetailView(generic.DetailView):
model = Products
template_name = 'products/details.html'
html:
{% extends 'products/base.html' %}
{%block title%}Home{%endblock%}
{% block body %}
{% if all_items %}
<ul>
{% for product in all_items %}
<li>{{product.name}} </li>
{% endfor %}
</ul>
{% else %}
<h3>You have no categories</h3>
{% endif %}
{% endblock %}
also what would go in the url here where the question marks are
thanks
Use name of your url, define in your url.py.
Check the documentation
<li>{{ product.name }}</li>
Why do you need category in your url ?? You can access to your product like this. And your DetailView need only the primary key of the object.
url(r'^product/(?P<products_id>[0-9]+)/$', views.DetailView.as_view(), name='details'),
I want to display the dashboards which are under the group of logged in user, and I already have logged in user information and group-name of that user
so far my views.py is
def custom_login(request):
if request.user.is_authenticated():
return HttpResponseRedirect('dashboards')
return login(request, 'login.html', authentication_form=LoginForm)
def custom_logout(request):
return logout(request, next_page='/')
def user(request):
context = {'user': request.user, 'groups': request.user.groups.all()}
return render_to_response('registration/dashboards.html', context, context_instance=RequestContext(request))
dashboard.html is like
{% extends "base.html" %}
{% block content %}
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.get_username }}. <br/>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
<ul>
{% for group in groups %}
<li>
and you belongs to <strong>{{ group.name }}<strong> -
{% endfor %}
</li>
</ul>
{% endblock %}
forms.py looks like
from django import forms
from django.contrib.auth.models import User
from django.forms import ModelForm
#from mhawk.models import Dashboard
class LoginForm(forms.Form):
username = forms.CharField(label=(u'User Name'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
and my models.py is
from django.db import models
from django.contrib.auth.models import Group, User
from django.utils import timezone
import datetime
class Dashboard(models.Model):
d_name = models.CharField(max_length=200)
d_description = models.CharField(max_length=200)
d_url = models.CharField(max_length=200)
d_status = models.CharField(max_length=200)
owner = models.ForeignKey(Group)
def __str__(self):return self.d_name
and urls.py is
from django.conf.urls import patterns, include, url
from django.contrib import admin
from drinker import views, models
from django.contrib.auth.models import User
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^login/$', 'django.contrib.auth.views.login',),
url(r'^logout/$', 'django.contrib.auth.views.logout'),
url(r'^dashboards/$', 'mhawk.views.user'),
)
as I am able to display the logged in username, in the same way I want to display his group and the dashboards which are under that group, thank you. Looking forward for help.
Can you not just do something like this:
def user(request):
user_groups = request.user.groups.all()
if request.user.is_anonymous():
user_groups = []
user_dashboards = Dashboard.objects.filter(owner__in=user_groups)
context = {
'user': request.user,
'user_groups': user_groups,
'user_dashboards': user_dashboards,
}
[...]
In your template, you need to do something like this...
{% extends "base.html" %}
{% block content %}
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.get_username }}. <br/>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
<p></p>
<p>And you belongs to: </p>
<ul>
{% for group in user_groups %}
<li>
<strong>{{ group.name }}<strong> -
</li>
{% endfor %}
</ul>
{% endblock %}
Learn more about Django templating:
https://docs.djangoproject.com/en/1.7/ref/templates/builtins/#for