#python #html #django
#python #HTML #django
Вопрос:
В view.py Я пытаюсь разделить значение атрибута, которое является длинной строкой. В обычном запросе:
someposts = Posts.object.all()[3:5]
должен возвращать:
<QuerySet [object<first post>, object<second post>]>
Итак, затем я запрашиваю сообщения следующим образом, поскольку мне нужно разделить значение атрибута (после этого изменения я получаю ошибку):
someposts = Posts.object.all().values('id', 'title', 'tags')[3:5]
таким образом, он возвращает что-то вроде:
<QuerySet [{'id': 2, 'title': 'first post', 'tags': ' X1, X2, X3,.., X10'}, {'id': 4, 'title': 'second post', 'tags': ' S1, S2, S3,.., S8'}]
Но я ожидаю получить tags
в виде списка жал, так что я сделал:
splited_tags = [v['tags'].split(',') for v in someposts]
for n, i in enumerate(someposts):
someposts[n]['tags'] = splited_tags[n]
и в результате
<QuerySet [{'id': 2, 'title': 'first post', 'tags': [' X1', 'X2', 'X3',.., X10']}, {'id': 4, 'title': 'second post', 'tags': [' S1', 'S2', 'S3,.., 'S8']}]
поскольку я передаю someposts
свой шаблон:
context = {
'someposts':someposts,
}
return render(request, 'app/home.html', context)
и в home.html:
{%for post in someposts %}
<a class="avator" href="{% url 'user-post' post.author.username %}"></a>
{ % endfor %}
Я получаю эту ошибку:
Обратный для ‘user-post’ с аргументами ‘(«,)’ не найден
Я думаю, проблема в том, что post.author.username
поскольку post является строкой, у нее нет .author
атрибута, поэтому он будет вычислен до string_if_invalid, который, если я не указал иначе, является пустой строкой «.
Вы знаете, как решить эту ошибку? или как разделить строку внутри набора запросов?
Ответ №1:
Конечно, у вас есть несколько вариантов, чтобы сделать это правильно, но чтобы решить вашу проблему очень быстро, я дам вам самое простое решение:
На самом деле вы можете комментировать сообщения, чтобы в каждом сообщении у вас было имя пользователя автора:
from django.db.models import F
Post.objects.annotate(formatted_author=F('author__username')).values('id', 'formatted_author')
Таким образом, вы можете получить имя пользователя автора, который написал сообщение. Но будьте осторожны, чтобы, если у вас есть некоторые нулевые значения в поле author некоторых сообщений, вы не получили никаких значений в ответе.
Однако, если вы используете Postgres в качестве своей базы данных, вы можете использовать встроенную функциональность arrayField Postgres и таким образом сделать свою аннотацию еще более элегантной:
from django.db.models.expressions import Func
from django.db.models import F, Value, TextField
from django.contrib.postgres.fields import ArrayField
formatted_author = F('author__username')
formatted_tags = Func(
F('tags'),
Value(","),
function='regexp_split_to_array', output=ArrayField(TextField())
)
Post.objects
.annotate(formatted_author=formatted_author, formatted_tags=formatted_tags)
.values('id', 'formatted_author', 'formatted_tags')
Таким образом, вы также сэкономите затраты на выполнение SQL-запросов на каждой итерации, которые вы выполняли ранее.
Обновление 1
Если у вас нет базы данных Postgres, то мне жаль сообщать вам, что вам все еще нужно обрабатывать теги в коде python, и у меня есть несколько улучшенных рефакторингов для вашей текущей реализации. Итак, что у вас есть сейчас:
splited_tags = [v['tags'].split(',') for v in someposts]
for n, i in enumerate(someposts):
someposts[n]['tags'] = splited_tags[n]
И что я рекомендую:
someposts = list(map(lambda somepost: dict(formatted_tags=somepost['tags'].split(','), **somepost), someposts))
Как вы видите, для этого требуется только одна итерация только с новым свойством компромисса, но это всего лишь мое предложение.
Обновление 2
Поскольку владелец сообщения спросил о свойствах post.author.profile.user.first_name
и post.author.profile.image.url
в своем комментарии, я хотел бы подробнее остановиться на этом.
В общем, вы не можете получить эти свойства, потому что вы явно не выбираете их в своей .values()
функции. .values()
будут получены только те свойства, которые выбраны. Итак, в основном, что вы можете сделать, это снова создать F
переменные (для уменьшения длины имени) с аннотациями:
from django.db.models import F
Post.objects.annotate(formatted_author=F('author__username'), formatted_first_name=F('author__profile__user__first_name'), formatted_image=F('author__profile__image')).values('id', 'formatted_author', 'formatted_first_name', 'formatted_image')
И, как подсказывает мне моя интуиция, на самом деле post.author.first_name
эквивалентно post.author.profile.user.first_name
, но я могу ошибаться, если у вас другая структура модели. 🙂
Комментарии:
1. Спасибо за ваш ответ. Я пробовал с вашим первым решением и последним решением, поскольку я использую базу данных MySQL. В обоих случаях я получаю ошибку, в последнем говорится, что ‘d’ не определен, а в первом говорится, что существует конфликт между автором и одной из ваших форм модели, в то время как в форме модели у меня просто есть
author
,title
,tags
,date
2. Это ошибка первой части:
The annotation 'author' conflicts with a field on the model.
3. Извините за опечатку, я только что проверил на своем компьютере и забыл изменить имена, теперь должны работать как 1-е, так и 3-е решения. Я забыл, что у вас уже было
author
свойство вPost
модели, поэтому теперь я переименовал его вformatted_author
, в последнем решении вместо должна была бытьsomepost
переменная.4. @Braiano пожалуйста, проверьте их еще раз
5. Спасибо за обновление. Я заменил его
post.author.username
наpost.formatted_author
, он почти работает, однако все еще есть два других раздела{{ post.author.profile.user.first_name }}
и{{ post.author.profile.image.url }}
, которые не загружают значения. Все эти переменные работали раньше!
Ответ №2:
Быстрое решение вашей проблемы:
class Posts((models.Model):
....
tags = ...
....
def get_tags(self):
if self.tags:
return self.tags.split(",")
else:
None
а затем в вашем шаблоне попробуйте назвать это чем-то вроде:
{% for tag in someposts.get_tags %}
{{ tag }}
{% endfor %}
Однако имейте в виду, что чрезмерно толстые модели могут превратиться в кучу не поддерживаемого материала. Вы бы преобразовали некоторые свои сериализованные данные в Python, что имеет смысл сделать на уровне модели. Но попробуйте справиться с такого рода проблемами в представлении!