我的网站允许用户发布他们的想法和其他用户对想法的评论并将想法从 1 到 10 进行评分。想法页面加载了用户的想法以及评级表和评论表,但是当登录用户尝试提交时他们遇到 AttributeError 的评论表单或评级表单。因为页面加载我相信 get() 方法正在工作,但我不相信 post() 方法正在工作。如何在我的视图中访问用户属性?
这是我处理想法页面的基于类的视图:
class IdeaView(TemplateView):
template_name = 'idea.html'
def get_average_rating(self, idea):
"""get average rating for an idea"""
ratings = Rating.objects.filter(idea=idea)
# aggregate function used to perform calcs on database records. Takes one or more arguments.
# returns dictionary containing results of calcs.
# rating__sum is the key used to access the sum of the 'rating' values from the dictionary.
total_ratings = ratings.aggregate(Sum('rating'))['rating__sum'] or 0
number_of_ratings = ratings.count() or 0
return total_ratings / number_of_ratings
def get_context_data(self, **kwargs):
# call corresponding method of parent class and updating context dict. with data defined in get_context_data() method
context = super().get_context_data(**kwargs)
# add additional data to context dictionary that is available to all when accessing this method
context['user'] = self.request.user
context['rating_form'] = RatingForm()
context['comment_form'] = CommentForm()
return context
def get(self, request, slug):
""" get idea, user comments and forms for displaying to user"""
idea = Idea.objects.get(slug=slug)
rating = self.get_average_rating(idea)
# double underscore __ is used to perform lookups that span relationships
# idea__slug means that we are transversing the 'idea' relationship and filtering the slug field of the 'Idea' model
comments = Comment.objects.filter(idea__slug=slug).order_by('date_commented')
context = {'idea': idea, 'rating': rating, 'comments': comments}
context.update(self.get_context_data(**context))
return render(request, self.template_name, context)
@login_required
def post(self, request, slug):
"""handle Post request for user comment or rating of idea.
Redirect to login screen if not logged in."""
comment_form = CommentForm(request.POST)
rating_form = RatingForm(request.POST)
# allow for updating user rating if they've already rated. if rating exits then update.
# I've added __init__ function in RatingForm.
# I used filter() because it returns an empty query_set whereas get() raises
# a DoesNotExist exception that needs to be handled.
idea = Idea.objects.get(slug=slug)
rating_exists = Rating.objects.filter(idea=idea, author=self.request.user).first()
if rating_exists and rating_form.is_valid():
# update existing rating
rating_exists.rating = rating_form.cleaned_data['rating']
rating_exists.idea = idea
rating_exists.author = self.request.user
rating_exists.save()
elif comment_form.is_valid() and not rating_form.is_valid():
# only save comment form
comment = comment_form.save(commit=False)
comment.idea = idea
comment.author = self.request.user
comment.save()
elif rating_form.is_valid() and not comment_form.is_valid():
# only save users rating form
rating = rating_form.save(commit=False)
rating.idea = idea
rating.author = self.request.user
rating.save()
rating = self.get_average_rating(idea)
comments = Comment.objects.filter(idea__slug=slug).order_by('date_commented')
context = {'idea': idea, 'rating': rating, 'comments': comments}
context.update(self.get_context_data(**context))
return render(request, self.template_name, context)
这是我的模型:
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
class Idea(models.Model):
title = models.CharField(max_length=255, unique=True)
idea = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='idea_authored')
date_posted = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
slug = models.SlugField(unique=True, blank=True, null=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title + ' ' + self.author.username)
super().save(*args, **kwargs)
def __str__(self):
return f'Idea: {self.title} by {self.author.username}'
class Rating(models.Model):
idea = models.ForeignKey(Idea, on_delete=models.CASCADE, related_name='idea_rating')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='authors_rating')
rating = models.DecimalField(max_digits=3, decimal_places=1)
class Comment(models.Model):
idea = models.ForeignKey(Idea, on_delete=models.CASCADE, related_name='idea_comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='authors_comment')
comment = models.TextField()
date_commented = models.DateTimeField(auto_now_add=True)
这是我的 html 模板:
{% block content %}
<div class="container">
<div class="row d-flex justify-content-between">
<div>
<h1>{{ idea.author.username }}</h1>
<h5 style="text-indent: 25px;">Date: {{ idea.date_posted }}</h5>
</div>
<div class="border border-dark rounded">
<h5>{{ rating }}/10</h5>
<form method="post">
{% csrf_token %}
{{ rating_form.as_p }}
{% if user.is_authenticated %}
<button type="submit" class="btn btn-primary">Submit</button>
{% else %}
<a href="{% url 'users:login' %}?next={{ request.path }}" class="btn btn-primary">Login</a>
{% endif %}
</form>
</div>
</div>
</div>
<h5>{{ idea.title }}</h5>
<p class="border border-dark rounded">{{ idea.idea }}</p>
<h4>Comments:</h4>
{% if comments %}
{% for comment in comments %}
<h5 style="text-indent: 25px;">{{ comment.author.username }} ({{ comment.date_commented }})</h5>
<p class="border border-dark">{{ comment.comment }}</p>
{% endfor %}
{% else %}
<h4>Be the first to comment.</h4>
{% endif %}
<form method="post">
{% csrf_token %}
{{ comment_form.as_p }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock %}
我试过将 request.user 更改为 self.request.user,我试过将 self.request.user 放在 get_context_data() 方法中,但没有成功。
这样试过吗?
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
@method_decorator(login_required, name="post")
class IdeaView(TemplateView):
...
在这里了解更多:ref
希望这有帮助!
我不确切知道你的项目和当前 Exception 跟踪。但在这种情况下你可以轻松做到:
class IdeaView(TemplateView):
...
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.user = request.user
...
这是向您的视图添加一些属性的最佳和正确方法。