Model object has no attribute 'get' - django

using Django 1.11 I'm stuck with uuid referencing in my views.
I read through all similar looking questions here, but they either focus on forms or anything else.
Minimal example
It's an app called MegaTest. It's bound to /testuuid/
I have a working index view that generate links to /testuuid/<uuid>
If I click on a link on my index page, I get:
AttributeError at /testuuid/5a147a14-a9a9-4045-8e79-0ce2e8258a68/
'MegaTest' object has no attribute 'get'
models.py
class MegaTest(models.Model):
uuid = models.UUIDField(db_index=True, default=uuid.uuid4,
editable=False, unique=True)
name = models.CharField(max_length=128, blank=True, null=True)
views.py
class IndexView(generic.ListView):
template_name = 'testuuid/index.html'
context_object_name = 'test_list'
def get_queryset(self):
"""Return the last five published questions."""
return MegaTest.objects.all()
class MegaTestDetailView(generic.DetailView):
model = MegaTest
def get(self, request, uuid):
try:
megatest = MegaTest.objects.get(uuid=uuid)
return megatest
except MegaTest.DoesNotExist:
raise Http404
urls.py
app_name = 'testuuid'
urlpatterns = [
# ex: /polls/
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<uuid>[\w-]+)/$', views.MegaTestDetailView.as_view(), name='detail'),
]
testuuid/index.html
{% if test_list %}
<ul>
{% for test in test_list %}
<li>
{{ test.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No tests available.</p>
{% endif %}
I assume a damn simple mistake, but I really have no clue at this point.
The complete traceback can be found here http://dpaste.com/3JTB5NZ

You should override get_object() method instead of get().
class MegaTestDetailView(generic.DetailView):
model = MegaTest
def get_object(self):
try:
megatest = MegaTest.objects.get(uuid=self.kwargs['uuid'])
return megatest
except MegaTest.DoesNotExist:
raise Http404
You can also work with get_queryset() or even just specify pk field in url and don't write any method in the view class. Django will automatically query on your specified field in pk_url_kwarg

Related

KeyError, Exception Value: 'object'

1
I'm working on Django. I'm getting the error below. I didn't find the solution despite the much increased.Please refer the this link for trace back
Codes in views.py
class UpdateVote(LoginRequiredMixin,UpdateView):
form_class = VoteForm
queryset = Vote.objects.all()
def get_object(self,queryset=None):
vote = super().get_object(queryset)
user = self.request.user
if vote.user != user:
raise PermissionDenied('can not change another user vote')
return vote
def get_success_url(self):
movie_id = self.object.movie.id
return reverse('core:movie_detail', kwargs={'pk':movie_id})
def render_to_response(self, context, **response_kwargs):
movie_id = context['object'].id
movie_detail_url = reverse('core:movie_detail',kwargs={'pk':movie_id})
return redirect(to=movie_detail_url)
class MovieDetail(DetailView):
queryset = Movie.objects.all_with_prefetch_persons()
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
if self.request.user.is_authenticated:
vote = Vote.objects.get_vote_or_unsaved_blank_vote(movie=self.object,user=self.request.user)
if vote.id:
vote_url_form = reverse('core:UpdateVote',kwargs={'movie_id':vote.movie.id,'pk':vote.id})
else:
vote_url_form = (reverse('core:create_vote',kwargs={'movie_id':self.object.id}))
vote_form = VoteForm(instance=vote)
ctx['vote_form'] = vote_form
ctx['vote_url_form'] = vote_url_form
return ctx
Codes in form.py
I have used this form to link with UpdateView
from django import forms
from django.contrib.auth import get_user_model
from .models import Movie,Vote
class VoteForm(forms.ModelForm):
user = forms.ModelChoiceField(widget=forms.HiddenInput,queryset=get_user_model().objects.all(),disabled=True)
movie = forms.ModelChoiceField(widget=forms.HiddenInput,queryset = Movie.objects.all(),disabled=True)
value = forms.ChoiceField(widget=forms.RadioSelect,choices=Vote.VALUE_CHOICE)
class Meta:
model = Vote
fields = ('value','user','movie',)
urls.py
This is the url mapping for the view.
from django.contrib import admin
from django.urls import path
from .views import MovieList,MovieDetail,PersonDetail,CreateVote,UpdateVote
app_name = 'core'
urlpatterns = [
path('movies/', MovieList.as_view(), name='movie_list'),
path('movie/<int:pk>/', MovieDetail.as_view(), name='movie_details'),
path('person/<int:pk>/', PersonDetail.as_view(), name='person_details'),
path('movie/<int:movie_id>/vote/', CreateVote.as_view(), name='create_vote'),
path('movie/<int:movie_id>/vote/<int:pk>', UpdateVote.as_view(), name='UpdateVote'),
]
HTML template
This is the template I used.
{% block sidebar %}
<div>
{% if vote_form %}
<form action="{{vote_form_url}}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ vote_form.as_p }}
<button class="btn btn-primary" type="submit" >Vote</button>
</form>
{% else %}
<p>Login to vote for this movie</p>
{% endif %} </div> {% endblock %}
Your UpdateVote view is using VoteForm and the queryset on that view is from Vote model, so that the object field inside that view is the instance of Vote model, not Movie model.
This code movie_id = context['object'].id also not work because context might not included object of UpdateVote view, that caused the error KeyError, Exception Value: 'object'. You could get movie_id via kwargs field inside UpdateVote view because you've already defined movie_id in the path.
With this:
path('movie/<int:movie_id>/vote/<int:pk>', UpdateVote.as_view(), name='UpdateVote'),
Your view can get the values by using kwargs like so:
class UpdateVote(LoginRequiredMixin,UpdateView):
form_class = VoteForm
queryset = Vote.objects.all()
def get_object(self,queryset=None):
vote = super().get_object(queryset)
user = self.request.user
if vote.user != user:
raise PermissionDenied('can not change another user vote')
return vote
def get_success_url(self):
movie_id = self.kwargs.get('movie_id')
return reverse('core:movie_detail', kwargs={'pk':movie_id})
def render_to_response(self, context, **response_kwargs):
movie_id = self.kwargs.get('movie_id')
movie_detail_url = reverse('core:movie_detail',kwargs={'pk':movie_id})
return redirect(to=movie_detail_url)

Django modelManager - can not see instances/objects in View/listview - no erroer

I am new to django. I am trying to display with a models.Manager only the published=True instances. In the terminal no error comes. What I am doing wrong? I have a feeling it has something to do with my view.
Any help would be highly appreciated.
models.py
from django.db import models
# Create your models here.
class BlogPostManager(models.Manager):
use_for_related_fields = True
def freetosee(self, **kwargs):
return self.filter(published=True, **kwargs)
class Post(models.Model):
NOT_RATED = 0
RATED_G = 1
RATED_PG = 2
RATED_R = 3
RATINGS =(
(NOT_RATED, 'NR-Not Rated'),
(RATED_G, 'G - General Audience'),
(RATED_PG, 'Parental'),
(RATED_R, 'Restriced'),
)
title = models.CharField(max_length=140)
body = models.TextField()
published = models.BooleanField(default=False)
rating = models.IntegerField(
choices=RATINGS,
default=NOT_RATED,
)
objects = BlogPostManager()
def __str__(self):
return self.title
views.py
from django.shortcuts import render
# Create your views here.
from django.views.generic import DetailView, ListView
from .models import Post
class PostListView(ListView):
model = Post
context_object_name = 'posts'
template_name = 'postlist.html'
template
{% extends "base.html" %}
{% block content %}
{% for post in posts.objects.freetosee %}
{{ post.title }} - {{ post.body }}
{% endfor %}
{% endblock %}
urls.py
from django.urls import path, include
from django.views.generic import TemplateView
from .views import PostListView
app_name = 'blog'
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('list/', PostListView.as_view(), name='post-list'),
]
I expect to see all models instances in the ListView with published=True
That's not how it works. posts is a queryset, it doesn't have an objects attribute. You need to call that in the view:
class PostListView(ListView):
queryset = Post.objects.freetosee()
context_object_name = 'posts'
template_name = 'postlist.html'
and then in your template just do {% for post in posts %}
Since you're using 2.1
As per django 2.0 deprecation docs use_for_related_fields = True is removed
You'll have to use base_manager_name in model Meta. like this:
class Post(models.Model):
# your fields here
objects = BlogPostManager()
class Meta:
base_manager_name = 'objects'
As suggested above in comments, when you have context_object_name set you don't have to do posts.objects.freetouse
Change your template to:
{% extends "base.html" %}
{% block content %}
{% for post in posts %}
{{ post.title }} - {{ post.body }}
{% endfor %}
{% endblock %}
from docs: the ListView has a get_queryset() method we can override. Previously, it has just been returning the value of the queryset attribute, but now we can add more logic.
This means you can do
class PostListView(ListView):
queryset = Post.objects.freetosee()
context_object_name = 'posts'
template_name = 'postlist.html'
and you can also do:
class PostListView(ListView):
context_object_name = 'posts'
template_name = 'postlist.html'
def get_queryset(self):
# this method can be used to apply as many filters as you want
# Just a quick example,
# filter_id = self.request.GET.get('filter_by')
# if filter_id:
# return Post.objects.filter(id=filter_id)
return Post.objects.freetosee()
NOTE: Please understand Views are there to handle all data and pass it to templates. You make managers to keep your custom queries methods in one place. So it's one place for one kind of thing also your template should not make any query request unless it's super necessary. templates are just to display. If you want filters in templates use template tags. That will keep your code clean and readable.

Cannot resolve keyword 'name' into field using get_queryset

Sorry is this is basic but I'm new at this
I am attempting to take the captured group from a url in the template, (the primary key of the story model) and then use that to filter the correct posts from the Post datbase, which it has a one(story) to many(Post) relationship with. I based the code of the docs: https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/#dynamic-filtering
But when I run it, I get the error:
FieldError at /story/1/
Cannot resolve keyword 'name' into field. Choices are: body, id, title, work, work_id
My code:
#views
from django.shortcuts import get_object_or_404, render
from django.views.generic import ListView, DetailView
from . models import Post, Story
class StoryListView(ListView):
model = Story
template_name = 'home.html'
class PostListView(ListView):
template_name = 'story_overview.html'
def get_queryset(self):
self.work_id=get_object_or_404(Post, name=self.kwargs['pk'])
return Post.objects.filter(work_id=self.work_id)
#urls
from django.urls import path
from . import views
urlpatterns = [
path('', views.StoryListView.as_view(), name='home'),
path('story/<int:pk>/', views.PostListView.as_view(), name='story_overview'),
]
#templates/home.html
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<h2>{{ post.title }}</h2>
<p>{{ post.description }}</p>
{% endfor %}
{% endblock content %}
#models
from django.db import models
class Story(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=1500, default= "Description")
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=200, default= "Title")
work = models.ForeignKey(Story,on_delete=models.CASCADE,)
body = models.TextField()
def __str__(self):
return self.title
If you filter using work_id then you should use the integer.
def get_queryset(self):
return Post.objects.filter(work_id=self.kwargs['pk'])
If you want to fetch the Story instance then you should call get_object_or_404 with Story, and filter on the pk field instead of name:
def get_queryset(self):
self.work=get_object_or_404(Story, pk=self.kwargs['pk'])
return Post.objects.filter(work=self.work)
Note I've renamed work_id to work because it's a model instance, not an id.
You are trying to get object from Post() model using name field. Is name field present in your Post() model?
Instead of doing this
self.work_id=get_object_or_404(Post, name=self.kwargs['pk'])
Do this
self.work_id=get_object_or_404(Post, id=self.kwargs['pk'])
Hope it helps!

