How to display Model data in a Django Template - python

I am new to Django. I am trying to display data from my Project model in my index view, using a template. I tried my best to structure this app similar to the polls app. I'm not sure what I am doing wrong. I am using python 2.7, and django 1.8.6
Here is my url:
from django.conf.urls import url
from . import views
app_name = 'project'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
]
Here is my Model:
import datetime
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.contrib.auth.models import User
from django.utils import timezone
#python_2_unicode_compatible # only if you need to support Python 2
class Contractor(models.Model):
#project
name = models.CharField(max_length=50)
address = models.CharField(max_length=100, blank=True)
phone = models.CharField(max_length=14, blank=True)
city = models.CharField(max_length=60, blank=True)
state = models.CharField(max_length=2, blank=True)
created_by = models.ForeignKey(User, related_name='Contractor_created_by')
created_date = models.DateTimeField()
modified_by = models.ForeignKey(User, related_name='Contractor_modified_by')
modified_date = models.DateTimeField()
def __str__(self):
return self.name
#python_2_unicode_compatible # only if you need to support Python 2
class Project(models.Model):
name = models.CharField(max_length=50)
jobNumber = models.CharField(max_length=8)
shopOut = models.DateTimeField(null=True)
shopIn = models.DateTimeField(null=True)
delivery = models.DateTimeField(null=True)
job1 = models.CharField(max_length=50, null=True)
job2 = models.CharField(max_length=50, null=True)
job3 = models.CharField(max_length=50, null=True)
contractor = models.ForeignKey(Contractor, on_delete=models.CASCADE, default=101)
created_by = models.ForeignKey(User, related_name='Project_created_by')
created_date = models.DateTimeField(auto_now_add=True)
modified_by = models.ForeignKey(User, related_name='Project_modified_by')
modified_date = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.id:
self.created_by = User.objects.get(id=1)
self.modified_by = User.objects.get(id=1)
super(Project, self).save(*args, **kwargs)
year = datetime.datetime.now().year
self.jobNumber = '{}{:04d}'.format(year, self.id)
self.modified_by = User.objects.get(id=1)
super(Project, self).save(*args, **kwargs)
Here is my View:
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views import generic
from django.utils import timezone
from .models import Project
# Create your views here.
class IndexView(generic.ListView):
model = Project
template_name = 'project/index.html'
def get_queryset(self):
return Project.objects
class DetailView(generic.DetailView):
model = Project
Here is my Template:
{% load staticfiles %}
<h1>Projects</h1>
<ul>
{% for projects in project.get_queryset %}
in for loop
<!-- <li>{{ projects.name }}</li> -->
<li>Test</li>
{% endfor %}
</ul>
end of list
When I go to the page I get a h1 Project, an empty ul, and a line that says 'end of list'

In your get_queryset, you should return Project.objects.all().
In your template, you don't need to do project.get_queryset, the get_queryset method is called for you and the values are passed to the template as object_list and <objectname>_list, along with other parameters. In your case, the object is Project so there should be a project_list variable too along with object_list.
You can do:
{% for project in project_list %}
<li>{{ project.name }}</li>
{% endfor %}
Or:
{% for project in object_list %}
<li>{{ project.name }}</li>
{% endfor %}
You can read more about it here: https://docs.djangoproject.com/en/1.9/ref/class-based-views/generic-display/#listview

Your get queryset doesn't return a query set at the minute, currently its just returning a related manager. you should make it return a queryset...
def get_queryset(self):
return Project.objects.all() # added all

You might want to try:
{% for project in object_list %}
<li>{{ project.name }}</li>
{% endfor %}
object_list is the default name of queryset if you use ListView, you can change that by defining context_object_name in your view. Here's django doc about that.

Related

How get image from images model to home page in Django?

