I'm pretty new to Django and already have read a lot about class-based views before coming here. I'm trying to build a one page website, with dynamic blocks that can be written from the Django admin. My problem is that I cannot manage to render variables from my database in my template. Here's what I wrote:
models.py
from django.db import models
from tinymce.models import HTMLField
class MyResume(models.Model):
subline = models.CharField(max_length=200)
content = HTMLField()
class Meta:
verbose_name = "My Resume"
verbose_name_plural = "My Resume"
def __str__(self):
return "My Resume"
class AboutMe(models.Model):
subline = models.CharField(max_length=200)
content = HTMLField()
cover_img = models.ImageField(upload_to="about_me")
class Meta:
verbose_name = "About me"
verbose_name_plural = "About me"
def __str__(self):
return "About me"
class Experience(models.Model):
subline = models.CharField(max_length=200)
pres_content = models.TextField()
exp_content = HTMLField()
date_exp = models.IntegerField()
class Meta:
verbose_name = "Experience"
verbose_name_plural = "Experiences"
def __str__(self):
return "Experience"
class ProjectPost(models.Model):
title = models.CharField(max_length=200)
technology = models.CharField(max_length=100)
subline = models.CharField(max_length=200)
content = HTMLField()
project_post_cover = models.ImageField(upload_to="projectpost_cover")
class Meta:
verbose_name = "Project Post"
verbose_name_plural = "Project Posts"
def __str__(self):
return self.title
class BlogPost(models.Model):
title = models.CharField(max_length=200)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = HTMLField()
blogpost_thumbnail = models.ImageField(upload_to="blogpost_thumbnail")
class Meta:
verbose_name = "Blog Post"
verbose_name_plural = "Blog Posts"
def __str__(self):
return self.title
class Contact(models.Model):
subline = models.CharField(max_length=200)
presentation_content = HTMLField()
def __str__(self):
return "Contact section text"
views.py
from django.shortcuts import render
from django.views.generic.base import TemplateView
from .models import *
class IndexTemplateView(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) # first, call super get context data
context['myresume'] = MyResume.objects.all()
context['aboutme'] = AboutMe.objects.all()
context['experience'] = Experience.objects.all()
context['projectpost'] = ProjectPost.objects.all()
context['blogpost'] = BlogPost.objects.all()
context['contact'] = Contact.objects.all()
return context
core.urls.py:
from django.urls import path
from .views import IndexTemplateView
urlpatterns = [
path('', IndexTemplateView.as_view()),
]
appname.urls.py:
from django.contrib import admin
from django.urls import include, path
from django.conf.urls import url
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^tinymce/', include('tinymce.urls')),
path('', include('core.urls')),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
and a snippet from my index.html template:
{% extends 'base.html' %}
{% load static %}
{% block content %}
(...)
<!-- ==================== ABOUT ==================== -->
<section id="about" class="section">
<h2 class="title">ABOUT</h2>
<div class="section-des">
{{ aboutme.subline }}
</div>
<div class="content-670">
<p>
{{ aboutme.content }}
</p>
</div>
<img class="about-img block-right" data-jarallax-element="0 -40" src="{{ aboutme.cover_img.url }}" alt="">
(...)
{% endblock content %}
All of the variables you've added to your template context are querysets, not objects. But you're trying to read them as individual objects in your template, which is why it doesn't work. You have two options:
Iterate over each queryset in your template:
{% for item in aboutme %}
<h2 class="title">ABOUT</h2>
{{ item.subline }}
{{ item.content }}
{% endfor %}
If you only want to display one of each model, then you need to fix your context method to only return one object, e.g.,
context['aboutme'] = AboutMe.objects.first()
Where here you're just returning the first AboutMe object in the database. If you do this, then your existing template logic will work. How you determine which object to return depends on what your data looks like.
{% for obj in myresume %}
<p>{{ obj.subline }}</p>
{% endfor %}
{% for obj in aboutme %}
<p>{{ obj.subline }}</p>
{% endfor %}
you can call your objects in this way in your templates. Also modify str function in models to get the dynamic content.
class MyResume(models.Model):
subline = models.CharField(max_length=200)
content = HTMLField()
class Meta:
verbose_name = "My Resume"
verbose_name_plural = "My Resume"
def __str__(self):
return self.sublime
Related
I am attempting to display a list of notes that are attached to a project. I can display the individual project the notes are linked to but I am not able to figure out how to display only the notes related to the project.
My models are:
class Project(models.Model):
title = models.CharField(max_length= 200)
description = models.TextField()
def __str__(self):
return self.title
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateField(auto_now_add=True)
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
def __str__(self):
return self.title
The views:
from django.shortcuts import get_object_or_404, render
from django.urls.base import reverse
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView
from .models import Project, ProjectNotes
class CompanyProjects(ListView):
model = Project
template_name = 'company_accounts/projects.html'
class CompanyProjectsDetailView(DetailView):
model = Project
id = Project.objects.only('id')
template_name = 'company_accounts/project_detail.html'
context_object_name = 'project'
class ProjectNotes(ListView):
model = ProjectNotes
template_name = 'company_accounts/project_notes.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['project'] = get_object_or_404(Project, id=self.kwargs.get('pk'))
return context
class ProjectNotesDetailview(DetailView):
model = ProjectNotes
template_name = 'company_accounts/project_note_detail.html'
The template displays the correct project:
{% extends 'base.html' %}
{% block content %}
<h1>Notes</h1>
{{ project }}
{% for note in notes %}
<div class ="projectnotes-entry">
<h2>{{ note.title }}</h2>
<p>{{ note.body }}</p>
</div>
{% endfor %}
{% endblock content %}
So far I have not been able figure out a way to only display the notes related to the specific project.
I'm trying to display a group of images classified by category. When the user clicks on a category name, the page should display the images that belongs to that category. I'm getting the the next browser error:
NoReverseMatch at /services/
'services' is not a registered namespace
. . .
Error during template rendering
The models belongs to different apps, one (that contains the Category model) works fine, and this other (That contains the Services model) just works if I delete the html content that I need. Help me please.
Here are my files:
home_app/models.py
from django.db import models
from django.urls import reverse
class Category(models.Model):
name=models.CharField(primary_key=True, max_length=50)
slug=models.SlugField(unique=True, blank=True, null=True)
image=models.ImageField(upload_to='category_home')
description=models.CharField(max_length=100)
content=models.TextField(max_length=500, default="Service")
created=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('services:services_by_category', args=[self.slug])
services_app/models.py
from django.db import models
from home_app.models import Category
class Services(models.Model):
category=models.ForeignKey(Category, on_delete=models.CASCADE)
title=models.CharField(max_length=50)
completed=models.DateField(auto_now_add=False, null=True, blank=True)
content=models.CharField(max_length=50, null=True, blank=True)
image=models.ImageField(upload_to='services_services')
created=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Service'
verbose_name_plural = 'Services'
def __str__(self):
return '%s de %s' % (self.category, self.title)
services_app/views.py
from django.shortcuts import render, get_object_or_404
from .models import Services
from home_app.models import Category
def service_list(request,category_slug=None):
category = None
categories = Category.objects.all()
services = Services.objects.all()
if category_slug:
category = get_object_or_404(Category,slug=category_slug)
services = services.filter(category=category)
return render(request, 'services_app/services.html', {'categories':categories, 'category':category, 'services':services,})
services_app/urls.py
from django.urls import path
from services_app import views
urlpatterns = [
path('', views.service_list, name='Services'),
path('<slug:category_slug>', views.service_list, name='services_by_category'),
]
services_app/templates/services_app/services.html
{% extends "home_app/base.html" %}
{% load static %}
{% block content %}
<!-- The app only works if I delete this section -->
<div id="sidebar">
<h3>Categories</h3>
<ul>
{% for c in categories %}
<li>
<h4>{{ c.name }}</h4>
</li>
{% endfor %}
</ul>
</div><br>
<div>
<h1>{% if category %}{{ category.name }}{% endif %}</h1>
{% for service in services %}
<img src="{{service.image.url}}">
{% endfor %}
</div>
{% endblock %}
Also my main urls:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('home_app.urls')),
path('services/', include('services_app.urls')),
path('contact/', include('contact_app.urls')),
]
Just change en models.py the following:
def get_absolute_url(self):
return reverse('services_by_category', args=[self.slug])
'cause you have not defined the namespace services.
I'm learning how to use urls in Django and I have a problem. I'm trying to get all services that belongs to a category by clicking on the category link, but when I do that, the browser returns me this error:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/services/None
Raised by: services_app.views.service_list
No Category matches the given query.
And the url looks:
http://localhost:8000/services/None
I already have a populated data base, and it can display their content just using a djanfo for, but I need it to be displayed by categories. Can anyone help me?
Here are my files:
home_app/models.py
from django.db import models
from django.urls import reverse
class Category(models.Model):
name=models.CharField(primary_key=True, max_length=50)
slug=models.SlugField(unique=True, blank=True, null=True)
image=models.ImageField(upload_to='category_home')
description=models.CharField(max_length=100)
content=models.TextField(max_length=500, default="Service")
created=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('services_by_category', args=[self.slug])
services_app/models.py
from django.db import models
from home_app.models import Category
class Services(models.Model):
category=models.ForeignKey(Category, on_delete=models.CASCADE)
title=models.CharField(max_length=50)
completed=models.DateField(auto_now_add=False, null=True, blank=True)
content=models.CharField(max_length=50, null=True, blank=True)
image=models.ImageField(upload_to='services_services')
created=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Service'
verbose_name_plural = 'Services'
def __str__(self):
return '%s de %s' % (self.category, self.title)
services_app/views.py
from django.shortcuts import render, get_object_or_404
from .models import Services
from home_app.models import Category
def service_list(request,category_slug=None):
category = None
categories = Category.objects.all()
services = Services.objects.all()
if category_slug:
category = get_object_or_404(Category,slug=category_slug)
services = services.filter(category=category)
return render(request, 'services_app/services.html', {'categories':categories, 'category':category, 'services':services,})
services_app/urls.py
from django.urls import path
from services_app import views
urlpatterns = [
path('', views.service_list, name='Services'),
path('<slug:category_slug>', views.service_list, name='services_by_category'),
]
services_app/templates/services_app/services.html
{% extends "home_app/base.html" %}
{% load static %}
{% block content %}
<div id="sidebar">
<br>
<br>
<h3>Categories</h3>
<ul>
{% for c in categories %}
<li>
<h4>{{ c.name }}</h4>
</li>
{% endfor %}
</ul>
</div><br>
<div>
<h1>{% if category %}{{ category.name }}{% endif %}</h1>
{% for service in services %}
<img src="{{service.image.url}}">
{% endfor %}
</div>
{% endblock %}
Also my main urls:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('home_app.urls')),
path('services/', include('services_app.urls')),
path('contact/', include('contact_app.urls')),
]
The problem is you don' t generate the slug of Category:
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
class Category(models.Model):
name=models.CharField(primary_key=True, max_length=50)
slug=models.SlugField(unique=True, blank=True, null=True)
image=models.ImageField(upload_to='category_home')
description=models.CharField(max_length=100)
content=models.TextField(max_length=500, default="Service")
created=models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
def save(self, *args, **kwargs):
if self._state.adding:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('services_by_category', args=[self.slug])
Note that you need to set manually the slug of the
existing Category instances (with the admin, a shell or a migration), or you can simply recreate them.
It is returning an error : Not Found: /post-detail/6/images/wallpaper002.jpg. I have tried to show image through {{ post_detail.img.all.first.url }} but I could show image in the template, it returns None value.
news.html
'''
<div class="text-center">
<img class="detail_picture img-thumbnail" src="{{ post_detail.img.all.first }}">
</div>
'''
models.py
'''
class Pictures(TimestampedModel):
img = models.ImageField(upload_to='images')
def __str__(self):
return str(self.img)
class Post(TimestampedModel):
title = models.CharField(max_length=128)
lang = models.IntegerField(choices=LANGUAGES, default=1)
short_description = models.CharField(max_length=255, blank=True, null=True)
description = models.TextField(blank=True, null=True)
category = models.ManyToManyField(PostCategoies, blank=True)
img = models.ManyToManyField(Pictures, blank=True)
icon = models.CharField(max_length=128, blank=True, null=True, help_text="Example: fa fa-info")
is_active = models.BooleanField(default=True)
def __str__(self):
return self.title
'''
views.py
'''
from django.shortcuts import render, redirect
from django.contrib import messages
from django.views import View
from .models import Post, Pictures
from django.views.generic import DetailView
from . import models
from django.shortcuts import get_object_or_404
class HomePageView(View):
def get(self, request):
posts = Post.objects.all()[:4]
context = {'posts': posts}
return render(request, 'index.html', context)
class PostDetailView(DetailView):
context_object_name = "post_detail"
model = models.Post
template_name = 'news.html'
'''
urls.py
'''
app_name = 'posts'
urlpatterns = [
path('', HomePageView.as_view(), name=""),
path('post-detail/<int:pk>/', PostDetailView.as_view(), name="post_detail")
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
'''
You are accessing the instance of a Pictures class with your current code. You need to then access the img property:
<div class="text-center">
<img class="detail_picture img-thumbnail" src="{{ post_detail.img.all.first.img.url }}">
</div>
I would also suggest that you protect against the case of not having an instance in the ManyToMany field
{% if post_detail.img.all.first %}
<div class="text-center">
<img class="detail_picture img-thumbnail" src="{{ post_detail.img.all.first.img.url }}">
</div>
{% endif %}
I'd also suggest looking into prefetch_related and/or Subquery as a way to more efficiently fetch these related details. It will help you prevent N+1 queries. You can verify you're not running too many queries with the django debug toolbar.
i created methods within my model class to handle my redirects all work except for the one i created for a link in my list view(go_to_create method ) im using class based views
class Todo(models.Model):
name = models.CharField(max_length=100, default='unamedTodo')
description = models.CharField(max_length=200)
Todo_date = models.DateTimeField('Todo Date')
pub_date = models.DateTimeField('Date Published')
def get_absolute_url(self):
return reverse('ToDo:detail', kwargs={'id': self.id})
def get_back_home(self):
return reverse('ToDo:todos', kwargs={})
def go_to_update(self):
return reverse('ToDo:update', kwargs={'id': self.id})
def go_to_create(self):
return reverse('ToDo:create', kwargs={})
class TodoCreateView(CreateView):
template_name = 'ToDo/todo_create.html'
form_class = TodoForm
queryset = Todo.objects.all()
from django.urls import path
from .views import (
TodoListView,
TodoDetailView,
TodoCreateView,
TodoUpdateView,
TodoDeleteView,
)
app_name = "ToDo"
urlpatterns = [
path('Todos/', TodoListView.as_view(), name='todos'),
path('Todos/<int:id>/', TodoDetailView.as_view(), name='detail'),
path('Todos/create/', TodoCreateView.as_view(), name='create'),
path('Todos/<int:id>/update/', TodoUpdateView.as_view(), name='update'),
path('Todos/<int:id>/delete/', TodoDeleteView.as_view(), name='delete')
]
<h1>ToDo's</h1>
<ul>
{% for object in object_list %}
<li>
<p>
{{ object.id }} -
{{ object.name }}
</p>
</li>
{% endfor %}
<p>Create new Todo here</p>
</ul>
the link calling the go_to_create method does not work i stay on the same page no error is generated
Instead of a method call directly on template,that will do the job.
{% url 'ToDo:create' %}