Я разбираюсь в этом по частям. Я хочу, чтобы пользователи могли оценивать сообщения в блоге на основе 4 критериев (сложность-рейтинг, рабочая нагрузка-рейтинг, книга-рейтинг, посещаемость-рейтинг). Я использовал выбор в файле models.py, чтобы предоставить пользователям выбор.
После этого, благодаря пользователю из StackOverflow, я смог рассчитать среднее значение для каждого из этих значений и отобразить их в верхней части каждого поста.
Проблема в том, что они отображаются как числа с длинными десятичными числами. Есть ли способ показать человека читаемым вместо этого? Что происходит от моей модели кортежей?
Я сделал оператор {% if%} внутри всего шаблона, жестко запрограммировав его, но я почти уверен, что должен быть лучший способ.
Models.py
class Post(models.Model):
STATUS_CHOISES = (
('draft', 'Draft'),
('published', 'Published'),
)
category = models.ForeignKey(Category)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique=True)
content = models.TextField()
seo_title = models.CharField(max_length=250)
seo_description = models.CharField(max_length=160)
author = models.ForeignKey(User, related_name='blog_posts', default=settings.AUTH_USER_MODEL)
published = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=9, choices=STATUS_CHOISES, default='draft')
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.slug])
def avg_ratings(self):
return self.comments.aggregate(
Avg('difficulty_rating', output_field=FloatField()),
Avg('workload_rating', output_field=FloatField()),
Avg('book_rating', output_field=FloatField()),
Avg('attendance_rating', output_field=FloatField()),
)
def __str__(self):
return self.title
class Comment(models.Model):
difficulty_rating_choices = (
(1, 'Very Easy'),
(2, 'Easy'),
(3, 'Moderate'),
(4, 'Hard'),
(5, 'Very Hard'),
)
workload_rating_choices = (
(1, 'Very Light'),
(2, 'Light'),
(3, 'Moderate'),
(4, 'Heavy'),
(5, 'Very Heavy'),
)
book_rating_choices = (
(1, '$'),
(2, '$$'),
(3, '$$$'),
(4, '$$$$'),
(5, '$$$$$'),
)
attendance_rating_choices = (
(1, 'Not Required'),
(2, 'Required'),
)
post = models.ForeignKey(Post, related_name="comments")
user = models.CharField(max_length=250)
email = models.EmailField()
title = models.CharField(max_length=250)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
difficulty_rating = models.IntegerField(choices=difficulty_rating_choices)
workload_rating = models.IntegerField(choices=workload_rating_choices)
book_rating = models.IntegerField(choices=book_rating_choices)
attendance_rating = models.IntegerField(choices=attendance_rating_choices)
def approved(self):
self.approved = True
self.save()
def __str__(self):
return self.title
Views.py
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
template = 'blog/post/post_detail.html'
context = {
'post': post,
}
return render(request, template, context)
Шаблон
{% with avg_ratings=post.avg_ratings %}
<h1>Difficulty: {{ avg_ratings.difficulty_rating__avg }}</h1>
<h1>Workload: {{ avg_ratings.workload_rating__avg }}<h1>
<h1>Book Cost: {{ avg_ratings.book_rating__avg }}<h1>
<h1>Attendance: {{ avg_ratings.attendance_rating__avg }}<h1>
{% endwith %}
3 ответа
Используйте фильтр шаблонов django https://docs.djangoproject.com/ ан / 1,10 / исх / шаблоны / встроенные функции / # floatformat
Например:
{{ avg_ratings.difficulty_rating__avg|floatformat:"-3" }}
Если под «удобочитаемым человеком» вы хотите заменить слова диапазонами значений, создайте свой собственный шаблонный фильтр для этого.
Вы можете сделать что-то вроде (добавить диапазоны для ваших уровней):
from django import template
register = template.Library()
@register.filter
def rating_humanize(value): # Only one argument.
if value < 1.0:
return 'Very Easy'
elif value < 2.0:
return 'Easy'
else:
return 'Hard'
Лучшая реализация - составить список отображений диапазона в строку, а затем найти соответствующий диапазон и вернуть для него строку.
Возможно, использование DecimalField(decimal_places=2)
вместо FloatField
поможет.
Не уверен, что это лучшее решение, но это то, что я придумал, вам нужно обновить метод avg_ratings
в вашей модели Post
:
import math
class Post(models.Model):
# ...
def avg_ratings(self):
ratings = {}
data = self.comments.aggregate(
Avg('difficulty_rating', output_field=FloatField()),
Avg('workload_rating', output_field=FloatField()),
Avg('book_rating', output_field=FloatField()),
Avg('attendance_rating', output_field=FloatField()),
)
for key, val in data.items():
key = key.replace('__avg', '')
scaled_val = int(math.ceil(val))
display = ''
choices = getattr(CommentTest, '{}_choices'.format(key))
for choice_display, choice_val in choices:
if scaled_val == choice_val:
display = choice_display
break
if not display:
raise Exception('Display for "{}" avg with value "{}" not found.'.format(key, scaled_val))
ratings[key] = (scaled_val, display, val)
return ratings
Затем в шаблоне:
{% with avg_ratings=post.avg_ratings %}
<h1>Difficulty: {{ avg_ratings.difficulty_rating.0 }} - {{ avg_ratings.difficulty_rating.1 }}</h1>
<h1>Workload: {{ avg_ratings.workload_rating.0 }} - {{ avg_ratings.workload_rating.1 }}<h1>
<h1>Book Cost: {{ avg_ratings.book_rating.0 }} - {{ avg_ratings.book_rating.1 }}<h1>
<h1>Attendance: {{ avg_ratings.attendance_rating.0 }} - {{ avg_ratings.attendance_rating.1 }}<h1>
{% endwith %}
Метод avg_ratings
делает то, что он подготавливает словарь рейтингов в следующем формате:
{'difficulty_rating': (2, 'Easy', 1.9), ..}
Значением для каждого ключа будет кортеж, содержащий три значения:
- Первым значением будет масштабированное значение среднего, например, т.е. если в среднем было 1,7, оно будет считаться 2.
- Второе значение - это удобочитаемое значение дисплея.
- Третье значение - это фактическое среднее значение, которое было масштабировано.
Я использовал math.ceil
в этой логике, но вы можете решить свою собственную логику позже, как вы сказали.
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.