Django 2.1 passing a variable to template, - python

Have a question here about passing a variable into a Django template. The goal is to filter a set of photos based off the type of photography. I initially wanted to do it from S3 and the folder that it was in, but that's a little beyond my skill at the moment. I went with just creating different url's that account for that. The issue I'm having is that I'd like to pass the variable into the template that extends the base_layout.html, but it won't render anything for that variable. Am I just miss-understanding how to do it?
Model.py
from django.db import models
# Create your models here.
class Gallery(models.Model):
title = models.CharField(max_length = 50)
body = models.TextField(max_length = 500)
created = models.DateTimeField(auto_now_add = True)
thumb = models.ImageField(default = 'default.jpg', blank = True)
slug = models.SlugField(blank = True)
order = models.CharField(max_length = 2, blank = True)
def __str__(self):
return self.title
def body_preview(self):
return self.body[:50]
class photoUrl(models.Model):
url = models.CharField(max_length = 128)
uploaded_on = models.DateTimeField(auto_now_add = True)
class Photos(models.Model):
title = models.CharField(max_length = 50)
picture = models.ImageField(blank = True)
created = models.DateTimeField(auto_now_add = True)
catagory = models.CharField(max_length=256, choices=[('wedding', 'wedding'), ('portrait', 'portrait'), ('landscape', 'landscape'), ('boudoir', 'boudoir'),], blank = True)
def __str__(self):
return self.title
views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.urls import reverse
from . models import Photos
# Create your views here.
def photo_wedding(request):
photo_list = Photos.objects.filter(catagory = 'wedding').order_by('created')
photoCat = 'Wedding'
return render(request, 'gallery/gallery.html', {'photo_list' : photo_list}, {'photoCat' : photoCat})
urls.py
from django.contrib import admin
from django.urls import path
from . import views
app_name='gallery'
urlpatterns = [
path('wedding/', views.photo_wedding, name='wedding'),
path('portrait/', views.photo_portrait, name='portrait'),
path('landscape/', views.photo_landscape, name='landscape'),
path('boudoir/', views.photo_boudoir, name='boudoir'),
]
gallery.html
{% extends 'gallery/base_layout.html' %}
{% load static %}
{% block gallery %}
<div class="gallery" id="gallery">
<div class="container">
<div class="w3l-heading">
<h3>{{photoCat}}</h3>
<div class="w3ls-border"> </div>
</div>
</div>
{% endblock gallery %}

From the definition of render:
render(request, template_name, context=None, content_type=None, status=None, using=None)
Combines a given template with a given context dictionary and returns an HttpResponse object with that rendered text.
the render method takes the first parameter as a request, the second parameter as template_name and the third parameter is a context which is of type dictionary you choose to pass to the template, you can access all the values of dictionary with the key.
So your method should look like below:
def photo_wedding(request):
photo_list = Photos.objects.filter(catagory = 'wedding').order_by('created')
photoCat = 'Wedding'
return render(request, 'gallery/gallery.html', {'photo_list' : photo_list, 'photoCat' : photoCat})

Why are you passing two dictionaries. Just add a key. That is the context data.
In class based views you can also overload the method get_context_data

With the render() function, the third argument is the context. The context is a dictionary used to send variable to templates. No need to pass two dicts
def photo_wedding(request):
photo_list = Photos.objects.filter(catagory = 'wedding').order_by('created')
photoCat = 'Wedding'
context = {'photo_list' : photo_list,'photoCat' : photoCat}
return render(request, 'gallery/gallery.html', context)

Related

Search field in Django is not redirecting to detail view