I am developing an ecommerce website with Django. In my home page displayed product cards as you see in the below image.
This product image in each card I take from my Product model (image field). When I hover over this image on the home page, the image is changing to another image. That is for I need another image, and I want to take the next image (display when I hover over) from my Product_images model. But I don't know how to do that.
urls.py
from django.urls import path
from . import views
from django.conf.urls.static import static
urlpatterns =
path('', views.home_page, name='amd-home'),
path('product/<int:id>/', views.product_detail, name='product-detail'),
path('about/', views.about, name='amd-about'),
]
views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView
from django.http import HttpResponse
from .models import Product, Product_image, Product_details
def home_page(request):
products = Product.objects.all()
images = Product_image.objects.all()
context = {'products':products, 'images':images}
return render(request, 'product/home.html', context)
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=200)
parent_id = models.IntegerField(default=0)
description = models.TextField()
image = models.ImageField(upload_to='uploads/')
def __str__(self):
return f'{self.name}'
class Brand(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=400)
image = models.ImageField(upload_to='uploads/')
def __str__(self):
return f'{self.name}'
class Product(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='uploads/', blank=True, null=True)
sku = models.CharField(max_length=200)
price = models.IntegerField(default=0)
price_old = models.IntegerField(default=0)
description = models.TextField()
status = models.BooleanField(default=False)
date_posted = models.DateTimeField(auto_now_add=True)
internal_storage = models.CharField(max_length=50, blank=True, null=True, default=None)
ram = models.CharField(max_length=50, blank=True, null=True, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return f'{self.title}, {self.description}'
class Product_image(models.Model):
image = models.ImageField(upload_to='uploads/')
product = models.ForeignKey(Product, on_delete=models.CASCADE)
def __str__(self):
return f'{self.product.title} image'
home.html
my template file is a very large file, so I only insert the element where I get an image from the Product model (this code word fine), but I don't know how to write code to take images from my Product_image model.
{% for product in products %}
<img alt="" src="{{ product.image.url }}">
{% endfor %}
First, in your model you can give a related_name field like :
class Product_image(models.Model):
image = models.ImageField(upload_to='uploads/')
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="product_images)
def __str__(self):
return f'{self.product.title} image'
Then you can access the product's images in template like:
{% for product in products %}
{% for image in product.product_images.all %}
<img alt="" src="{{ image.image.url }}">
{% endfor %}
{% endfor %}
PS: You dont have to return all Product_image quesryset from the view
Expanding on the answer, if you want to order the images there are different approaches you can take:
Method1:
class Product_image(models.Model):
image = models.ImageField(upload_to='uploads/')
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="product_images)
time_created = models.DateTimeField(null=True, blank=True)
def __str__(self):
return f'{self.product.title} image'
class Meta:
ordering = ['time_created']
This will order the query set from first created to last . If you don't want to add a time created field you can also choose to order by id.
Method2:
Add a property to your Product model:
class Product:
....
#property
def sorted_image_set(self):
return self.product_images.order_by('time_created')
Then you can access this property from the template
{% for image in product.sorted_image_set %}
Method 3 :
Creating a custom template tag to support order_by in template
#register.filter
def order_by(queryset, args):
args = [x.strip() for x in args.split(',')]
return queryset.order_by(*args)
Then you can do :
{% for image in product.product_images|order_by:"time_created" %}
After the list has been ordered you can access it just by the array indexes like for example images[0] or images[1]
change src in your HTML
{% for product in products %}
<a href="{% url 'product-detail' product.id %}"><img alt="" src="/media/uploads/{{
product.image }}"></a>
{% endfor %}
I have assumed that you have MEDIA_URL=/media/ in your settings. Change this in src if you have different MEDIA_URL

How to pass multiple values from models.py to HTML via views.py in Django

I have a following models.py for my Django blog, I made a following views.py to pass the value of the slug for my URL parameter.
However I am struggling to create a model in views to get other data(person & description) from Category class.
I have tried some patterns by myself but can not pass them to HTML. (always Error or not showing)
Can you please give me some idea of how to solve this.
models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
views.py
def blog_category(request, category):
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
context = {"category": category, "posts": posts}
return render(request, "blog_category.html", context)
HTML(Localhost:8000/slug)
{{ person }}
{{ description }}
this is full code of my models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
class Recommender(models.Model):
recommender_name = models.CharField(max_length=20)
slug = models.SlugField()
def __str__(self):
return self.recommender_name
class Post(models.Model):
book_title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
book_link = models.CharField(max_length=255)
recommenders = models.ForeignKey("Recommender", on_delete=models.CASCADE,)
source = models.TextField()
source_link = models.CharField(max_length=255)
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")
slug = models.SlugField()
def __str__(self):
return self.book_title
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
Is going to return a queryset. It can have more than one instance of the model class (since you are using filter). In your context you are sending this queryset as posts to your templates.
So in your HTML you can use something like this. You need to use a for loop since there can be more than one item in posts.
{% for post in posts %}
{% for category in post.categories.all %}
{{ category.person }}
{{ category.description }}
{% endfor %}
{% endfor %}
I would look at this example.
Namely, if you render the template like it is shown in the example, you should be able to do
{{ category.person }} {{ category.description }}

