I'm trying to get a DetailView's model's pk in a variable in the get_context_data but I keep getting the error KeyError at /x/x/ 'pk'.
views.py
class MangaView(DetailView):
model = Manga
template_name = 'mangas/manga.html'
context_object_name = 'manga'
slug_field = 'manga_slug'
slug_url_kwarg = 'manga_slug'
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
manga = get_object_or_404(Manga, id=self.kwargs['pk']) # error line
favorited = False
latered = False
...
return data
urls.py
urlpatterns = [
path('mangas/', MangasHomeView.as_view(), name='mangas-home'),
path('manga/<slug:manga_slug>/', MangaView.as_view(), name='manga'),
...
]
The error you are seeing is caused by trying to access the pk value through self.kwargs, when in fact your view is using a slug field and slug URL parameter.
Try to use self.get_object() as it gives you current instance in DetailView whether it is pk or slug so:
class MangaView(DetailView):
model = Manga
template_name = 'mangas/manga.html'
context_object_name = 'manga'
slug_field = 'manga_slug'
slug_url_kwarg = 'manga_slug'
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
manga = self.get_object()
favorited = False
latered = False
...
return data
Related
How do I override the get_context_data method of my DetailView so that it displays both the ticket details and its comment list? How do I get the comment object from a different app so that I can put it into the view? The end goal is to have both the Ticket Details and have the comment list on the same page. Here's what I have so far
This is my TicketDetailView
class TicketDetailView(DetailView):
model = Ticket
context_object_name = 'comments'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = context['comments'].filter(author=self.request.user)
return context
This is my CommentListView
class CommentListView(ListView):
model = Comment
template_name = 'tickets/ticket_detail.html'
context_object_name = 'comments'
ordering = ['-date_posted']
paginate_by = 5
def get_queryset(self, *args, **kwargs):
ticket = self.kwargs['ticket']
return Comment.objects.filter(ticket=ticket).order_by(self.ordering)
Is there a way to return a dictionary through the get_queryset function of a class based view in Django? I want to pass the array tickets and the string email to my template, but I am only able to pass tickets right now.
Content of views.py:
class UserTicketListView(ListView):
model = Ticket
template_name = 'ticket_system/user_tickets.html'
context_object_name = 'tickets'
ordering = ['-date_posted']
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
email = User.objects.get(username=user).email
return Ticket.objects.filter(author=user).order_by('-date_posted')
class UserTicketListView(ListView):
model = Ticket
template_name = 'ticket_system/user_tickets.html'
context_object_name = 'tickets'
ordering = ['-date_posted']
paginate_by = 5
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
queryset = self.get_queryset()
user = get_object_or_404(User, username=self.kwargs.get('username'))
email = User.objects.get(username=user).email
queryset = queryset.filter(author=user).order_by('-date_posted')
context['user'] = user
context['email'] = email
return context
If the 'school year' value is changed, 404 does not appear.
I want data to be displayed only when both 'school_year' and 'pk' have the right values in url.
for example
If you have data that (School_Year = 2020, pk = 33)
when you enter url https://190.0.1/190/190/33 and https://190.0.1/190/whatthell/33
Both are the same results.
However, I would like to display the result only when both values are correct.
i really dont know if i explained correctly, thanks.
view.py
class StudentDetail(DetailView,FormView):
model = Student
template_name = 'student/member.html'
context_object_name = 'student'
form_class = AddConsultation
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['pk'] = Student.objects.filter(pk=self.kwargs.get('pk'))
return context
url.py
path('student/<school_year>/<pk>/', views.StudentDetail.as_view(), name='student_detail'),
html link
<a href='{% url 'student_detail' student.school_year student.pk %}'>
models.py
class Student(models.Model):
school_year = models.CharField(
max_length=10,
choices=SCHOOL_YEAR_CHOICES,
default='2021N',
verbose_name='school year'
)
... etc
I would remove get_context_data and override get_object using get_object_or_404:
class StudentDetail(DetailView, FormClass):
model = Student
template_name = 'student/member.html'
context_object_name = 'student'
form_class = AddConsultation
def get_object(self, queryset=None):
return get_object_or_404(Student, pk=self.kwargs['pk'], school_year=self.kwargs['school_year'])
Other solution may be:
class StudentDetail(DetailView, FormClass):
model = Student
template_name = 'student/member.html'
context_object_name = 'student'
form_class = AddConsultation
slug_field = 'school_year'
slug_url_kwarg = 'school_year'
query_pk_and_slug = True
but I find the first one less magic :)
I cannot display the products in the ProductDetailView.
ProductDetailView is returning empty string to 'category-detail'..
In Product Detail View it links to:
http://127.0.0.1:8000/products/products/6/
but returns this Error:
Reverse for 'category_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['products/categories/(?P<pk>\\d+)$']
The Information shows up fine in list view for both category and product.
urls.py
url(r'^categories/(?P<pk>\d+)/$', views.CategoryDetailView.as_view(), name='category_detail'),
models.py
class Category(models.Model):
"""
Model For a product category
"""
c_name = models.CharField(max_length=200, help_text="Enter a Product Category: ")
def __str__(self):
"""
String Representation for the Model object
"""
return self.c_name
def get_absolute_url(self):
"""
Return an absolute URL to access a product instance
"""
return reverse('category_detail', args=[str(self.id)])
views.py
class CategoryDetailView(generic.DetailView):
template_name = 'category_detail.html'
context_object_name = 'category_detail'
paginate_by = 2
model = Category
def get_object(self):
return get_object_or_404(self.model, pk=self.kwargs['pk'])
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetailView, self).get_context_data(*args, **kwargs)
context['products'] = self.get_object().products.all()
return context
class ProductDetailView(generic.DetailView):
model = Product
context_object_name = 'product_detail'
template_name = 'product_detail.html'
paginate_by = 2
def get_object(self):
return get_object_or_404(self.model, pk=self.kwargs['pk'])
def get_context_data(self, *args, **kwargs):
context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
return context
html
<p><strong>Category:</strong> {{ product.category }}</p>
What I am missing?
You need to take out the context names
class CategoryDetailView(generic.DetailView):
...
context_object_name = 'category_detail' #
...
class ProductDetailView(generic.DetailView):
...
context_object_name = 'product_detail.html'
...
These are messing with the linking system.
Another thing.. in the product_detail.html. you need to add the product.pk into the url
update
Delete
This Should work..
Also maybe link back to the product-detail view when you have finished editing the product :)
I think your CategoryDetailView need get_object.
from django.shortcuts import get_object_or_404
...
class CategoryDetailView(generic.DetailView):
template_name = 'category_detail.html'
context_object_name = 'category_detail'
paginate_by = 2
model = Category
def get_object(self):
return get_object_or_404(self.model, pk=self.kwargs['pk'])
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetailView, self).get_context_data(*args, **kwargs)
context['products'] = self.get_object().products.all()
return context
and change the url;
url(r'^categories/(?P<pk>\d+)$', ...
to:
url(r'^categories/(?P<pk>\d+)/$', ...
I have a problem how to pass selected data from SelectDateWidget to view and to url.
Now I have the hardcoded data get_success_url in the digest, after the "submit" on the form.
For the SelectDateWidget help, I want to select the month and year for which I want to show selected events.
Here is my form:
class BookingForm(forms.ModelForm):
date_start = forms.DateField(widget=SelectDateWidget(years=range(1980, 2018)))
class Meta:
model = Booking
fields = ('date_start', )
widgets = {'date_start': SelectDateWidget()}
This is my view, where I have hardcoded value for success url:
class BookingListView(ListView, FormView):
model = models.Booking
form_class = BookingForm
queryset = models.Booking.objects.all() # order_by('-date_start')
paginate_by = 80
template_name = 'events/archive_list.html'
context_object_name = 'object_list'
date_field = 'date_start'
allow_future = True
def get_context_data(self, **kwargs):
context = super(BookingListView, self).get_context_data(**kwargs)
context['mode'] = 'archive'
context['form'] = BookingForm()
return context
def get_success_url(self):
return reverse('archive:archive_month_numeric', kwargs={'year': 2014, 'month': 10})
My url to page where I have events in selected date:
url(r'^/(?P<year>[0-9]{4})/(?P<month>[0-9]+)/$', views.ArticleMonthArchiveView.as_view(month_format='%m'), name="archive_month_numeric"),