I am adding a search field in my blog so people can put the name of the blog they want to read and a list of items come up and after clicking on any of the list items, it will redirect to the detail view. However, in my case,If I put anything in search, it is not redirecting to a detail view but going to http://127.0.0.1:8000/home/search/2 instead of http://127.0.0.1:8000/home/list/2/.
I have posted my models, views, URLs and template files below.
Is there any reverse method I need to use here to redirect and what changes I need in my template file?
models.py
from django.db import models
class Category(models.Model):
cat_name = models.CharField(max_length = 256, blank = True)
def __str__(self):
return self.cat_name
class Blog(models.Model):
name = models.CharField(max_length = 256, blank = True)
pub_date = models.DateTimeField('date published')
text = models.TextField(blank = True)
category = models.ForeignKey(Category, on_delete=models.CASCADE,
related_name='categories', verbose_name = 'blog_categories')
def __str__(self):
return self.name
views.py
from django.shortcuts import render
from homepage.models import Blog
from django.views.generic import TemplateView, ListView, DetailView
from homepage import models
from django.db.models import Q
class Home(TemplateView):
template_name = 'homepage/index.html'
class BlogListView(ListView):
context_object_name = 'blogs'
model = models.Blog
template_name = 'homepage/blog_list.html'
class BlogDetailView(DetailView):
context_object_name = 'blogs_detail'
model = models.Blog
template_name = 'homepage/blog_detail.html'
def get_queryset(self):
query = self.request.GET.get('q')
return Blog.objects.filter(
Q(name__icontains = query) | Q(name__icontains = query) )
class SearchResultsListView(ListView):
model = Blog
context_object_name = 'blog_list'
template_name = 'homepage/search_result_list.html'
def get_queryset(self):
query = self.request.GET.get('q')
return Blog.objects.filter(
Q(name__icontains = query) | Q(name__icontains = query) )
urls.py
from django.urls import path
from homepage import views
from homepage.views import SearchResultsListView
app_name = 'homepage'
urlpatterns = [
path('', views.Home.as_view(), name = 'index'),
path('list/', views.BlogListView.as_view(), name = 'blog-list'),
path('list/<int:pk>/', views.BlogDetailView.as_view(), name = 'blog-list'),
path('search/', SearchResultsListView.as_view(), name = 'search_result'),
]
index.html
<div class="grid-item-1">
<h1>G</h1>
<input type="button" name="" value="Back to Home" placeholder="">
<form action="{% url 'home:search_result' %}" method = 'get'>
<input type="text" name="q" placeholder="search">
</form>
</div>
search_result_list.html
{% for blog in blog_list %}
<ul>
<li>
{{blog.name}}
{{blog.address}}
here
</li>
</ul>
{% endfor %}
the URL redirects to http://127.0.0.1:8000/home/search/2 and its a 404 page.
how can I redirect it to the detail view page http://127.0.0.1:8000/home/list/1/ and see the detail of the list pulled by search result.
The reason this happens is because {{ blog.id }} just contains a number, for example 2. It will be appended to the URL. You can fix this by prepending the URL with a slash (/) and write list with:
{{blog.name}}
{{blog.address}}
here
But it is likely better to make use of the {% url … %} template tag [Django-doc]:
{{blog.name}}
{{blog.address}}
here
In your BlogDetailView, there is no q parameter, so you can remove the get_queryset:
class BlogDetailView(DetailView):
context_object_name = 'blogs_detail'
model = models.Blog
template_name = 'homepage/blog_detail.html'
# no get_queryset
Furthermore perhaps you should consider renaming the DetailView from blog-list, to blog-detail, or something similar.

Django many to many relationsip update field