template not displaying information - django

I can't figure out why my data won't display in my user.html template. From reviewing the code it looks like everything is linked correctly. The users.html page is showing up on the website minus the information about {{ user.order_set.all }}. I have highlighted the code I believe relates to the issue. Any guidance would be greatly appreciated, thanks!
user.html - html for displaying the data
{% extends "fuisce/base.html" %}
{% block content %}
**{{ user.order_set.all }}**
{% endblock content %}
views.py - order
from django.shortcuts import render, HttpResponseRedirect
from django.urls import reverse
# Create your views here.
from carts.models import Cart
from .models import Order
from users.models import Profile
from .utils import id_generator
**def orders(request):
context = {}
template = "orders/user.html"
return render(request, template, context)**
def checkout(request):
try:
the_id = request.session['cart_id']
cart = Cart.objects.get(id=the_id)
except:
the_id = None
return HttpResponseRedirect(reverse("cart"))
new_order, created = Order.objects.get_or_create(cart=cart)
if created:
new_order.order_id = id_generator()
new_order.save()
my_p = Profile.objects.get(user=request.user)
new_order.user = my_p
new_order.save()
if new_order.status == "Finished":
# cart.delete()
del request.session['cart_id']
del request.session['items_total']
return HttpResponseRedirect(reverse("cart"))
context = {}
template = "fuisce/about.html"
return render(request, template, context)
models.py - orders
from django.db import models
# Create your models here.
from carts.models import Cart
from users.models import Profile
STATUS_CHOICES =(
("Started", "Started"),
("Abandoned", "Abandoned"),
("Finished", "Finished"),
)
class Order(models.Model):
**user = models.ForeignKey('users.Profile', null=True, blank=True, on_delete=models.CASCADE)**
order_id = models.CharField(max_length=120, default='ABC', unique=True)
cart = models.ForeignKey('carts.Cart', on_delete=models.CASCADE)
status = models.CharField(max_length=120, choices=STATUS_CHOICES, default="Started")
sub_total = models.DecimalField(default=10.99, max_digits=1000, decimal_places=2)
tax_total = models.DecimalField(default=10.99, max_digits=1000, decimal_places=2)
final_total = models.DecimalField(default=10.99, max_digits=1000, decimal_places=2)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __string__(self):
return self.order_id
urls.py
from django.urls import path
from . import views
from carts import views as cart_views
from orders import views as order_views
urlpatterns = [
path('', views.home, name='fuisce-home'),
path('subscription/', views.subscription, name='fuisce-subscription'),
path('oneoff/', views.oneoff, name='fuisce-oneoff'),
path('about/', views.about, name='fuisce-about'),
path('contact/', views.contact, name='fuisce-contact'),
path('cart/', cart_views.view, name='cart'),
path('cart/<int:id>/', cart_views.remove_from_cart, name='remove_from_cart'),
path('cart/<slug>/', cart_views.add_to_cart, name='add_to_cart'),
path('checkout/', order_views.checkout, name='checkout'),
**path('orders/', order_views.orders, name='user_orders'),**
]
Based on the comments to the question, it seems you have a ForeignKey field to Profile and not to User.
Either change your ForeignKey from Profile to User like this:
class Order(models.Model):
user = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
null=True,
blank=True)
Or use a different lookup in your template:
{{ user.profile.order_set.all }}

Passing data with CreateView in django

