I'm building an e-commerce (like) project. While running the program, from Homepage, if we select a product I got hit by this error, instead of showing that product details. Now I can't figure out how to fix this please help me to fix it.enter image description here
Here's my Models.py
class Category(models.Model):
name=models.CharField(max_length=250,unique=True)
slug=models.SlugField(max_length=250,unique=True)
desc=models.TextField(blank=True)
image=models.ImageField(upload_to='category',blank=True)
class Meta:
ordering=('name',)
verbose_name='category'
verbose_name_plural='categories'
# for menu linking (url)
def get_url(self):
return reverse("ecommerce_app:products_by_category",args=[self.slug])
def __str__(self):
return '{}'.format(self.name)
class Product(models.Model):
name=models.CharField(max_length=250,unique=True)
slug = models.SlugField(max_length=250, unique=True)
desc = models.TextField(blank=True)
image = models.ImageField(upload_to='product', blank=True)
category=models.ForeignKey(Category,on_delete=models.CASCADE)
price=models.DecimalField(max_digits=10,decimal_places=2)
stock=models.IntegerField()
available=models.BooleanField(default=True)
created=models.DateTimeField(auto_now=True)
updated=models.DateTimeField(auto_now=True)
class Meta:
ordering = ('name',)
verbose_name = 'product'
verbose_name_plural = 'products'
# for url
def get_url(self):
return reverse("ecommerce_app:ProdCatDetails",args=[self.category.slug,self.slug])
def __str__(self):
return '{}'.format(self.name)
Her's my Urls.py
from django.urls import path
from . import views
app_name='ecommerce_app'
urlpatterns=[
path('',views.allProdCat,name='allProdCat'),
# for special urls for Category
path('<slug:c_slug>/',views.allProdCat,name='products_by_category'),
# for special urls for Product Details
path('<slug:c_slug>/<slug:product_slug>/',views.ProdCatDetails,name='ProdCatDetails'),
]
Here's my Views.py
from django.http import HttpResponse
from .models import Category,Product
from django.shortcuts import render,get_object_or_404
# Create your views here.
def home(request):
return HttpResponse("Hello")
def allProdCat(request,c_slug=None):
c_page=None
products=None
if c_slug!=None:
c_page=get_object_or_404(Category,slug=c_slug)
products=Product.objects.all().filter(category=c_page,available=True)
else:
products=Product.objects.all().filter(available=True)
return render(request,'category.html',{'category':c_page,'products':products})
# For product details
def ProdCatDetails(request,c_slug,product_slug):
try:
product=Product.objects.get(category__product=c_slug,slug=product_slug)
except Exception as e:
raise e
return render(request,'product.htmal',{'product':product})
If you filter with:
product = Product.objects.get(category=c_slug, slug=product_slug)
You will filter on the field the product ForeignKey is referring to. Since that is not specified, this is the primary key, and thus an AutoField.
You can filter with:
# filter on the slug ↓
product = Product.objects.get(category__slug=c_slug, slug=product_slug)
Related
can anyone tell me how combine detailview with list view and show info in the same template, i'll explain you, i'm learning Django and i am trying to create a Questions and Answer web app, and i need to show the question with all its awnsers, i need in my detailview for a specific question show below all it awsers, something like stackoverflow does
#models.py
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
# Create your models here.
class Question(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="question", null=True)
name = models.CharField(max_length=100)
description = models.TextField(max_length=100)
date = models.DateTimeField(auto_now_add=True)
cant_resp = models.IntegerField(default=0)
question_type = models.CharField(max_length=50, choices=QUESTION_TYPES_CHOICES)
def __str__(self):
return self.description
class Anwser(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="anwser", null=True)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.TextField(max_length=400)
date= models.DateTimeField(auto_now_add=True)
#and this are my views.py
from django.shortcuts import render, redirect
from django.urls import reverse, reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from .forms import QuestionForm, AnwserForm
from .models import Question
# Create your views here.
class QuestionListView(LoginRequiredMixin, generic.ListView):
template_name = 'anwserquestions/question_list.html'
context_object_name = 'questions'
def get_queryset(self):
return Question.objects.all()
def createquestion(response):
if response.method == "POST":
print("Its POST method")
form = QuestionForm(response.POST)
# user =response.user
if form.is_valid():
name = form.cleaned_data["name"]
description=form.cleaned_data['description'],
question_type=form.cleaned_data['question_type'],
# date=form.cleaned_data['date'],
t = Question(name=name, description=description, question_type=question_type, cant_resp=0)
t.save()
response.user.question.add(t) # adds the to do list to the current logged in user
# return HttpResponseRedirect("/%i" %t.id)
return redirect('anwserquestions:question-list')
else:
form = QuestionForm()
return render(response, "anwserquestions/question_create.html", {"form":form})
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_queryset(self):
return Question.objects.all()
class QuestionDeleteView(LoginRequiredMixin, generic.DeleteView):
template_name = 'anwserquestions/question_delete.html'
context_object_name = 'question'
success_url = reverse_lazy('anwserquestions:question-delete')
# def get_queryset(self):
# return Question.objects.all()
You can get the related answers by including it in the views context, so you QuestionDetailView becomes
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_context_data(self, **kwargs):
context = super(QuestionDetailView, self).get_context_data(**kwargs)
context['answers'] = Answer.objects.filter(post=self.get_object())
return context
I am creating a simple car dealership application in Django 3 whereby when goes to a detail page of a category it should list all cars that belong in that category , so in my case car objects are dependent objects of their respective category . I have tried to implement this using get_context_data() method and referencing the two respective models within the DetailView here is my code
models.py category
from django.db import models
from django.urls import reverse
# Create your models here.
class Category(models.Model):
name = models.CharField(null=False, blank=False, max_length=20)
description = models.TextField(null=False, blank=False, max_length=120)
image = models.ImageField(upload_to='images/')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('category_detail', args=[str(self.id)])
models.py cars
from django.db import models
from django.urls import reverse
from categories.models import Category
# Create your models here.
class Car(models.Model):
image = models.ImageField(upload_to='images/cars/')
make = models.CharField(null=False, blank=False, max_length=30)
model = models.CharField(null=False, blank=False, max_length=30)
year = models.IntegerField(null=False, blank=False)
transmission = models.CharField(null=False, blank=False, max_length=30)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.model
def get_absolute_url(self):
return reverse('car_detail', args=[str(self.id)])
views categories
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Category
from cars.models import Car
# Create your views here.
class CategoryList(ListView):
model = Category
template_name = 'category_list.html'
class CategoryDetailView(DetailView):
model = Category
template_name = 'category_detail.html'
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetailView, self).get_context_data(
*args, **kwargs)
context['category_cars'] = Car.objects.filter(
category=self.request.name)
return context
urls categories
from django.urls import path
from .views import CategoryList, CategoryDetailView
urlpatterns = [
path('categories/', CategoryList.as_view(), name='categories'),
path('categories/<int:pk>/', CategoryDetailView.as_view(), name='category_detail')
]
so using my above implementation results into an error
any suggestions so as to achieve my desired functionality?
Parameters are transferred through kwargs also your parameter name is pk and not name
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetailView, self).get_context_data(
*args, **kwargs)
context['category_cars'] = Car.objects.filter(
category=context['object']
)
return context
But you actually don't need to do this as Category objects have access to their related Car objects ( car_set):
{% for car in object.car_set.all %}
{{car.make}}
{% endfor %}
I'm developing my personal blog; it has only two categories and I would like to have a specific list of posts for both categories.
For this reason I've expand get_absolute_url as you can see below:
from django.db import models
from django.urls import reverse
CATEGORY_CHOICES = (
('G.I.S.', 'G.I.S.'),
('Sustainable Mobility', 'Sustainable Mobility'),
)
class Blog(models.Model):
"""
Blog's post definition
"""
title = models.CharField(
max_length=70,
unique=True,
)
slug = models.SlugField(
unique=True,
)
contents = models.TextField()
publishing_date = models.DateTimeField()
category = models.CharField(
max_length=50,
choices=CATEGORY_CHOICES,
)
def __str__(self):
return self.title
def get_absolute_url(self):
if Blog.objects.filter(category="G.I.S."):
return reverse("gis_single_post", kwargs={"slug": self.slug})
if Blog.objects.filter(category="Sustainable Mobility"):
return reverse("sumo_single_post", kwargs={"slug": self.slug})
Below you can see views.py; it has different model based on a category:
from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from .models import Blog
class GisSinglePost(DetailView):
model = Blog
queryset = Blog.objects.filter(category="G.I.S.")
context_object_name = 'post'
template_name = "gis_single_post.html"
class GisListPost(ListView):
model = Blog
queryset = Blog.objects.filter(category="G.I.S.")
context_object_name = 'posts'
template_name = "gis_list_post.html"
class SuMoSinglePost(DetailView):
model = Blog
queryset = Blog.objects.filter(category="Sustainable Mobility")
context_object_name = 'post'
template_name = "sumo_single_post.html"
class SuMoListPost(ListView):
model = Blog
queryset = Blog.objects.filter(category="Sustainable Mobility")
context_object_name = 'posts'
template_name = "sumo_list_post.html"
And below there is urls.py with its four path:
from django.urls import include, path
from .views import GisSinglePost, GisListPost, SuMoListPost, SuMoSinglePost
urlpatterns = [
path("gis/", GisListPost.as_view(), name="gis_list_post"),
path("gis/<slug:slug>/", GisSinglePost.as_view(), name="gis_single_post"),
path("sustainable-mobility/", SuMoListPost.as_view(), name="sumo_list_post"),
path("sustainable-mobility/<slug:slug>/", SuMoSinglePost.as_view(), name="sumo_single_post"),
]
When I click on a single post of GIS's category it's shown the relative details without problem. But when I click on a post of the other category it's shown to me this:
Page not found (404) Request Method: GET Request URL:
http://127.0.0.1:8000/gis/erova-mobilita/ Raised by:
blog.views.GisSinglePost
No Articolo found matching the query
You're seeing this error because you have DEBUG = True in your Django
settings file. Change that to False, and Django will display a
standard 404 page.
I've been stuck on this problem for many days. How I can resolve?
You should redefine your get_absolute_url method. Since your Blog instances with category G.I.S exist you are never reaching second if for Blog instances with category Sustainable Mobility.
def get_absolute_url(self):
if self.category == "G.I.S.":
return reverse("gis_single_post", kwargs={"slug": self.slug})
elif self.category == "Sustainable Mobility":
return reverse("sumo_single_post", kwargs={"slug": self.slug})
Try to redefine your get_absolute_url(self) in the next way:
def get_absolute_url(self):
if self.category == "G.I.S.":
return reverse("gis_single_post", kwargs={"slug": self.slug})
if self.category == "Sustainable Mobility":
return reverse("sumo_single_post", kwargs={"slug": self.slug})
I have exhausted all avenues in trying to put together a solution for this, but my current knowledge of Python and Django can only get me so far.
I'm creating a basic ticketing system and CreateView used to work until I created a Profile model and then separated the Ticket model into its own app. There were already a couple of tickets created when I refactored my code which is why I know ListView works, DeleteView works as well as DetailView. CreateView works until I hit the save button.
My views and models are below; I hope someone can please help me sort this out.
Ticket Model
from django.db import models
from django.contrib.auth.models import User
....
from qcapp.models import Profile
class Ticket(models.Model):
# Relations
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="tickets", verbose_name="user")
# Attributes
title = models.CharField(max_length=250, verbose_name="Title", help_text="Enter a Ticket Title")
color = models.CharField(max_length=7,
default="#ffffff",
validators=[RegexValidator("(^#[0-9a-fA-F]{3}$)|(^#[0-9a-fA-F]{6}$)")],
verbose_name="Color",
help_text="Enter the hex color code, like #ccc or #cccccc")
description = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now, verbose_name='Created Date')
created_by = models.ForeignKey(User, related_name='created_by_user')
# Attributes
# Object Manager
objects = managers.ProjectManager()
# Meta and String
class Meta:
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
ordering = ("user", "title")
unique_together = ("user", "title")
def __str__(self):
return "%s - %s" % (self.user, self.title)
def get_absolute_url(self):
return reverse('ticket_detail', args=[str(self.id)])
Ticket View (CreateView Only)
# -*- coding: utf-8 -*-
...
from django.views.generic import CreateView, UpdateView, DeleteView
...
from .models import Ticket
...
class TicketCreate(CreateView):
model = Ticket
template_name = "tickets/ticket_form.html"
fields = ['title', 'description']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(TicketCreate, self).form_valid(form)
...
Profile Model(Imported Into Ticket Model)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from . import managers
class Profile(models.Model):
# Relations
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
# Attributes
interaction = models.PositiveIntegerField(default=0, verbose_name="interaction")
# Attributes
# Object Manager
objects = managers.ProfileManager()
# Custom Properties
#property
def username(self):
return self.user.username
# Methods
# Meta and String
class Meta:
verbose_name = "Profile"
verbose_name_plural = "Profiles"
ordering = ("user",)
def __str__(self):
return self.user.username
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
It looks like you need to add the following to your TicketCreate class in the form_valid function:
form.instance.user = Profile.objects.get(user=self.request.user)
Let me know if that works!
I am new to Django and trying to make a basic website and having a few difficulties getting the relevant record for a page.
Models.py
import datetime
from django.db import models
from django.conf import settings
from ckeditor.fields import RichTextField
from markdown import markdown
class LiveEntryManager(models.Manager):
def get_query_set(self):
return super(LiveEntryManager,self).get_query_set().filter(status=self.model.LIVE_STATUS)
class Page(models.Model):
LIVE_STATUS = 1
HIDDEN_STATUS = 2
STATUS_CHOICES = (
(LIVE_STATUS, 'Live'),
(HIDDEN_STATUS, 'Hidden'),
)
title = models.CharField(max_length=250, help_text='Max 250 characters.')
slug = models.SlugField(unique=True, help_text='Suggested automatically generated from the title. Must be unique')
description = RichTextField()
description_html = models.TextField(editable=False, blank=True)
status = models.IntegerField(choices=STATUS_CHOICES, default=LIVE_STATUS,
help_text="Only pages with live status will be publicly displayed")
def save(self, force_insert=False, force_update=False):
self.description_html = markdown(self.description)
super(Page, self).save(force_insert, force_update)
def get_record(self):
return self.objects.get()
#Managers
live = LiveEntryManager()
objects = models.Manager()
class Meta:
ordering = ['title']
verbose_name_plural = "Pages"
def __unicode__(self):
return self.title
def get_absolute_url(self):
return "/%s/" % self.slug
class Image(models.Model):
page = models.ForeignKey(Page)
name = models.CharField(max_length=250)
image = models.ImageField(upload_to='gallery')
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
And Views.py
from django.shortcuts import get_object_or_404, render_to_response
from django.views.generic.list_detail import object_list
from mainsite.models import Page, Image
def home(request):
return render_to_response('templates/home.html')
def page(request, slug):
one_page = get_object_or_404(Page, slug=slug)
return render_to_response('templates/page/page.html',
{ 'object_list': one_page.get_record() })
and Urls.py
urlpatterns = patterns('',
# Examples:
url(r'^$', 'mainsite.views.home', name='home'),
# url(r'^disability/', include('disability.foo.urls')),
url(r'^page/(?P<slug>[-\w]+)/$', 'mainsite.views.page'),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^grappelli/', include('grappelli.urls')),
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
)
What I want to do is to be able to go to say /page/test and get the title, description and image for that object only. I know how to get all objects and display them in a template but cannot figure out how to get a single record and would be grateful of some help.
Thanks
If you would want to query the database for a single Page model you could use
views.py
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from models import Pages
def page(request, slug):
try:
page = Pages.objects.get(slug=slug)
except ObjectDoesNotExist:
return HttpResponse(status=404)
return render(request, 'templates/page/page.html', {'page': page})
Then just use
{{page.title}}
or something like that in your template.
Also, if you want to query and have an iterable list returned intead you coule use
Pages.objects.filter()
instead of
Pages.objects.get()
Where'd you get get_record() from? The return value of get_object_or_404 is a model instance. There's nothing else to "get", just pass the instance to your context. And, don't use object_list as a context name. Not only is this an instance, not a list or queryset, but that name is most often used with pagination, and you'll simply create confusion in your code if you're not actually paginating anything.
return render_to_response('templates/page/page.html', {
'one_page': one_page,
})
Then in your template:
<h1>{{ one_page.title }}</h1>
<img src="{{ one_page.image.url }}" alt="">
<p>{{ one_page.description }}</p>