I have two models many to many relationships, I am trying to update a field by subtraction two values from the two models and save the changes to the db.
class LeaveBalance(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,)
Leave_current_balance= models.FloatField(null=True, blank=True, default=None)
Year=models.CharField(max_length=100,default='')
def __unicode__(self):
return self.Year
class NewLeave(models.Model):
user=models.ForeignKey(User,default='',on_delete=models.CASCADE)
leave_balance=models.ManyToManyField(Leave_Balance)
leave=(
('annual','annual'),
('sick','sick'),
)
Leave_type=models.CharField(max_length=100,choices=leave,blank=False,default='')
Total_working_days=models.FloatField(null=True, blank=False)
DirAuth=(
('Pending','Pending'),
('Approved','Approved'),
('Rejected','Rejected'),
)
Director_Authorization_Status=models.CharField(max_length=100,choices=DirAuth,default='Pending',blank=False)
Date_Authorized=models.DateField(null=True,blank=False)
Authorized_by_Director=models.CharField(max_length=100,default='',blank=False)
def __unicode__(self):
return self.Leave_type
here is my form, when a leave is submitted the director is notified by email. the director can login to the system to approve the leave using the form. once the leave is approved, I want to adjust the Leave_current_balance.
class DirectorForm(forms.ModelForm):
class Meta:
model=NewLeave
fields=('Director_Authorization_Status','Authorized_by_Director','Date_Authorized',)
widgets={
'Date_Authorized':DateInput()
}
This is the function that allows the director to approve the leave which throws the error: u'Leave_current_balance'
def unitDirectorForm(request,id):
if request.method=='POST':
getstaffid=NewLeave.objects.get(id=id)
form = DirectorForm(request.POST, instance=getstaffid)
if form.is_valid():
getstaffid = form.save(commit=False)
getstaffid.save()
total_days = getstaffid.Total_working_days
current_balance = getstaffid.user.leave_balance.Leave_current_balance
diff_balance = current_balance - total_days
current_balance = diff_balance
current_balance=form.fields['Leave_current_balance']
current_balance.save()
getstaffid.leave_balance.add(current_balance)
return HttpResponse('You have successfuly Authorise the leave')
else:
#getstaffid=NewLeave.objects.get(id=id)
form=DirectorForm()
#c_balance=Leave_Balance.objects.get()
balance_form = leavebbalanceForm()
return render(request,'managerauthorisedform.html',{'form':form})
You could get this working in another way too. For example:
def on_balance(user_id):
id = user_id
c_balance = LeaveBalance.objects.get(user=id)
current_balance = c_balance.Leave_current_balance
t_days = NewLeave.objects.get(user=id)
total_days = t_days.Total_working_days
current_balance = current_balance - total_days
balance = LeaveBalance.objects.get(user=id)
balance.leave_balance = current_balance
balance.save()
And the above does not cause combined expression error.
Or just a bit simpler:
def on_balance(user_id):
id = user_id
c_balance = LeaveBalance.objects.get(user=id)
current_balance = c_balance.Leave_current_balance
t_days = NewLeave.objects.get(user=id)
total_days = t_days.Total_working_days
current_balance = current_balance - total_days
c_balance.leave_balance = current_balance
c_balance.save()
UPDATE - restructuring the models and views
So the above code works if it's used in an appropriate model/form/view structure, but instead I would suggest you to restructure the whole thing starting from your models. I give you a simple working example (I tested this and works):
My app name is in this example: Myusers1 , so where ever you see that, you can change that name to your app name if needed.
So the Models:
from django.db import models
from django.conf import settings
from django.utils.text import slugify
from django.db.models import F
from django.urls import reverse
class Director(models.Model):
name = models.CharField(max_length = 100, default = '', null = True, verbose_name = 'Name of Director')
def __str__(self):
return self.name
class Staff(models.Model):
TYPE_CHOICES = (
('REGULAR', 'Regular'),
('MANAGER', 'Manager'),
('FRESH', 'Fresh'),
)
name = models.CharField(max_length = 100, default = '', null = True, unique=True, verbose_name = 'Name of staff member')
birthdate = models.DateField(blank = True, verbose_name = 'Birth date')
department = models.CharField(max_length = 100, default = '', null = True, verbose_name = 'Department')
# department could also be a choice field from another table
type = models.CharField(max_length = 20, choices = TYPE_CHOICES, verbose_name = 'Position Type', null = True)
def __str__(self):
return self.name
class LeaveBalance(models.Model):
staff = models.ForeignKey(Staff, to_field='name', on_delete = models.CASCADE, primary_key = False)
Leave_current_balance = models.FloatField(null = True, blank = True, default = '')
date_updated = models.DateTimeField(auto_now_add = True, verbose_name = 'Last Updated date and time')
def __unicode__(self):
return self.Leave_current_balance
class NewLeave(models.Model):
all_staff = Staff.objects.values()
STAFF_CHOICES = [(d['name'], d['name']) for d in all_staff]
staff = models.CharField(max_length = 100, choices = STAFF_CHOICES)
leave_days_to_approve_now = models.FloatField(null = True, blank = False, default = 5.0, verbose_name = 'Leave days for approval now')
LEAVE_CHOICES=(
('annual','annual'),
('sick','sick'),
)
Leave_type = models.CharField(max_length = 100, choices = LEAVE_CHOICES, blank = False, default = '', verbose_name = 'Type of leave')
Total_working_days = models.FloatField(null = True, blank = False, default = 200.0)
APPROVAL_STATUS_CHOICES=(
('Pending','Pending'),
('Approved','Approved'),
('Rejected','Rejected'),
)
Director_Authorization_Status = models.CharField(max_length = 100, choices = APPROVAL_STATUS_CHOICES, default = 'Pending', blank = False)
Date_Authorized = models.DateTimeField(auto_now_add = True, verbose_name = 'date and time of Authorization')
all_directors = Director.objects.values()
DIRECTOR_CHOICES = [(d['name'], d['name']) for d in all_directors]
Authorized_by_Director = models.CharField(max_length = 100, choices = DIRECTOR_CHOICES, default = '', blank = False)
def __unicode__(self):
return self.Leave_type
def get_absolute_url(self):
pass
# return reverse('newleave-detail', kwargs={'pk': self.pk}) # this should be worked out too
def save(self, *args, **kwargs):
staff_name = self.staff
this_staff = Staff.objects.get(name=staff_name)
name = this_staff.name
minus_value = self.leave_days_to_approve_now
if (self.Director_Authorization_Status == 'Approved'):
LeaveBalance.objects.filter(staff = name).update(Leave_current_balance=F('Leave_current_balance') - minus_value)
return super(NewLeave, self).save(*args, **kwargs)
else:
return super(NewLeave, self).save(*args, **kwargs)
In the above, you can see that I created a Director and Staff Model in which you can set as many staff and directors as you want in the Admin back-end. I created the staff Model because maybe not all of the staff will be users, so I think it is just a bit better to keep them separately in the DB from Users.
Important: first create the Director and Staff Models then migrate immediately since the other two tables will depend on them. Then you can create the other two Models.
I also do not think that in the LeaveBalance Model you should keep more things than what I put there. I think Year field for example redundant, since you can always filter by the date and date range in you want in the database.
Then the views (I used simple views only directly from the Models). With using these view classes you do not have to create Forms since it is automatically created from the Models and you can handle them with different functions/methods as Forms in the Views and in the Model classes.
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.urls import reverse
from django.views import View
from django.views.generic.detail import DetailView
from django.views.generic import ListView, TemplateView
from django.template import loader
from .models import NewLeave
from django.views.generic.edit import FormView, CreateView, DeleteView, UpdateView
from django.urls import reverse_lazy
class NewLeaveCreate(CreateView):
model = NewLeave
fields = '__all__'
def form_valid(self, form):
super().form_valid(form)
auth_status = form.cleaned_data['Director_Authorization_Status']
if (auth_status == 'Approved'):
return redirect('Myusers1:success_page')
elif (auth_status == 'Pending'):
return redirect('Myusers1:pending_success')
else:
return redirect('Myusers1:rejected_success')
class NewLeaveUpdate(UpdateView):
model = NewLeave
fields = '__all__'
class NewLeaveDelete(DeleteView):
model = NewLeave
success_url = reverse_lazy('newleave-list')
class NewLeaveDetail(DetailView):
model = NewLeave
template_name = 'myusers1/newleave_detail.html'
context_object_name = 'newleave'
queryset = NewLeave.objects.all()
def get_context_data(self, **kwargs):
context = super(NewLeaveDetail, self).get_context_data(**kwargs)
context['leave_details'] = NewLeave.objects.filter(pk=pk)
return context
class Success(TemplateView):
template_name = "authorizationsuccess.html"
class pending_success(TemplateView):
template_name = "pendingsuccess.html"
class rejected_success(TemplateView):
template_name = "rejectedsuccess.html"
Then in urls.py I defined the required urls:
from django.urls import path, re_path
from . import views
from . import models
app_name = 'Myusers1'
urlpatterns = [
path('newleave/add/', views.NewLeaveCreate.as_view(), name='newleave-add'),
path('newleave/<int:pk>/', views.NewLeaveUpdate.as_view(), name='newleave-update'),
path('newleave/<int:pk>/delete/', views.NewLeaveDelete.as_view(), name='newleave-delete'),
# path('newleave/add/<int:pk>/', views.NewLeaveDetail.as_view(), name='newleave-detail'),
path('newleave/add/success/', views.Success.as_view(), name='success_page'),
path('newleave/add/pendingleaves/', views.pending_success.as_view(), name='pending_success'),
path('newleave/add/rejectedleaves/', views.rejected_success.as_view(), name='rejected_success'),
]
I have not worked out all of the url paths.
And the templates like the newleave_form.html
{% extends 'myusers1/base.html' %}
{% block content %}
<div class"container">
<div class="col col-lg-2">
<h2>New Leave Form</h2>
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Authorize</button>
</form>
</div>
</div>
{% endblock %}
And there should be at least 3 different redirect template when a they submit a NewLeave form, authorized, pending, and rejected templates. I just give here the simple authorized success template:
{% extends 'myusers1/base.html' %}
{% block content %}
<h2>Thank you! The authorization of leave was successful</h2>
<div class="col-xs-12 .col-md-8"><li> Back to Home </li></div>
{% endblock %}
Do not forget to migrate and then register the models in the admin.py. Then you should create some staff in the database and few directors to try the above. I hope that the above can give you some direction to accomplish what you are up to with your project. With this I just wanted to give you a very simple example. (You have to create all of the other necessary templates and views).
If you create a new app for trying the above then in your project main urls.py file you should reference (include) your app urls like this with adding one extra line to your project' urls.py file. Then all of your new app urls has to be defined in your app's urls.py file:
This is how your main project's urls.py looks like then:
urlpatterns = [
path('admin/', admin.site.urls),
path('myusers1/', include('Myusers1.urls')),
# so in your case:
path('myapp/', include('myapp.urls')),
]
(you have to change the Myusers1 to your app name,)
And of course we could do a lot of other things with the Model Manager in Django: https://docs.djangoproject.com/en/2.1/topics/db/managers/
You have to call refresh_from_db on balance. like balance.refresh_from_db() to get the updated values from database.

