I am new to Django. I have problem in displaying model objects into my template
here is my models.py:
from django.db import models
from django.contrib.auth.models import User
class Employee(models.Model):
username = models.TextField(max_length=100)
email = models.CharField(max_length=100)
password = models.TextField(max_length=100)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.username
here is my views.py:
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import Employee
#login_required
def home(request):
context ={
'employee': Employee.objects.all()
}
return render(request, 'newusers/home.html', context)
here is my template code:
{% extends "users/base.html" %} {% load crispy_forms_tags %} {% block content %}
<article class="media content-section">
<div class="media-body">
<div class="card">
<a class="mr-2" href="#">{{ employee.username }}</a>
<small class="text-muted">{{ employee.email }}</small>
</div>
</div>
</article>
{% endblock content %}
You get two distinct notions mixed up: querysets and model instances.
Employee.objects.all(), that is to say currently employee in your template, is a queryset.
Depending on what you exactly want to achieve, you need to iterate this queryset to access each instance attributes:
# views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import Employee
#login_required
def home(request):
context ={'employees': Employee.objects.all()} # note the s at the end
# here you may want to print `list(context["employees"])` to understand the queryset structure
return render(request, 'newusers/home.html', context)
And then for each employee of the queryset employees:
{% block content %}
{% for employee in employees %}
<article class="media content-section">
<div class="media-body">
<div class="card">
<a class="mr-2" href="#">{{ employee.username }}</a>
<small class="text-muted">{{ employee.email }}</small>
</div>
</div>
</article>
{% endfor %}
{% endblock %}
Related
I can't seem to get my delete, edit and add review functionality working. The errors come as soon as I try to navigate to the urls I have set up. When I try and add a new review using my link on the reviews page I get the below message:
TemplateDoesNotExist at /reviews/add
I don't understand why because I have linked the url above to the template, which I have created.
The issue I have with my edit/delete views is that the url it searches for when I click the button is just /edit/ or /delete/ rather than reviews/edit/int:pk or reviews/delete/int:pk as per my urls.
I have pasted my code below, any help would be much appreciated! I have the feeling I am going to kick myself when I realise!
reviews.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid home-container">
<div class="row align-items-center">
<div class="col-sm-12 text-center mt-4">
<h2><strong>Reviews</strong></h2>
</div>
</div>
{% for review in reviews %}
<hr class="hr-1">
<div class="row featurette">
<div class="col-sm-12">
<h2 class="featurette-heading">{{ review.title }}</h2>
<p class="lead">{{ review.content }}</p>
<div class="row justify-content-between mx-1">
<p>By: {{ review.user }}</p>
<p>Created on: {{ review.created }}</p>
<p>Last Updated: {{ review.updated }}</p>
</div>
<!-- Add user authentication if -->
<div class="text-center">
<a href="edit/{{ review.id }}" class="mx-2">
<button class="positive-button mb-2">Edit</button></a>
<a href="delete/{{ review.id }}" class="mx-2 mb-2">
<button class="negative-button">Delete</button></a>
</div>
</div>
</div>
{% endfor %}
<div class="row">
<div class="col-sm-12 text-center py-4">
{% if user.is_authenticated %}
<a href="{% url 'home:add_review' %}">
<button class="positive-button-lg">Add a review</button>
</a>
{% else %}
<p>If you would like to add your own review, please login or sign up if you haven't already!</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
add_review.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{{ review_form }}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
</div>
</div>
{% endblock %}
views.py:
from django.shortcuts import render
from django.views import View
from django.urls import reverse_lazy
from django.views.generic import UpdateView, DeleteView
from .models import Reviews
from .forms import ReviewForm
def home(request):
''' Returns the home page.'''
return render(request, 'home/index.html')
def reviews(request):
''' Returns the reviews page.'''
serialized_reviews = []
reviews = Reviews.objects.all()
for review in reviews:
serialized_reviews.append({
"title": review.title,
"content": review.content,
"user": review.user,
"created": review.created,
"updated": review.updated,
})
context = {
"reviews": serialized_reviews
}
print(serialized_reviews)
return render(request, 'home/reviews.html', context)
class AddReview(View):
'''View which allows the user to add a new review.'''
def get(self, request, *args, **kwargs):
review = Reviews
review_form = ReviewForm
context = {
'review': review,
'review_form': review_form,
'user': review.user,
'title': review.title,
'content': review.content,
}
return render(request, 'add_review.html', context)
def post(self, request, *args, **kwargs):
review_form = ReviewForm(data=request.POST)
if review_form.is_valid():
obj = review_form.save(commit=False)
obj.user = request.user
obj.save()
return redirect("home:reviews")
class DeleteReview(DeleteView):
'''View which allows the user to delete the selected review.'''
model = Reviews
template_name = 'delete_review.html'
success_url = reverse_lazy('reviews')
class EditReview(UpdateView):
'''View which allows the user to edit the selected review.'''
model = Reviews
template_name = 'edit_review.html'
fields = ['title', 'content']
urls.py:
from django.urls import path
from . import views
app_name = 'home'
urlpatterns = [
path('', views.home, name='home'),
path('reviews', views.reviews, name='reviews'),
path('reviews/add', views.AddReview.as_view(), name='add_review'),
path('reviews/delete/<int:pk>', views.DeleteReview.as_view(), name='delete_review'),
path('reviews/edit/<int:pk>', views.EditReview.as_view(), name='edit_review'),
]
The main difference is my app name, which is 'core'. Also, I forgot to add the content field to the model, but that is easily done, the form will just handle it as soon as you do the migration. (except on list.html)
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
class Reviews(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
title = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=timezone.now())
updated_at = models.DateTimeField(auto_now=timezone.now())
forms.py
from django import forms
from core.models import Reviews
class ReviewsForm(forms.ModelForm):
class Meta:
model = Reviews
fields = '__all__'
views.py
from core.models import Reviews
from core.forms import ReviewsForm
from django.shortcuts import render, redirect
def list_reviews(request):
reviews = Reviews.objects.all()
context = {
"reviews": reviews
}
return render(request, 'reviews/list.html', context)
def add_review(request):
if request.method == 'POST':
form = ReviewsForm(request.POST)
if form.is_valid():
form.save()
return redirect('/reviews/')
else:
form = ReviewsForm()
context = {
'form': form
}
return render(request, 'reviews/detail.html', context)
def edit_review(request, pk):
if request.method == 'POST':
form = ReviewsForm(request.POST)
if form.is_valid():
obj = Reviews.objects.get(id=pk)
obj.title = form.cleaned_data['title']
obj.user = form.cleaned_data['user']
obj.save()
return redirect('/reviews/')
else:
obj = Reviews.objects.get(id=pk)
form = ReviewsForm(instance=obj)
context = {
'form': form
}
return render(request, 'reviews/detail.html', context)
def delete_review(request, pk):
obj = Reviews.objects.get(id=pk)
obj.delete()
return redirect('/reviews/')
urls.py
from django.urls import path
import core.views as views
app_name = 'core'
urlpatterns = [
path('reviews/', views.list_reviews, name='list-reviews'),
path('reviews/add', views.add_review, name='add-review'),
path('reviews/edit/<int:pk>/', views.edit_review, name='edit-review'),
path('reviews/delete/<int:pk>/', views.delete_review, name='delete-review'),
]
list.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid home-container">
<div class="row align-items-center">
<div class="col-sm-12 text-center mt-4">
<h2><strong>Reviews</strong></h2>
</div>
</div>
{% for review in reviews %}
<hr class="hr-1">
<div class="row featurette">
<div class="col-sm-12">
<h2 class="featurette-heading">{{ review.title }}</h2>
<p class="lead">{{ review.content }}</p>
<div class="row justify-content-between mx-1">
<p>By: {{ review.user }}</p>
<p>Created on: {{ review.created_at }}</p>
<p>Last Updated: {{ review.updated_at }}</p>
</div>
<!-- Add user authentication if -->
<div class="text-center">
<a href="{% url 'core:edit-review' pk=review.id %}" class="mx-2">
<button class="positive-button mb-2">Edit</button></a>
<a href="{% url 'core:delete-review' pk=review.id %}" class="mx-2 mb-2">
<button class="negative-button">Delete</button></a>
</div>
</div>
</div>
{% endfor %}
<div class="row">
<div class="col-sm-12 text-center py-4">
{% if user.is_authenticated %}
<a href="{% url 'core:add-review' %}">
<button class="positive-button-lg">Add a review</button>
</a>
{% else %}
<p>If you would like to add your own review, please login or sign up if you haven't already!</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
detail.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{% csrf_token %}
<table>
{{ form }}
</table>
<button type="submit" class="btn btn-primary btn-lg">Save</button>
</form>
</div>
</div>
{% endblock %}
According to your urls, It is a review/edit/<int:pk>.
So you must add same thing in href tag.
Change this:
<a href="edit/{{ review.id }}"
To this:
<a href="review/edit/{{ review.id }}"
That's why you are getting that error
I've fixed it, firstly the path in my add_review view was wrong, which I have amended and it now works (thanks Ivan).
I also was not actually bringing the ID through on my 'reviews' view in the first place, so when following the links on my edit and review buttons, it didn't know what I meant by 'id', as I hadn't specified what that was in the view context.
Thanks for the help all!
I think you're writing in your urls the wrong way, like this below your div text-center:
<a href="edit/{{ review.id }}" class="mx-2">
It should be:
<a href="{% url 'yourappname:edit' review.id %}">
urls.py
from django.urls import path
from . import views
app_name='shop'
urlpatterns = [
path('',views.allproduct,name='allproductcat'),
path('<slug:c_slug>/',views.allproduct,name='product_by_catagory')
]
views.py
from django.shortcuts import render, get_object_or_404
from . models import catagory,product
# Create your views here.
def allproduct(request,c_slug=None):
c_page=None
products=None
if c_slug!=None:
c_page=get_object_or_404(catagory,slug=c_slug)
products=product.objects.all().filter(catagory=c_page,available=True)
else:
products=product.objects.all().filter(available=True)
return render(request,'catagory.html',{'catagory':c_page,'products':products})
model.py
from django.db import models
# Create your models here.
from django.urls import reverse
class catagory(models.Model):
name=models.CharField(max_length=250,unique=True)
slug=models.SlugField(max_length=250,unique=True)
description=models.TextField(blank=True)
image=models.ImageField(upload_to='catagory',blank=True)
class Meta:
ordering=('name',)
verbose_name='catagory'
verbose_name_plural='catagories'
def __str__(self):
return '{}'.format(self.name)
def get_url(self):
return reverse('shop:product_by_catagory',args=(self.slug,))
class product(models.Model):
name = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='product', blank=True)
price=models.DecimalField(max_digits=10,decimal_places=2)
stock=models.IntegerField()
available=models.BooleanField()
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
catagory=models.ForeignKey(catagory,on_delete=models.CASCADE)
class Meta:
ordering = ('name',)
verbose_name = 'product'
verbose_name_plural = 'products'
def __str__(self):
return '{}'.format(self.name)
catagory. html
{% extends 'base.html' %}
{% load static %}
{% block metadiscription %}
{% if catagory %}
{{catagory.discription}}
{% else %}
welcome
{% endif %}
{% endblock %}
{% block title %}
{% if catagory %}
{{catagory.name}}--ABC store
{% else %}
see our new collection
{% endif %}
{% endblock %}
{% block content %}
{% if catagory %}
<div>
<div>
OUR PRODUCT COLLECTION
</div>
</div>
{% endif %}
<div>
{% if catagory %}
<img src="{{catagory.img.url}}" alt="{{catagory.name}}">
</div>
<br>
<div>
<h1>
{{catagory.name}}
</h1>
<p>
{{catagory.discription}}
</p>
</div>
{% else %}
<div>
<img src="{% static 'img/banner.png' %}">
</div>
<br>
<div>
<h1>OUR PRODUCT COLLECTION</h1>
<p>INDIA IS MY COUNTRY I LOVE MY COUNTRY</p>
</div>
{% endif %}
<div>
<div>
{% for product in products %}
<div>
<div>
<div>
<h4>{{product.name}}</h4>
<p>{{product.price}}</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
context_processors.py
from . models import catagory
def menu_link(request):
link=catagory.objects.all()
return dict(links=link)
i can't load the catagory page using the slug address,that is dress, when i enter that it is showing there is no revrse for allproducts, and when i open the website there is no image in image position.as i have uploaded the image file in the admin pannel
The name=… of your path is allproductcat, not allproduct, you thus should implement a link with:
OUR PRODUCT COLLECTION
when I add a post in the admin panel, the posts are not shown on the home page of the app.
it only shows spaces of the post but couldn't show writeup of the post on the home page.
views.py
from django.shortcuts import render,HttpResponseRedirect
from django.contrib import messages
from django.http import HttpResponse
from .forms import SignUpForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from .models import Post
# Create your views here.
# home
def home(request):
posts = Post.objects.all()
return render(request, 'blog/home.html',{'posts':posts})
home.html
{% extends 'blog/base.html' %}
{% load static %}
{% block content %}
<div class="col-sm-10">
<h3 class="text-white my-5">Home Page</h3>
{% for post in posts %}
<div class="jumbotron jumbotron-fluid jumbo-colour">
<div class="container">
<h1 class="display-4 font-weight-bold">{{posts.title}}</h1>
<p class="lead">{{posts.desc}}</p>
</div>
</div>
{% endfor %}
</div>
{% endblock content %}
models.py
from django.db import models
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=150)
desc = models.TextField()
There is a typo in your code. It should be:
{% for post in posts %}
<div class="jumbotron jumbotron-fluid jumbo-colour">
<div class="container">
<h1 class="display-4 font-weight-bold">{{post.title}}</h1> // not posts.title
<p class="lead">{{post.desc}}</p> // not posts.desc
</div>
</div>
{% endfor %}
Here is the problem: I'm trying to 'fresh' my django web blog, so instead of having /post/2/ I want to have slugged link that's exactly like my title (smth like this: /post/today-is-friday
Here is some code, I've tried couple of things, but there is nothing working:
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from django.template.defaultfilters import slugify
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
categories = models.ManyToManyField('Category', related_name='posts')
image = models.ImageField(upload_to='images/', default="images/None/no-img.jpg")
slug= models.SlugField(max_length=500, unique=True, null=True, blank=True)
def save(self, *args, **kwargs):
self.url= slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
urls.py
from django.urls import path
from django.conf.urls import include, url
from . import views
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView, UserPostListView
urlpatterns = [
#Blog section
path("", PostListView.as_view(), name='blog-home'),
path("user/<str:username>", UserPostListView.as_view(), name='user-posts'),
path("<slug:slug>/", PostDetailView.as_view(), name='post-detail'),
path("post/new/", PostCreateView.as_view(), name='post-create'),
path("<slug:slug>/update/", PostUpdateView.as_view(), name='post-update'),
path("<slug:slug>/delete/", PostDeleteView.as_view(), name='post-delete'),
path("about/", views.about, name="blog-about"),
path("<category>/", views.blog_category, name="blog_category"),
]
user_posts.html(this is for accessing blog post itself)
{% extends 'blog/base.html' %}
{% block content %}
<h1 class='mb-3'>Post by {{ view.kwargs.username }} ({{ page_obj.paginator.count }})</h1>
{% for post in posts %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" alt="">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2 author_title" href="{% url 'user-posts' post.author.username %}">#{{ post.author }}</a>
<small class="text-muted">{{ post.date_posted|date:"N d, Y" }}</small>
<div>
<!-- category section -->
<small class="text-muted">
Categories:
{% for category in post.categories.all %}
<a href="{% url 'blog_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</small>
</div>
</div>
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content|slice:200 }}</p>
</div>
</article>
{% endfor %}
{% endblock content %}
post_form.html(It's for creating a new post, have trouble with redirecting after post created)
{% extends 'blog/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Blog Post</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
If you are going to change the value of the slug field before saving, you can use signals.
Also the slugify method of django is located in django.utils.text not django.template.defaultfilters.
urls.py
# ...
path('post/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
# ...
models.py
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils.text import slugify
import string
class Post(models.Model):
# ...
slug= models.SlugField(max_length=500, unique=True, null=True, blank=True)
# do not override save method here
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
class_ = instance.__class__
qs_exists = class_.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = f"{slug}-{random_string_generator(size=5)}"
return unique_slug_generator(instance, new_slug=new_slug)
return slug
#receiver(pre_save, sender=Post)
def post_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
Those two functions, unique_slug_generator and random_string_generator, together will guaranty that you won't have same slug on two posts, even if the title of those posts are same! (it will add some randomly generated string at the end)
Edit
In your html template for user_posts.html, replace
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
with
<h2><a class="article-title" href="{% url 'post-detail' post.slug %}">{{ post.title }}</a></h2>
Also, in your view (not template) of post_form, you should override get_success_url like this:
def get_success_url(self):
return reverse('post-detail', kwargs={'slug': self.object.slug})
Edit 2 (for more clarification)
First, we need a url for each post, we implement it as:
path('post/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
Next, you should change your previous links to the post-detail. These include your 1)template links and 2)links in the views/models:
In your templates, wherever you have {% url 'post-detail' post.pk %}, you should change that to {% url 'post-detail' post.slug %}.
and in your views/models, you should change reverse('post-detail', kwargs={'pk': self.pk}) tp reverse('post-detail', kwargs={'slug': self.slug}) (not self.object.slug)
I am trying to build a basic blog using django framework. In the posts, i have image field in the Post model. First few posts were added properly. But after i added pagination, the images are not being loaded. Whatever image i add, it is not loading on the screen.
models.py:
import os
from django.conf import settings
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.db import models
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
poster = models.ImageField(upload_to=settings.MEDIA_ROOT);
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='blog_posts')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_image(self):
return os.path.join('/media', self.poster.name)
views.py:
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render,get_object_or_404
from .models import Post
# Create your views here.
def post_list(request):
posts_list = Post.objects.filter(status='published')
paginator = Paginator(posts_list, 2) # 3 posts in each page
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
return render(request,'blog/post/list.html',{'page':page,'posts':posts})
Template:
{% extends "blog/base.html" %}
{% block title %}My Blog{% endblock %}
{% block content %}
<h1 class="my-4">BlogSpot
<small>Find Everything</small>
</h1>
{% for post in posts %}
<div class="row">
<div class="col-md-8">
<!-- Blog Entries Column -->
<!-- Blog Post -->
<div class="card mb-2">
<img class="card-img-top" src="{{ post.get_absolute_image }}" alt="Card image cap">
<div class="card-body">
<h2 class="card-title">{{ post.title }}</h2>
<p class="card-text"></p>
Read More →
</div>
<div class="card-footer text-muted">
{{ post.publish }} by {{post.author}}
</div>
</div>
</div>
</div>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if posts.has_previous %}
Previous
{% endif %}
<span class="current">
Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
</span>
{% if posts.has_next %}
Next
{% endif %}
</span>
</div>
{% endblock %}
These are the files I have used. All of a sudden, when i add the new posts, images are not being loaded. How to solve this?