Hello I'm getting KeyError at object_post for some reason.
I believe keyError means it's not importing data correctly, but I have no idea what's wrong with the code. If anyone has an idea I would appreciated it. My guess is my python code is wrong, but I googled around and some one says it's JSON problem. I'm not an expert in JSON(so it will be bigger prob if it's the case)...I'll post my code assuming there's something wrong with my code.
Error MEssage: KeyError at /'object_list'
Code:
views.py
for front page
class IndexView(TemplateView):
template_name = 'main/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated():
voted = Vote.objects.filter(voter=self.request.user)
posts_in_page = [post.id for post in context["object_list"]]
voted = voted.filter(post_id__in=posts_in_page)
voted = voted.values_list('post_id', flat=True)
context.update({
'voted' : voted,
'latest_posts': Post.objects.all().order_by('-created_at'),
'popular_posts': Post.objects.all().order_by('-views'),
'hot_posts': Post.objects.all().order_by('-score')[:25],
'categories': Category.objects.all(),
})
return context
Models.py
class Post(models.Model):
category = models.ForeignKey(Category)
created_at = models.DateTimeField(auto_now_add = True)
title = models.CharField(max_length = 100)
content = FroalaField()
url = models.URLField(max_length=250, blank=True)
moderator = models.ForeignKey(User, default="")
rank_score = models.FloatField(default=0.0)
with_votes = PostVoteCountManager()
views = models.IntegerField(default=0)
image = models.ImageField(upload_to="images",blank=True, null=True)
slug = models.CharField(max_length=100, unique=True)
objects = models.Manager() # default manager
def save(self, *args, **kwargs):
self.slug = uuslug(self.title, instance=self, max_length=100)
super(Post, self).save(*args, **kwargs)
def __unicode__(self):
return self.title
# for redirecting URL so slug is always shown
def get_absolute_url(self):
return '/%s/%s' % (self.id, self.slug)
def set_rank(self):
# Based on HN ranking algo at http://amix.dk/blog/post/19574
SECS_IN_HOUR = float(60*60)
GRAVITY = 1.2
delta = now() - self.submitted_on
item_hour_age = delta.total_seconds() // SECS_IN_HOUR
votes = self.votes - 1
self.rank_score = votes / pow((item_hour_age+2), GRAVITY)
self.save()
class Vote(models.Model):
voter = models.ForeignKey(User)
post = models.ForeignKey(Post)
def __unicode__(self):
return "%s voted %s" % (self.voter.username, self.post.title)
Complete Error:
KeyError at /
'object_list'
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 1.8.4
Exception Type: KeyError
Exception Value:
'object_list'
Exception Location: /home/younggue/Desktop/ebagu0.2/rclone/main/views.py in get_context_data, line 25
Python Executable: /home/younggue/Desktop/ebagu0.2/env/bin/python
Edit3:
my modified view
class IndexListView(ListView):
model = Post
queryset = Post.with_votes.all()
template_name = 'main/index.html'
def get_context_data(self, **kwargs):
context = super(IndexListView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated():
voted = Vote.objects.filter(voter=self.request.user)
posts_in_page = [post.id for post in context["object_list"]]
voted = voted.filter(post_id__in=posts_in_page)
voted = voted.values_list('post_id', flat=True)
context.update({
'voted' : voted,
'latest_posts': Post.objects.all().order_by('-created_at'),
'popular_posts': Post.objects.all().order_by('-views'),
'hot_posts': Post.objects.all().order_by('-score')[:25],
'categories': Category.objects.all(),
})
errors occur from here
#login_required
def add_category(request):
if request.method == 'POST':
form = CategoryForm(request.POST)
if form.is_valid():
form.save(commit=True)
return IndexListView(request)
else:
print form.errors
else:
form = CategoryForm()
return render(request, 'main/add_category.html', {'form':form})
I provided one argument request and the error says I provided two: TypeError at /add_category/
""__init__() takes exactly 1 argument (2 given).
So I googled it and people say it's from urls.py
urls.py """
urlpatterns = [
url(r'^$', IndexListView.as_view(), name='index'),
#url(r'^add_post/', views.add_post, name='add_post'),
url(r'^add_post/$', PostCreateView.as_view(), name='post-add'),
url(r'^(?P<slug>[\w|\-]+)/edit/$', PostUpdateView.as_view(), name='post-edit'),
url(r'^(?P<slug>[\w|\-]+)/delete/$', PostDeleteView.as_view(), name='post-delete'),
url(r'^add_category/', views.add_category, name='add_category'),
url(r'^(?P<slug>[\w|\-]+)/$', views.post, name='post'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$', CategoryDetailView.as_view(), name='category'),
]
I have IndexListView.as_view().
why is this error happening?
Your view inherits from TemplateView so nobody fills up the object_list entry in the context.
Instead, you might want to inherit from ListView or other generic CBVs which populate such context key
As described there:
This template will be rendered against a context containing a variable
called object_list that contains all the publisher objects.
you can see it in the code for ListView
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
...
def get_context_data(self, **kwargs):
"""
Get the context for this view.
"""
queryset = kwargs.pop('object_list', self.object_list)
page_size = self.get_paginate_by(queryset)
context_object_name = self.get_context_object_name(queryset)
if page_size:
paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
context = {
'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset
}
else:
context = {
'paginator': None,
'page_obj': None,
'is_paginated': False,
'object_list': queryset
}
if context_object_name is not None:
context[context_object_name] = queryset
context.update(kwargs)
return super(MultipleObjectMixin, self).get_context_data(**context)
As you can see, the get method sets self.object_list to the queryset retrieved and then the get_context_data method uses it to update the context for the template.
On the contrary, TemplateView does not perform such steps:
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
def get_context_data(self, **kwargs):
if 'view' not in kwargs:
kwargs['view'] = self
return kwargs
so the object_list key does not exist in the context dicitonary.
Of course, in case for some reason you prefer not to use Listview you can still perform such steps in your code, overriding the get and get_context_data methods or inheriting from the proper mixins, e.g.
class IndexView(TemplateResponseMixin, MultipleObjectMixin , View):
Given your latest edit:
in add_category you do
return IndexListView(request)
which makes little sense (i.e. returning an instance of a view).
I presume you are trying to redirect to the index page, so that can be achieved with
return redirect(reverse_lazy('index'))
Related
I have this class that changes user password:
class PasswordsChangeView(PasswordChangeView):
from_class = PasswordChangingForm
success_url = reverse_lazy(
"base:password/passwordsuccess",
)
And I would like to insert User Avatar Img Path in context.
This Img is inside a UserComplement model.
When I create function views, it works doing:
#login_required
def password_success(request):
try:
obg = UserComplement.objects.get(pk=request.user.id)
context = {
"img_avatar": obg.avatar_image,
}
return render(request, "registration/passwordsuccess.html", context)
except UserComplement.DoesNotExist:
return render(request, "registration/passwordsuccess.html")
The problem is that I cannot get the userID in classviews to pass it through the context on success_url.
It was a lack of knowledge on how class based views work. The function get_context_data did the job well, returning the context.
class PasswordsChangeView(PasswordChangeView):
from_class = PasswordChangingForm
success_url = reverse_lazy(
"base:password/passwordsuccess",
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = UserComplement.objects.get(pk=self.request.user.id)
context["img_avatar"] = obj.avatar_image
return context
I have two models, Question and Solution. One question can have many solutions but a solution can only have one question.
Here they are:
models.py
class Question(models.Model):
question_title = models.CharField(max_length = 100)
question_description = models.TextField()
question_tags = models.TextField()
def __str__(self):
return self.question_title
class Solution(models.Model):
user_profile = models.ForeignKey(UserProfile, on_delete = models.SET_NULL)
question_id = models.ForeignKey(Question, on_delete = models.CASCADE, blank = False, null = True)
solution = models.TextField()
date_modified = models.DateTimeField(auto_now_add = True)
def __str__(self):
return "[SOL] " + self.question_id + "/" + self.user_profile
Here's my views.py:
class QuestionList(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
# Used to access all questions and adding one
queryset = Question.objects.all()
serializer_class = QuestionSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class QuestionDetails(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
mixins.DestroyModelMixin):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
lookup_field = 'id'
def get_question(self, id):
try:
return Question.objects.get(id = id)
except Question.DoesNotExist:
raise Http404
def get(self, request, id):
question = self.get_question(id)
serializer = QuestionSerializer(question)
return Response(serializer.data, status.HTTP_200_OK)
def put(self, request, id):
question = self.get_question(id)
serializer = QuestionSerializer(question, data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
def delete(self, request, id):
question = self.get_object(id)
question.delete()
return Response(status = status.HTTP_204_NO_CONTENT)
class SolutionList(generics.GenericAPIView, mixins.ListModelMixin,mixins.CreateModelMixin):
# Empty because I'm still incredibly confused
This is my urlpatterns :
urlpatterns = [
path("questions/", QuestionList.as_view()),
path("questions/<int:id>/", QuestionDetails.as_view()),
]
The first is to access the list of questions and the second is to access a particular question. I want the URL to access the solution list of a particular question to look like this:
questions/question_id/solutions/
where question_id is the ID of the particular question. I also want the URL to access a particular solution of a particular question to look like this:
questions/question_id/solutions/solution_id/
where solution_id is the ID of the particular solution.
How would I do this?
Help is appreciated.
I don't work with mixins but here's the function for you..
def show_solution(request, q_id, s_id):
context = {
'q' : Question.objects.get(pk=q_id),
's' : Solution.objects.filter(question_id=question),
}
return render (request, 'template.html', context)
I have a comment section in django blog and there are two forms one is for comment another is for reply to the comment but the comment form is working fine and reply form doesn't work! i was trying to do but getting error... IntegrityError at /page/9/
FOREIGN KEY constraint failed...
appreciate to your help :)
Thank you.
views.py
class PostDetailView(DetailView):
model = Post
template_name = "post_detail.html"
context_object_name = 'post'
form = CommentForm()
def get_object(self):
obj = super().get_object()
if self.request.user.is_authenticated:
PostView.objects.get_or_create(
user=self.request.user,
post=obj
)
return obj
def get_context_data(self, **kwargs):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
context = super().get_context_data(**kwargs)
context['most_recent'] = most_recent
context['page_request_var'] = "page"
context['category_count'] = category_count
context['form'] = self.form
return context
def post(self, request, *args, **kwargs):
form = CommentForm(request.POST)
form = ReplyForm(request.POST)# how to work with this form like above from
if form.is_valid():
post = self.get_object()
form.instance.user = request.user
form.instance.post = post
form.save()
return redirect(reverse("post-detail", kwargs={
'pk': post.pk
}))
models.py
class Reply(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
content = models.TextField()
comment = models.ForeignKey('Comment', related_name='replies',default=False, null=True,
on_delete=models.CASCADE)
def __str__(self):
return self.content
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
content = models.TextField()
post = models.ForeignKey('Post', related_name='comments', default=False,
on_delete=models.CASCADE)
def __str__(self):
return self.content
You might find it easier if you did not struggle with trying to persuade a Class-based view to do what it was not intended to do, and instead used a plain old Function-based view.
Here is a two-form view. The code has been refactored into what I regard as a better pattern, to validate both forms and redisplay if anything is wrong at the top, and then you just do the actual work to create and save the objects at the bottom.
def receive_uncoated( request): #Function based view
# let's put form instantiation in one place not two, and reverse the usual test. This
# makes for a much nicer layout with actions not sandwiched by "boilerplate"
# note any([ ]) forces invocation of both .is_valid() methods
# so errors in second form get shown even in presence of errors in first
args = [request.POST, ] if request.method == "POST" else []
batchform = CreateUncWaferBatchForm( *args )
po_form = CreateUncWaferPOForm( *args, prefix='po')
if request.method != "POST" or any(
[ not batchform.is_valid(), not po_form.is_valid() ]):
return render(request, 'wafers/receive_uncoated.html', # can get this out of the way at the top
{'batchform': batchform,
'po_form': po_form,
})
#POST, everything is valid, do the work
# create and save some objects based on the validated forms ...
return redirect( 'wafers:ok' )
I want to get the id or pk of a ForeignKey relationship post_comment but I've tried many different ways to catch it and i do not have any good result, please guys give me a hand in this situation
In views.py
class createComment(View):
form_class = CommentForm
template_name = "createComment.html"
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self, request):
obj = self.form_class(None)
obj.title_comment = self.request.POST['title_comment']
obj.body_comment = self.request.POST['body_comment']
obj.post_comment = self.pk
obj.save()
In models.py
class Comment(models.Model):
user_comment = models.ForeignKey("auth.User")
title_comment = models.CharField(max_length=50)
body_comment = models.TextField()
timestamp_comment = models.DateTimeField(auto_now=True)
post_comment = models.ForeignKey("Post", null=True)
status_comment = models.BooleanField(default=True)
def __unicode__(self):
return unicode(self.title_comment)
def __str__(self):
return self.title_comment
You can pass a primary key in the url, and then use it in your class as one way.
kwargs.get(pk name)
You could change post to:
def post(self, request, *args, **kwargs)
You then can't just assign obj.post_comment = kwargs.get(pk) you have to actually get the object.
Post.objects.get(pk = pk)
You might want to also consider renaming fieldname_comment to just fieldname for your models fields. Seems a bit redundant to have _comment on every single field in the Comment model.
I don't know how works class based views but I can tell you that self.pk does not exist in class based view, you would try get form instance and get the I'd field from this instance...
I have a DetailView which displays a Post. I now want to add the ability to create a Comment for a Post. For that I need a CommentForm, within the DetailView, so that I can create comments while being on the same page with a Post.
Is this possible, or should I be looking for another approach, like doing the form handling 'manually'?
class Comment(models.Model):
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
author_name = models.CharField(max_length=255)
parent_post = models.ForeignKey('Post',related_name='comments')
class PostDetailView(BlogMixin,DetailView):
""" A view for displaying a single post """
template_name = 'post.html'
model = Post
#Add some code for the CommentForm here?
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
exclude = ("parent_post","created_at")
def create_view(request, **kwargs):
if request.method == "POST":
parent_fk = request.args['parent_fk'] #Im hoping to find how this will work soon
form = CommentForm(request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.parent_post = parent_fk
new_comment.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
** Alternative **
I have been trying to apply the solution - A better alternative - but I get
Exception Value: __init__() takes exactly 1 argument (3 given)
Exception Location: .../sitepackages/django/core/handlers/base.py in get_response, line 112
and have not been able to trace it yet.
class PostView(BlogMixin,DetailView):
""" A view for displaying a single post """
template_name = 'post.html'
model = Post
def get_context_data(self, **kwargs):
context = super(PostView, self).get_context_data(**kwargs)
context['form'] = CommentForm()
return context
class PostDetailView(View):
def get(self, request, *args, **kwargs):
view = PostView.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = PostComment.as_view()
return view(request, *args, **kwargs)
class PostComment( SingleObjectMixin , FormView):
template_name = 'post.html'
form_class = CommentForm
model = Post
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super(PostComment, self).post(request, *args, **kwargs)
def get_success_url(self):
return reverse('post-detail', kwargs={'pk': self.object.pk})
class BlogMixin(object):
"""
Basic mixin for all the views. Update the context with additional
information that is required across the whole site, typically
to render base.html properly
"""
def get_context_data(self, *args, **kwargs):
context = super(BlogMixin, self).get_context_data(*args, **kwargs)
blog = Blog.get_unique()
context.update({
'blog': blog,
'active_user': users.get_current_user(),
'is_admin': users.is_current_user_admin()
})
return context
urls.py:
url(r'^post/(?P[\d]+)/$', views.PostDetailView., name="post-detail"),
If you want to use your first method, you can make the FK a hidden field. In your view, you can save the FK before committing the comment to the database. Like this:
if form.is_valid():
comment = form.save(commit=False)
comment.parent_post = parent_post
comment.save()
Edit: If you want to fetch the comments, then you can use filter by post to get a QuerySet of the comments.
Why dont you send your form in the context in detail view:
class YourDetailView(DetailView):
#Your stuff here
def get_context_date(self, **kwargs):
context = super(YOurDetailView, self).get_context_data(**kwargs)
context['form'] = YourForm
return context
PS. Look for the parameters in get_context_date..
In the end I could not make it work with the redirect, but the following is working:
class PostDetailView(BlogMixin,CreateView):
""" A view for displaying a single post """
template_name = 'post.html'
model = Comment
fields = ['body','author_name']
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['post'] = Post.objects.get(pk=self.kwargs['pk'])
return context
def form_valid(self, form):
# self.object = form.save()
obj = form.save(commit=False)
obj.parent_post = Post.objects.get(pk=self.kwargs['pk'])
obj.save()
return redirect('post-detail', self.kwargs['pk'])