Tango with Django Chapter 6 - URL won't work

I have been going through "Tango with Django" and have been unable to solve this problem myself or by looking online. Would anyone know how to approach it?
The relevant page should be opened when I click on the link, but none are going through, which makes me assume something in my view.py file is wrong or even in my url.py or model.py file (index.html seems to be working correctly).
Views.py
# Create your views here.
from django.http import HttpResponse
from django.shortcuts import render
from Spaces.models import Category, Page
def index(request):
# Query the databse for a list of ALL categories currently stored.
# Order the categories by no likes in descending order .
# Retrieve the top 5 only - or all if less than 5.
# Place the list in context_dict dictionary
# that will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
context_dict = {'categories': category_list}
# Render the response and send it back!
return render(request, 'Spaces/index.html', context=context_dict)
def about(request):
context_dict = {'boldmessage':"Crunchy, creamy, cookie, candy, cupcake!"}
return render(request, 'Spaces/about.html', context=context_dict)
def show_category(request, category_name_slug):
# Create a context dictionary which we can pass
# to the template rendering engine.
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
# Retrieve all of the associated pages.
# Note that filter() will return a list of page objects or an empty list
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from
# the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything -
# the template will display the "no category" message for us.
context_dict['category'] = None
context_dict['pages'] = None
# Go render the response and return it to the client.
return render(request, 'Spaces/category.html', context_dict)
Urls.py
from django.conf.urls import url
from Spaces import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^about/$', views.about, name='about'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$',
views.show_category, name='show_category'),
]
models.py
from django.db import models
from django.template.defaultfilters import slugify
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True, blank=True, null=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = 'categories'
def __str__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category, on_delete=models.PROTECT)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __str__(self): # For Python 2, use __unicode__ too
return self.title
index.html
<!DOCTYPE html>
{% load staticfiles %}
<html>
<head>
<title>Spaces</title>
</head>
<body>
<h1>Spaces says...</h1>
<div>hey there partner!</div>
<div>
{% if categories %}
<ul>
{% for category in categories %}
<li>
{{ category.name }}
</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no categories present.</strong>
{% endif %}
</div>
<div>
About Space<br />
<img src="{% static 'images/Spaces.jpg' %}" alt="Picture of Rango" />
</div>
</body>
</html>
populate_spaces.py (test script)
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'Space.settings')
import django
django.setup()
from Spaces.models import Category, Page
def populate():
#First, we will create lists of dictionaries containing the pages
# we want to add into each category.
# Then we will create a dictionary of dictionaries for our categories.
# This might seem a little bit confusing, but it allows us to iterate
# through each data structure, and add the data to our models.
python_pages = [
{"title": "Prahran",
"url":"http://docs.python.org/2/tutorial/", "views":20},
{"title": "South Yarra",
"url":"http://docs.python.org/2/tutorial/", "views":25},
{"title": "etcetera",
"url":"http://docs.python.org/2/tutorial/", "views":35}
]
django_pages = [
{"title" : "Official Django Tutorial",
"url" :"https://docs.djangoproject.com/en/1.9/intro/tutorial01/", "views":36},
{"title":"Django Rocks",
"url":"http://www.djangorocks.com/", "views":23},
{"title":"How to Tango with Django",
"url":"http://www.tangowithdjango.com/", "views":45}
]
other_pages = [
{"title":"Bottle",
"url":"http://bottlepy.org/docs/dev/", "views":3},
{"title":"Flask",
"url":"http://flask.pocoo.org",
"views":34}]
cats = {"Python": {"pages": python_pages, "views": 128, "likes":64},
"Django": {"pages": django_pages, "views": 64, "likes":32},
"Other Frameworks": {"pages": other_pages, "views": 32, "likes":16} }
# If you want to add more categories or pages,
# Add them to the dictionaries above.
# The code below goes through the cats dictionary, then adds each category
# and then adds all the associated pages for that category.
for cat, cat_data in cats.items():
c = add_cat(cat,cat_data)
for p in cat_data["pages"]:
add_page(c, p["title"], p["url"], p["views"])
#Print out the categories we have added.
for c in Category.objects.all():
for p in Page.objects.filter(category=c):
print("-{0})-{1}".format(str(c), str(p)))
def add_page(cat, title, url, views=0):
p = Page.objects.get_or_create(category=cat, title=title)[0]
p.url=url
p.views=views
p.save()
return p
def add_cat(name, cat_data):
c = Category.objects.get_or_create(name=name)[0]
c.likes = cat_data["likes"]
c.views = cat_data["views"]
c.save()
return c
# Start execution here!
if __name__ == '__main__':
print("Starting Spaces population script...")
populate()
I fixed the issue.
Essentially I had indented a return function in my view.py file incorrectly!