I am getting the error:
NOT NULL constraint failed: films_comment.film_id
On the comments page there is a form field called body for the comment itself, I also need it to store this comment against the user and the film.
Models:
from django.db import models
from django.urls import reverse
class Film(models.Model):
title = models.CharField(max_length=200)
director = models.CharField(max_length=200)
description = models.CharField(max_length=200)
pub_date = models.DateField('date published')
def get_absolute_url(self):
return reverse('films:detail', kwargs={'pk' : self.pk})
class Comment(models.Model):
# user = models.ForeignKey(User, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
film = models.ForeignKey(Film, on_delete=models.CASCADE)
body = models.CharField(max_length=200)
Views:
from django.views import generic
from .models import Film, Comment
from django.views.generic.edit import CreateView, UpdateView, DeleteView
class IndexView(generic.ListView):
# model = Film
template_name = 'films/index.html'
# context_object_name = 'object_list'
def get_queryset(self):
return Film.objects.all()
class DetailView(generic.DetailView):
model = Film
template_name = 'films/detail.html'
class CommentCreate(CreateView):
model = Comment
fields = ['body']
Urls:
app_name = 'films'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
# path('<int:film_id>/comment', views.add_comment, name='add_comment'),
path('<int:pk>', views.DetailView.as_view(), name='detail'),
path('<int:film_id>/comment/', views.CommentCreate.as_view(), name='add_comment'),
]
Link on details page for adding a comment:
Leave a comment
comment_form.py:
<form action="" method="post">
{% csrf_token %}
{% include 'films/form-template.html' %}
<button type="submit">Submit</button>
</form>
Form template:
{% for field in form %}
{{field.errors}}
<label>{{ field.label_tag }}</label>
{{ field }}
{% endfor %}
forms.py
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body',)
You need to override view's form_valid method to update new comment instance with current user and film:
class CommentCreate(CreateView):
model = Comment
fields = ['body']
def form_valid(self, form):
film = Film.objects.get(pk=self.kwargs['film_id'])
form.instance.user = self.request.user
form.instance.film = film
return super(CommentCreate, self).form_valid(form)
To fix "No URL redirect to" you can add get_absolute_url() method to the Comment model:
def get_absolute_url(self):
return reverse('detail', kwargs={'pk': self.film.pk})

Return a list of objects from selected tags

I am trying to figure out what I thought would be easy to find an answer for. I am using django-taggit in a project and I simply want to return a list of objects when a tag is selected. I have tried this:
How do I create list and detail views for django-taggit?
But I cannot get it to work. It just renders a blank page. I think the problem is in my template code. Maybe someone can point me in the direction. Any help would be appreciated..Thanks a lot.
Here is my code:
models.py
from taggit.managers import TaggableManager
from django.template.defaultfilters import slugify
from ckeditor.fields import RichTextField
from taggit.models import TaggedItemBase
class Tagged(TaggedItemBase):
content_object = models.ForeignKey('Shows')
class Shows(models.Model):
title = models.CharField(max_length=40)
slug = models.SlugField(null=True, blank=True, unique=True)
tags = TaggableManager(through=Tagged)
hosts = models.ManyToManyField('Host', blank=True, null=True)
featured = models.BooleanField(default=False)
thumbnail = FilerImageField(related_name="thumbnail", help_text="Image should be: 550 X 350.")
playing_next = models.DateTimeField(null=True, blank=True)
description = RichTextField()
views.py:
class TaggedList(ListView):
queryset = Shows.objects.all()
paginate_by = 10
template_name = "tagged.html"
def get_queryset(self):
return Shows.objects.filter(tags__name__in=[self.kwargs['tag']])
urls.py:
urlpatterns = patterns('radio.views',
url(r'^$', 'main', name='app_main'),
url(r'^(?P<slug>[^\.]+)/detail/$', 'detail_view', name='detailsview'),
url(r'^(?P<tag>\w+)/$', TaggedList.as_view()),
url(r'^tagged/(?P<tag>\w+)/$', TaggedList.as_view())
)
Template code:
{% for objects in object_list %}
{{ objects.title }}
{{ objects.tag }}
{{ objects.slug }}
------
{% endfor %}
did you iterate over object_list in template? Because default list name in LiseView is object_list: doc: https://docs.djangoproject.com/en/dev/ref/class-based-views/generic-display/#listview

Categories

Resources