Why is this Django class-based year archive view not working?

I'm trying to subclass the YearArchiveView class-based view to show a list of articles published in a year, but the filtering doesn't work and example.com/2012 shows articles from all years.
Note that I do not want the view code in urls.py. Rather, I want the LogbookYearArchive wrapper to continue living in views.py.
models.py:
class Entry(models.Model):
KIND = (
('L', 'Link'),
('A', 'Article'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(unique_for_date='pub_date')
kind = models.CharField(max_length=1, choices=KIND, default=1,
help_text="Is this a link to other content or an original article?")
url = models.URLField(blank=True, help_text="The link URL")
body = models.TextField(blank=True)
body_html = models.TextField()
content_format = models.CharField(choices=CONTENT_FORMAT_CHOICES,
max_length=50, default=1)
is_active = models.BooleanField(help_text=_("Tick to make this entry\
live (see also the publication date). Note that administrators\
(like yourself) are allowed to preview inactive entries whereas\
the general public aren't."), default=True)
pub_date = models.DateTimeField(verbose_name=_("Publication date"),
help_text=_("For an entry to be published, it must be active and its\
publication date must be in the past."))
mod_date = models.DateTimeField(auto_now_add=True, editable=False)
class Meta:
db_table = 'blog_entries'
verbose_name_plural = 'entries'
ordering = ('-mod_date',)
get_latest_by = 'pub_date'
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
"""Construct the absolute URL for an Entry of kind == Article."""
return ('logbook-entry-detail', (), {
'year': self.pub_date.strftime("%Y"),
'month': self.pub_date.strftime("%m"),
'slug': self.slug})
urls.py:
from __future__ import absolute_import
from django.conf.urls import patterns, include, url
from .models import Entry
from .views import LogbookYearArchive
urlpatterns = patterns('',
url(r'^(?P<year>\d+)/$',
view=LogbookYearArchive.as_view(),
name='archive-year'),
)
views.py:
from django.views.generic.list import MultipleObjectMixin
from django.views.generic import ArchiveIndexView, MonthArchiveView, YearArchiveView, DetailView
from django.core.urlresolvers import reverse
from .models import Entry
class LogbookYearArchive(YearArchiveView):
"""Yearly archives of articles"""
model = Entry
date_field = 'pub_date'
year_format='%Y'
make_object_list=True,
template_name = 'hth/archive_year.html'
allow_future = False
def get_context_data(self, **kwargs):
context = super(LogbookYearArchive, self).get_context_data(**kwargs)
# =todo: fix filtering by date which is not working
context['object_list'] = Entry.objects.filter(
is_active=True, kind='A').order_by('-pub_date', 'title')[:9999]
return context
archive_year.html:
{% block content %}
<h1 style="margin-bottom:1em;">Articles Published in {{ year|date:"Y" }}</h1>
{% for object in object_list %}
{% ifchanged %}
<h2 class="dateline datelinearchive">{{ object.pub_date|date:"F Y" }}</h2>
{% endifchanged %}
<p>
{{ object.title }}
</p>
{% endfor %}
{% endblock %}
Can you try this:
class LogbookYearArchive(YearArchiveView):
"""Yearly archives of articles"""
model = Entry
date_field = 'pub_date'
year_format='%Y'
make_object_list=True,
template_name = 'hth/archive_year.html'
allow_future = False
queryset = Entry.objects.filter(
is_active=True, kind='A').order_by('-pub_date', 'title')
I added a queryset attribute and removed get_context_data()
I had the same problem. All ArchiveViews were working except YearArchiveView. Solution was found in make_object_list property. It should be True
That's a cut from django code
if not self.get_make_object_list():
# We need this to be a queryset since parent classes introspect it
# to find information about the model.
qs = qs.none()

Creating Tag Index Django

Im using django-taggit to create a tagging system for a blog. How do you separate and filter objects so that only ones with selected tags are shown? Kind of like how on StackOverflow if you click on django
it will give you all the questions tagged django. I have tried the method described on this blog post, but I get an IndexError: tuple index out of range. This is the code I am using:
url(r'^tagged/(?P<tag>[\w-]+)/$', TagView.as_view(), name='tag_url'),
class TagView(ListView):
context_object_name = 'blog'
template_name = 'links/index.html'
def get_queryset(self):
return Blog.objects.filter(tags__name__in=[self.args[0]])
def get_context_data(self, **kwargs):
context = super(TagView, self).get_context_data(**kwargs)
context['requested_tag'] = self.args[0]
return context
<a href='{% url tag_url tag=tag %}'>{{ tag.name }}</a>
Am I missing something to get this method to work?
It seems like this is a pretty common programming necessity. Maybe you know a better method... Thanks for your ideas!
EDIT: TagView based on #catherine's suggestions:
class TagView(ListView):
model = Blog
context_object_name = 'blog_list'
template_name = 'tag-list.html'
def get_queryset(self):
queryset = super(TagView, self).get_queryset()
return queryset.filter(tags__name__in=self.kwargs['tags'])
class Blog(models.Model):
name = models.CharField(max_length=50)
date = models.DateTimeField()
slug = models.SlugField()
article = models.TextField()
tags = TaggableManager()
def __unicode__(self):
return self.name
tag-list.html:
{% block content %}
stuff
{% for blog in blog_list %}
{{ blog.article }}
{{ blog.name }}
{% endfor %}
{% endblock %}
The blog_list does not exist in the template, and no blog objects are available. Rather, only 'stuff' is rendered to the template. Any ideas are appreciated! Thanks!
class TagView(ListView):
model = Blog
......
def get_queryset(self):
# Fetch the queryset from the parent get_queryset
queryset = super(TagView, self).get_queryset()
return queryset.filter(tags__name__in=self.kwargs['tag'])
This answer is based on "EDIT: TagView based on #catherine's suggestions:".
You have a typo, in get_queryset method:
return queryset.filter(tags__name__in=self.kwargs['tags'])
you use tag and not tags thus it should be:
return queryset.filter(tags__name__in=[self.kwargs['tag']])