type object 'Album' has no attribute 'object'

I'm new to Django and web coding.
I'm following Bucky tuts: Django Tutorial for Beginners - 29 - Generic Views
& I'm trying to get my music ( index ) page , but it gives me that error in the browser :
AttributeError at /music/ type object 'Album' has no attribute
'object'
& here's my views.py :
from django.http import HttpResponse, Http404
from django.shortcuts import render , get_object_or_404
from .models import Album,song
from django.views import generic
"""
def index(request):
all_albums = Album.objects.all()
context = {'all_albums': all_albums}
return render(request, 'music/index.html', context)
"""
class IndexView (generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums'
def get_queryset(self):
return Album.object.all()
'''
class DetailView (generic.DetailView):
model = Album
template_name = "music/details.html"
'''
def details(request, album_id):
try:
album = Album.objects.get(pk=album_id)
except Album.DoesNotExist:
raise Http404("Album Does Not Exists !")
return render(request, 'music/details.html', {'album': album})
def favourite (request , album_id):
album = get_object_or_404 (Album , pk=album_id)
try:
selected_song = album.song_set.get(pk=request.POST['song'])
except(KeyError, song.DoesNotExist):
return render(request, 'music/details.html', {
'album':album,
'error_message': "you entered wrong"
})
else:
selected_song.is_favorite = False
selected_song.save()
return render(request,'music/details.html' , {'album':album})
models.py
from django.db import models
# Create your models here.
class Album (models.Model):
artist = models.CharField(max_length = 100)
album_title = models.CharField(max_length = 100)
genre = models.CharField(max_length = 50)
album_logo = models.CharField(max_length = 1000)
def __str__(self):
return self.album_title + " - " + self.artist
class song (models.Model):
album = models.ForeignKey(Album , on_delete=models.CASCADE)
file_type = models.CharField(max_length = 10)
song_title = models.CharField(max_length = 100)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
index.html
{% extends 'music/base.html' %}
{% block title %}Main : MuSiC {% endblock %}
{% block body %}
<ul>
{% for album in all_albums %}
<li>{{ album.album_title }}</li>
{% endfor %}
</ul>
{% endblock %}
#/music/{{ album.id }}
project structure
{ (website) project dir }
|-music
..|-migrations
..|-static
..|-templates
....|-music
......|-base.html
......|-details.html
......|-index.html
|-__init__.py
|-admin.py
|-apps.py
|-models.py
|-tests.py
|-urls.py
|-views.py
|-website
..|-__init__.py
..|-settings.py
..|-urls.py
..|-wsgi.py
|-db.sqlite3
|-manage.py
and I don't know where is the problem :(
btw, lot's of coding terms I still didn't learned , that's why I may ask alot ever I searched for a solution but didn't understand the answer from other question's answers .
Album.object does not exist; you should've written Album.objects.
class IndexView (generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums'
def get_queryset(self):
# return Album.object.all() <-- Remove this
return Album.objects.all()
As a side note, reserved words cannot be python attributes. This is by design, because disallowing these words makes parsing substantially easier.
Why can't attribute names be Python keywords?

Trouble with order.by('?') .first() to get random content in Django

Update #4:
The for loop in slider.html is currently not pulling content after the last update. Slider.html was randomized; however, I'm getting four of the same story and the urls are not going to their appropriate detailed view page anymore.
List.html has been fixed and is now random.
slider.html - This section is still wonky, (updated - 4:19 p.m.)
{% for random_article in random_articles %}
<div class="slider">
<div class="group visible">
<div class="sliderItem">
<img src="{{random_article.relatedImage}}" alt="" class="sliderPicture">
<p class="related">{{random_article.title}}</p>
</div><!-- /.sliderItem -->
</div><!-- /.group -->
</div><!-- /.slider -->
{% endfor %}
Here is the URL error when I click to detailed view:
NoReverseMatch at /last-us
Reverse for 'detailed' with arguments '()' and keyword arguments '{u'slug': ''}' not found. 1 pattern(s) tried: ['(?P<slug>\\S+)']
New culprits (for why slider.html isn't working)
urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns(
'',
url(r'^$', views.BlogIndex.as_view(), name="list"),
url(r'^(?P<slug>\S+)', views.BlogDetail.as_view(), name="detailed"),
)
views.py (updated - 4:19 p.m.)
Added context['random_slider'] = FullArticle.objects.order_by('?')[:4] but I don't think this is the right approach. So that I can get four different articles vs. four of the same article randomized.
from django.views import generic
from . import models
from .models import FullArticle
# Create your views here.
class BlogIndex(generic.ListView):
queryset = models.FullArticle.objects.published()
template_name = "list.html"
def get_context_data(self, **kwargs):
context = super(BlogIndex, self).get_context_data(**kwargs)
context['random_article'] = FullArticle.objects.order_by('?').first()
return context
class BlogDetail(generic.DetailView):
model = models.FullArticle
template_name = "detailed.html"
def get_context_data(self, **kwargs):
context = super(BlogDetail, self).get_context_data(**kwargs)
context['object_list'] = models.FullArticle.objects.published()
return context
def get_context_data(self, **kwargs):
context = super(BlogDetail, self).get_context_data(**kwargs)
context['random_articles'] = FullArticle.objects.exclude(
pk=self.get_object().pk
).order_by('?')[:4]
return context
Original Problem
I'm using FullArticle.objects.order_by('?').first() to get a random article from my database, but it's currently giving the same article when I refresh the page. There is probably something missing from my models, view or how I'm calling it (using slice) in list.html or slider.html that is causing the problem.
The two parts I'm looking to make random on page load:
list.html (changed so that it's {{random_article.}} ) - This section of the problem is fixed.
<div class="mainContent clearfix">
<div class="wrapper">
<h1>Top 10 Video Games</h1>
{% for article in object_list|slice:":1" %}
<p class="date">{{article.pubDate|date:"l, F j, Y" }}</p> | <p class="author">{{article.author}}</p>
<img src="{{article.heroImage}}" alt="" class="mediumImage">
<p class="caption">{{article.body|truncatewords:"80"}}</p>
{% endfor %}
models.py
from django.db import models
from django.core.urlresolvers import reverse
# Create your models here.
class FullArticleQuerySet(models.QuerySet):
def published(self):
return self.filter(publish=True)
class FullArticle(models.Model):
title = models.CharField(max_length=150)
author = models.CharField(max_length=150)
slug = models.SlugField(max_length=200, unique=True)
pubDate = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
category = models.CharField(max_length=150)
heroImage = models.CharField(max_length=250, blank=True)
relatedImage = models.CharField(max_length=250, blank=True)
body = models.TextField()
publish = models.BooleanField(default=True)
gameRank = models.CharField(max_length=150, blank=True, null=True)
objects = FullArticleQuerySet.as_manager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("FullArticle_detailed", kwargs={"slug": self.slug})
class Meta:
verbose_name = "Blog entry"
verbose_name_plural = "Blog Entries"
ordering = ["-pubDate"]
The problem is that you are setting the value of a class attribute at "compile time" and not each time the view is called. Instead, you could do:
class BlogIndex(generic.ListView):
queryset = models.FullArticle.objects.published()
template_name = "list.html"
def random_article(self):
return = FullArticle.objects.order_by('?').first()
Or:
class BlogIndex(generic.ListView):
queryset = models.FullArticle.objects.published()
template_name = "list.html"
def get_context_data(self, **kwargs):
context = super(BlogIndex, self).get_context_data(**kwargs)
context['random_article'] = FullArticle.objects.order_by('?').first()
return context
[update]
In list html, I only need one random article. In slider.html, I need four random articles, would I just tack on FullArticle.objects.order_by('?')[:4] somewhere in that def get_context_data snippet?
Yes. Make it plural in the view (don't forget to exclude the main article from the side list):
class BlogDetail(generic.DetailView):
model = models.FullArticle
template_name = "detailed.html"
def get_context_data(self, **kwargs):
context = super(BlogDetail, self).get_context_data(**kwargs)
context['random_articles'] = FullArticle.objects.exclude(
pk=self.get_object().pk
).order_by('?')[:4]
return context
At the template, do:
{% for random_article in random_articles %}
<div class="sliderItem">
<img src="{{random_article.relatedImage}}" alt="" class="sliderPicture">
<p class="related">{{random_article.title}}</p>
</div><!-- /.sliderItem -->
{% endfor %}
The generic listview just passes an object_list as context based on the queryset. In your case it means you have to either change the value of queryset in your view or override the get_context_data method and add your random item to it.
https://docs.djangoproject.com/en/dev/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.get_context_data

Categories