如何修复错误 'str' object 没有属性 'relative_url'
How to fix error 'str' object has no attribute 'relative_url'
我正在尝试将一些 wagtail 上下文传递到 django 项目的搜索页面。 post 标题出现,但图像、描述和其他参数未出现在搜索模板中。如何将这些上下文传递给搜索模板?
这是我得到的错误
AttributeError at /search/
'str' object has no attribute 'relative_url'
Request Method: GET
Request URL: http://127.0.0.1:8000/search/?q=hel
Django Version: 3.1.3
Exception Type: AttributeError
Exception Value:
'str' object has no attribute 'relative_url'
Exception Location: C:\Users\Bree\AppData\Roaming\Python\Python37\site-packages\wagtail\contrib\routable_page\templatetags\wagtailroutablepage_tags.py, line 25, in routablepageurl
Python Executable: C:\Program Files\Python37\python.exe
Python Version: 3.7.3
这是search.view.py代码
from django.shortcuts import render
from wagtail.core.models import Page
from wagtail.search.models import Query
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from news.models import NewsPage, NewsCategory
def search(request):
posts = NewsPage.objects.live().public()
categories = NewsCategory.objects.all()
# Search
search_query = request.GET.get('q', None)
if search_query:
search_results = NewsPage.objects.live().search(search_query)
# Log the query so Wagtail can suggest promoted results
Query.get(search_query).add_hit()
reversenews = list(reversed(search_results))
# Pagination
paginator = Paginator(reversenews, 16) #show 10 articles per page
page = request.GET.get('page')
try:
search_results = paginator.page(page)
except PageNotAnInteger:
search_results = paginator.page(1)
except EmptyPage:
search_results = paginator.page(paginator.num_pages)
else:
search_results = NewsPage.objects.none()
# Render template
return render(request, 'search/search.html', {
'search_query': search_query,
'search_results': search_results,
'recent_posts' : posts,
'categories' : categories
})
这是搜索模板search.html
{% extends "news/news_index_page.html" %}
{% load static wagtailcore_tags %}
{% load wagtailembeds_tags %}
{% load wagtailcore_tags %}
{% load static wagtailuserbar %}
{% load wagtailimages_tags %}
{%load static%}
{% load wagtailcore_tags %}
{% load wagtailroutablepage_tags %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8">
<h3>Query Results FOR <b>"{{ search_query }}"</b></h3>
<div class="post">
{% if search_results %}
<div class="row">
{% for result in search_results %}
<div class="col-md-6 col-sm-6">
<div class="images">
{% image result.blog_image max-770x480 as blog_img %}
<a class="images" href="{% pageurl result %}" title="images"><img src="{{result.blog_image}}" alt="images"></a>
</div>
<div class="text">
<h2><a href="{% pageurl result %}" title="title">{{result.title}}</a></h2>
<div class="categories">
{% for cat in result.categories.all%}
<a href="{% routablepageurl news_page 'category_view' cat.slug %}" style="color:white">{{cat.name}}</a>
{%endfor%}
<p class="date"><i class="fa fa-clock-o"></i>{{result.date}}</p>
</div>
<p>{{result.description}}</p>
<a href="{% pageurl result %}" title="read more">read more</a>
</div>
{%endfor%}
</div>
{% elif search_query %}
<p> No results found</p>
<img src="{% static '/images/not_found %}" alt="image">
{% endif %}
</div>
<!-- Pagination -->
{% if search_results.paginator.num_pages > 1 %}
<div class="box center float-left space-30">
<nav class="pagination">
{% if search_results.has_previous %}
<a class="control prev" href="?page={{ search_results.previous_page_number }}" title="pre"><i class="fa fa-long-arrow-left"></i>Previous</a>
{% endif %}
<ul>
{% for page_num in search_results.paginator.page_range %}
<li class="{% if page_num == search_results.number %} active{% endif %}"><a href="?page={{ page_num }}" title="1">{{ page_num }}</a></li>
{% endfor %}
</ul>
{% if search_results.has_next %}
<a class="control next" href="?page={{ search_results.next_page_number }}" title="next">Next<i class="fa fa-long-arrow-right"></i></a>
{% endif %}
</nav>
<!-- End pagination -->
</div>
{% endif %}
</div>
</div>
这是models.py
from django.db import models
from django.shortcuts import render
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, MultiFieldPanel, InlinePanel
from wagtail.snippets.edit_handlers import SnippetChooserPanel
from wagtail.core.fields import StreamField
from wagtail.core.models import Page, Orderable
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.snippets.models import register_snippet
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from wagtailmenus.models import MenuPage
from django import forms
import datetime
from datetime import date
from streams import blocks
# Create your models here.
class NewsPageTag(TaggedItemBase):
content_object = ParentalKey(
'NewsPage',
related_name='tagged_items',
on_delete=models.CASCADE
)
class NewsIndexPage(RoutablePageMixin, Page):
custom_title = models.CharField(
max_length=100,
blank=True,
null=True,
help_text='Overwrites the default title',
)
content_panels = Page.content_panels + [
FieldPanel("custom_title"),
]
def get_context(self, request, *args, **kwargs):
"""Adding custom stuff to our context."""
context = super().get_context(request, *args, **kwargs)
posts = NewsPage.objects.live().public()
context["recent_posts"] = posts
context["tech_world"] = NewsPage.objects.live().filter(categories = 2)
context["digital_creatives"] = NewsPage.objects.live().filter(categories = 10)
context["exclusives"] = NewsPage.objects.live().filter(categories = 4)
context["news"] = NewsPage.objects.live().filter(categories = 1)
context["startups"] = NewsPage.objects.live().filter(categories = 3)
context['news_page'] = self
context['parent'] = self.get_parent().specific
context['categories'] = NewsCategory.objects.all()
return context
@route(r"^category/(?P<cat_slug>[-\w]*)/$", name="category_view")
def category_view(self, request, cat_slug):
context = self.get_context(request)
try:
category = NewsCategory.objects.all().get(slug=cat_slug)
except Exception:
category= None
if category is None:
pass
catPosts = NewsPage.objects.all().filter(categories__in=[category])
reversenews = list(reversed(catPosts))
paginator = Paginator(reversenews, 6)
page = request.GET.get("page")
try:
# If the page exists and the ?page=x is an int
posts = paginator.page(page)
except PageNotAnInteger:
# If the ?page=x is not an int; show the first page
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
context["posts"]= posts
context["category"] = NewsCategory.objects.all().get(slug=cat_slug)
return render(request, "news/cat_posts.html", context)
class NewsPage(Page):
"""Blog detail page."""
blog_image = models.ForeignKey(
"wagtailimages.Image",
blank=False,
null=True,
related_name="+",
on_delete=models.SET_NULL,
)
image_description = models.TextField(max_length=500, blank=True, null=True , default=" ")
categories = ParentalManyToManyField("news.NewsCategory", blank = True)
date = models.DateTimeField(verbose_name="Post date", default=datetime.datetime.today)
tags = ClusterTaggableManager(through=NewsPageTag, blank=True)
content = StreamField(
[
("full_richtext", blocks.RichtextBlock())
],
null=True,
blank=False
)
description = StreamField(
[
("full_richtext", blocks.RichtextBlock())
],
null=True,
blank=False
)
content_panels = Page.content_panels + [
MultiFieldPanel([
InlinePanel("news_authors", label="Author", min_num=1, max_num=4)
], heading="Author(s)"),
MultiFieldPanel([
FieldPanel("categories", widget = forms.CheckboxSelectMultiple),
FieldPanel('tags'),
FieldPanel('date'),
]),
ImageChooserPanel("blog_image"),
FieldPanel('image_description'),
StreamFieldPanel("content"),
StreamFieldPanel("description"),
]
@property
def news_page(self):
return self.get_parent().specific
def get_context(self, request, *args, **kwargs):
context = super(NewsPage, self).get_context(request, *args, **kwargs)
posts = NewsPage.objects.live().public()
context['categories'] = NewsCategory.objects.all()
context['news_page'] = self.news_page
context['post'] = self
context["recent_posts"]= NewsPage.objects.live().public()
return context
class NewsAuthor(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=500, blank=False, null=True)
email = models.URLField(blank=True, null=True)
image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.SET_NULL,
null = True,
blank = False,
related_name="+"
)
panels = [
MultiFieldPanel([
FieldPanel("name"),
FieldPanel("description"),
ImageChooserPanel("image")
], heading="Name & Image"),
MultiFieldPanel([
FieldPanel("email")
], heading="Links")
]
def __str__(self):
return self.name
register_snippet(NewsAuthor)
class NewsCategory(models.Model):
name= models.CharField(max_length=255)
slug = models.SlugField(
verbose_name="slug",
allow_unicode= True,
unique=True,
max_length=255,
help_text="A slug to identify posts by this category"
)
panels=[
FieldPanel("name"),
FieldPanel("slug")
]
class Meta:
verbose_name = 'News Category'
verbose_name_plural = 'News Categories'
ordering = ['name']
def __str__(self):
return self.name
register_snippet(NewsCategory)
这是urls.py
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.core import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls
from search import views as search_views
urlpatterns = [
url(r'^django-admin/', admin.site.urls),
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
url(r'^search/$', search_views.search, name='search'),
]
我做错了什么?
您模板中的 news_page
变量似乎是一个字符串,而不是页面对象,因为这是您共享的代码示例中唯一使用 {% routablepageurl %}
标记的地方。 但是,您没有显示 news_page
的定义位置,所以我可能弄错了。
我现在已经查看了您的模型文件,以及您定义 news_page
的位置。您已在 NewsIndexPage 的上下文中定义 news_page
。这将在使用 Wagtail 的内部视图显示 NewsIndexPage 时使用,但在呈现搜索视图时不会使用。
这是您在 search/views.py
中设置的响应上下文:
# Render template
return render(request, 'search/search.html', {
'search_query': search_query,
'search_results': search_results,
'recent_posts' : posts,
'categories' : categories
})
你能在上下文中添加 news_page
吗?
我正在尝试将一些 wagtail 上下文传递到 django 项目的搜索页面。 post 标题出现,但图像、描述和其他参数未出现在搜索模板中。如何将这些上下文传递给搜索模板?
这是我得到的错误
AttributeError at /search/
'str' object has no attribute 'relative_url'
Request Method: GET
Request URL: http://127.0.0.1:8000/search/?q=hel
Django Version: 3.1.3
Exception Type: AttributeError
Exception Value:
'str' object has no attribute 'relative_url'
Exception Location: C:\Users\Bree\AppData\Roaming\Python\Python37\site-packages\wagtail\contrib\routable_page\templatetags\wagtailroutablepage_tags.py, line 25, in routablepageurl
Python Executable: C:\Program Files\Python37\python.exe
Python Version: 3.7.3
这是search.view.py代码
from django.shortcuts import render
from wagtail.core.models import Page
from wagtail.search.models import Query
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from news.models import NewsPage, NewsCategory
def search(request):
posts = NewsPage.objects.live().public()
categories = NewsCategory.objects.all()
# Search
search_query = request.GET.get('q', None)
if search_query:
search_results = NewsPage.objects.live().search(search_query)
# Log the query so Wagtail can suggest promoted results
Query.get(search_query).add_hit()
reversenews = list(reversed(search_results))
# Pagination
paginator = Paginator(reversenews, 16) #show 10 articles per page
page = request.GET.get('page')
try:
search_results = paginator.page(page)
except PageNotAnInteger:
search_results = paginator.page(1)
except EmptyPage:
search_results = paginator.page(paginator.num_pages)
else:
search_results = NewsPage.objects.none()
# Render template
return render(request, 'search/search.html', {
'search_query': search_query,
'search_results': search_results,
'recent_posts' : posts,
'categories' : categories
})
这是搜索模板search.html
{% extends "news/news_index_page.html" %}
{% load static wagtailcore_tags %}
{% load wagtailembeds_tags %}
{% load wagtailcore_tags %}
{% load static wagtailuserbar %}
{% load wagtailimages_tags %}
{%load static%}
{% load wagtailcore_tags %}
{% load wagtailroutablepage_tags %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8">
<h3>Query Results FOR <b>"{{ search_query }}"</b></h3>
<div class="post">
{% if search_results %}
<div class="row">
{% for result in search_results %}
<div class="col-md-6 col-sm-6">
<div class="images">
{% image result.blog_image max-770x480 as blog_img %}
<a class="images" href="{% pageurl result %}" title="images"><img src="{{result.blog_image}}" alt="images"></a>
</div>
<div class="text">
<h2><a href="{% pageurl result %}" title="title">{{result.title}}</a></h2>
<div class="categories">
{% for cat in result.categories.all%}
<a href="{% routablepageurl news_page 'category_view' cat.slug %}" style="color:white">{{cat.name}}</a>
{%endfor%}
<p class="date"><i class="fa fa-clock-o"></i>{{result.date}}</p>
</div>
<p>{{result.description}}</p>
<a href="{% pageurl result %}" title="read more">read more</a>
</div>
{%endfor%}
</div>
{% elif search_query %}
<p> No results found</p>
<img src="{% static '/images/not_found %}" alt="image">
{% endif %}
</div>
<!-- Pagination -->
{% if search_results.paginator.num_pages > 1 %}
<div class="box center float-left space-30">
<nav class="pagination">
{% if search_results.has_previous %}
<a class="control prev" href="?page={{ search_results.previous_page_number }}" title="pre"><i class="fa fa-long-arrow-left"></i>Previous</a>
{% endif %}
<ul>
{% for page_num in search_results.paginator.page_range %}
<li class="{% if page_num == search_results.number %} active{% endif %}"><a href="?page={{ page_num }}" title="1">{{ page_num }}</a></li>
{% endfor %}
</ul>
{% if search_results.has_next %}
<a class="control next" href="?page={{ search_results.next_page_number }}" title="next">Next<i class="fa fa-long-arrow-right"></i></a>
{% endif %}
</nav>
<!-- End pagination -->
</div>
{% endif %}
</div>
</div>
这是models.py
from django.db import models
from django.shortcuts import render
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, MultiFieldPanel, InlinePanel
from wagtail.snippets.edit_handlers import SnippetChooserPanel
from wagtail.core.fields import StreamField
from wagtail.core.models import Page, Orderable
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.snippets.models import register_snippet
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from wagtailmenus.models import MenuPage
from django import forms
import datetime
from datetime import date
from streams import blocks
# Create your models here.
class NewsPageTag(TaggedItemBase):
content_object = ParentalKey(
'NewsPage',
related_name='tagged_items',
on_delete=models.CASCADE
)
class NewsIndexPage(RoutablePageMixin, Page):
custom_title = models.CharField(
max_length=100,
blank=True,
null=True,
help_text='Overwrites the default title',
)
content_panels = Page.content_panels + [
FieldPanel("custom_title"),
]
def get_context(self, request, *args, **kwargs):
"""Adding custom stuff to our context."""
context = super().get_context(request, *args, **kwargs)
posts = NewsPage.objects.live().public()
context["recent_posts"] = posts
context["tech_world"] = NewsPage.objects.live().filter(categories = 2)
context["digital_creatives"] = NewsPage.objects.live().filter(categories = 10)
context["exclusives"] = NewsPage.objects.live().filter(categories = 4)
context["news"] = NewsPage.objects.live().filter(categories = 1)
context["startups"] = NewsPage.objects.live().filter(categories = 3)
context['news_page'] = self
context['parent'] = self.get_parent().specific
context['categories'] = NewsCategory.objects.all()
return context
@route(r"^category/(?P<cat_slug>[-\w]*)/$", name="category_view")
def category_view(self, request, cat_slug):
context = self.get_context(request)
try:
category = NewsCategory.objects.all().get(slug=cat_slug)
except Exception:
category= None
if category is None:
pass
catPosts = NewsPage.objects.all().filter(categories__in=[category])
reversenews = list(reversed(catPosts))
paginator = Paginator(reversenews, 6)
page = request.GET.get("page")
try:
# If the page exists and the ?page=x is an int
posts = paginator.page(page)
except PageNotAnInteger:
# If the ?page=x is not an int; show the first page
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
context["posts"]= posts
context["category"] = NewsCategory.objects.all().get(slug=cat_slug)
return render(request, "news/cat_posts.html", context)
class NewsPage(Page):
"""Blog detail page."""
blog_image = models.ForeignKey(
"wagtailimages.Image",
blank=False,
null=True,
related_name="+",
on_delete=models.SET_NULL,
)
image_description = models.TextField(max_length=500, blank=True, null=True , default=" ")
categories = ParentalManyToManyField("news.NewsCategory", blank = True)
date = models.DateTimeField(verbose_name="Post date", default=datetime.datetime.today)
tags = ClusterTaggableManager(through=NewsPageTag, blank=True)
content = StreamField(
[
("full_richtext", blocks.RichtextBlock())
],
null=True,
blank=False
)
description = StreamField(
[
("full_richtext", blocks.RichtextBlock())
],
null=True,
blank=False
)
content_panels = Page.content_panels + [
MultiFieldPanel([
InlinePanel("news_authors", label="Author", min_num=1, max_num=4)
], heading="Author(s)"),
MultiFieldPanel([
FieldPanel("categories", widget = forms.CheckboxSelectMultiple),
FieldPanel('tags'),
FieldPanel('date'),
]),
ImageChooserPanel("blog_image"),
FieldPanel('image_description'),
StreamFieldPanel("content"),
StreamFieldPanel("description"),
]
@property
def news_page(self):
return self.get_parent().specific
def get_context(self, request, *args, **kwargs):
context = super(NewsPage, self).get_context(request, *args, **kwargs)
posts = NewsPage.objects.live().public()
context['categories'] = NewsCategory.objects.all()
context['news_page'] = self.news_page
context['post'] = self
context["recent_posts"]= NewsPage.objects.live().public()
return context
class NewsAuthor(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=500, blank=False, null=True)
email = models.URLField(blank=True, null=True)
image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.SET_NULL,
null = True,
blank = False,
related_name="+"
)
panels = [
MultiFieldPanel([
FieldPanel("name"),
FieldPanel("description"),
ImageChooserPanel("image")
], heading="Name & Image"),
MultiFieldPanel([
FieldPanel("email")
], heading="Links")
]
def __str__(self):
return self.name
register_snippet(NewsAuthor)
class NewsCategory(models.Model):
name= models.CharField(max_length=255)
slug = models.SlugField(
verbose_name="slug",
allow_unicode= True,
unique=True,
max_length=255,
help_text="A slug to identify posts by this category"
)
panels=[
FieldPanel("name"),
FieldPanel("slug")
]
class Meta:
verbose_name = 'News Category'
verbose_name_plural = 'News Categories'
ordering = ['name']
def __str__(self):
return self.name
register_snippet(NewsCategory)
这是urls.py
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.core import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls
from search import views as search_views
urlpatterns = [
url(r'^django-admin/', admin.site.urls),
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
url(r'^search/$', search_views.search, name='search'),
]
我做错了什么?
您模板中的 news_page
变量似乎是一个字符串,而不是页面对象,因为这是您共享的代码示例中唯一使用 {% routablepageurl %}
标记的地方。 但是,您没有显示 news_page
的定义位置,所以我可能弄错了。
我现在已经查看了您的模型文件,以及您定义 news_page
的位置。您已在 NewsIndexPage 的上下文中定义 news_page
。这将在使用 Wagtail 的内部视图显示 NewsIndexPage 时使用,但在呈现搜索视图时不会使用。
这是您在 search/views.py
中设置的响应上下文:
# Render template
return render(request, 'search/search.html', {
'search_query': search_query,
'search_results': search_results,
'recent_posts' : posts,
'categories' : categories
})
你能在上下文中添加 news_page
吗?