woocommerce建站教程_新手建站论坛

woocommerce建站教程_新手建站论坛Wagtail是一款基于Django的CMS开源框架,集成的功能非常多,很适合做定制站点开发。

Wagtail是一款基于Django的CMS开源框架,集成的功能非常多,很适合做定制站点开发。本文是从Wagtail官网翻译的一篇教程(官网教程:Your first Wagtail site),由于原文比较长,我把它分成了三个部分,今天这篇文章是第三部分,主要内容是为博客文章添加图片上传功能、添加Tagging标签系统以及Categories分类系统。

如果您还没有看过前面的教程,可以参考:

Wagtail建站入门(一)

Wagtail建站入门(二)

图片Images

虽然可以简单地在富文本框body字段中插入图片,但是设置图片库作为一个新的对象类型还是若干优点的,比如我们可以完全控制模板中图像的布局和风格,而不是在富文本框中不停的推拽图片,而且这样上传的图片可以独立于文章(在其它地方使用),例如在博客列表中显示一个缩略图。

我们来添加博客文章的图片上传功能,在models.py中添加一个新的BlogPageGalleryImage类:

from django.db import models
# New imports added for ParentalKey, Orderable, InlinePanel
from modelcluster.fields import ParentalKey

from wagtail.models import Page, Orderable
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel, InlinePanel
from wagtail.search import index
# ... (Keep the definition of BlogIndexPage, and update BlogPage:)
class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    
    search_fields = Page.search_fields + [
        index.SearchField('intro'),
        index.SearchField('body'),
    ]

    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('intro'),
        FieldPanel('body', classname="full"),
        InlinePanel('gallery_images', label="Gallery
        images"),
    ]

class BlogPageGalleryImage(Orderable):
    page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='gallery_images')
    image = models.ForeignKey(
        'wagtailimages.Image', on_delete=models.CASCADE, related_name='+'
    )
    caption = models.CharField(blank=True, max_length=250)
    
    panels = [
        FieldPanel('image'),
        FieldPanel('caption'),
    ]

添加完新的Model运行migrate:

python manage.py makemigrations
python manage.py migrate

这里有一些新的概念,我们来讲解一下:从Orderable继承的model中增加了sort_order字段,主要是为了记录图像库中图片的顺序。

ParentalKey方法中引用BlogPage,主要定义了这个类关联了具体哪个特定的Page页面。ParentalKey的用法有些像ForeignKey,区别是ParentalKey会将BlogPageGalleryImage作为BlogPage的子类,以便它可以使用Page的基本功能例如提交修改、记录历史版本等。

Image字段是一个外键,类型是Wagtail的内置图像Model,指向的位置当然就是图像真正存储的地方。这个字段在页面编辑器中会显示为图像弹出选择框/上传新图片功能。通过这种方法我们可以允许一个图片存在于多个图片库中,这样其实很有效地实现了页面和图片的多对多关系。

在外键中指定on_delete=models.CASCADE的意思是如果在网站中删除图片,图库入口则同步删除。其他情况下,可能保留图库入口更合适,举例来说,如果在员工列表页面中显示员工和大头照的列表,我们可能更希望没有大头照也要保留人员信息,这种情况我们设定外键为:

blank=True, null=True, on_delete=models.SET_NULL。

最后,在BlogPage.content_panels 中添加InlinePanel,这样在Admin后台界面中BlogPage就会出现编辑图库的入口了。

修改blog page模板可以显示图片:

{% extends "base.html" %}

{% load wagtailcore_tags wagtailimages_tags %}

{% block body_class %}template-blogpage{% endblock %}

{% block content %}
<h1>{{ page.title }}</h1>
<p class="meta">{{ page.date }}</p>

<div class="intro">{{ page.intro }}</div>

{{ page.body|richtext }}

{% for item in page.gallery_images.all %}
    <div style="float: left; margin: 10px">
    {% image item.image fill-320x240 %}
    <p>{{ item.caption }}</p>
    </div>
{% endfor %}

<p><a href="{{ page.get_parent.url }}">Return to blog</a></p>

{% endblock %}

这里我们使用{% image %}标签(存在于wagtailimages_tags库中,这个库需在模板的开头引用)来插入一个<img>元素, fill-320×240表示图片将被重置为320×240大小。

woocommerce建站教程_新手建站论坛

由于我们的图片库是数据库对象,现在我们可以单独查询并重用图片。我们来定义一个main_image函数,这个函数会返回图库中的第一个图片(如果无图返回None)。

class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    
    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    search_fields = Page.search_fields + [
        index.SearchField('intro'),
        index.SearchField('body'),
    ]
    
    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('intro'),
        FieldPanel('body', classname="full"),
        InlinePanel('gallery_images', label="Gallery
        images"),
    ]

添加好之后,这个函数就可以在模板中调用了,更新blog_index_page.html可以为每一篇文章显示缩略图:

{% load wagtailcore_tags wagtailimages_tags %}
...
{% for post in blogpages %}
    {% with post=post.specific %}
    <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2>
    
    {% with post.main_image as main_image %}
    {% if main_image %}{% image main_image fill-160x100 %}{% endif %}
    {% endwith %}
    
    <p>{{ post.intro }}</p>
    {{ post.body|richtext }}
    {% endwith %}
{% endfor %}

博客的标签(Tagging)功能

我们想要一个可以让主编们为文章打“标签”功能,这样网站的读者就可以按照诸如查看所有关于自行车的文章这种方式检索。这时我们需要引入Wagtail自带的标签系统,将它绑定到BlogPage model和content panels中,然后为文章模板添加标签链接,当然,我们也可以通过标签url查看打上“标签”的文章。

首先,再次修改models.py:

from django.db import models

# New imports added for ClusterTaggableManager, TaggedItemBase,
MultiFieldPanel

from modelcluster.fields import ParentalKey
from modelcluster.contrib.taggit importClusterTaggableManager
from taggit.models import TaggedItemBase

from wagtail.models import Page, Orderable
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel
from wagtail.search import index
# ... (Keep the definition of BlogIndexPage)
class BlogPageTag(TaggedItemBase):
    content_object = ParentalKey(
        'BlogPage',
        related_name='tagged_items',
        on_delete=models.CASCADE
    )

class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    
    # ... (Keep the main_image method and search_fields definition)
    content_panels = Page.content_panels + [
        MultiFieldPanel([
        FieldPanel('date'),
        FieldPanel('tags'),
        ], heading="Blog information"),
        FieldPanel('intro'),
        FieldPanel('body'),
        InlinePanel('gallery_images', label="Gallery
        images"),
    ]

运行

python manage.py makemigrations
python manage.py migrate

注意这里我们引入了modelcluster和taggit库,添加了BlogPageTag model,在BlogPage中添加了一个tags字段,这次为了后台便于查看和操作,我们在content_panels中使用MultiFieldPanel将date和tags作为一个组放在了一起。

去Admin后台找一篇文章编辑,我们会发现现在可以为文章加上标签了:

woocommerce建站教程_新手建站论坛

前台界面也要显示,我们编辑一下模板blog_page.html:

{% if page.tags.all.count %}
    <div class="tags">
    <h3>Tags</h3>
        {% for tag in page.tags.all %}
            <a href="{% slugurl 'tags' %}?tag={{ tag }}"><button type="button">{{ tag }}</button></a>
        {% endfor %}
    </div>
{% endif %}

注意上述模板代码中我们没有和前面代码一样使用pageurl标签,而是使用内置的slugurl标签。这两个标签的区别的slugurl要传入slug(在Promote标签页中设置)做为参数。Pageurl会更通用一些因为参数意义明确,且不需要额外的数据库查询。但是在当前代码中,这时候Page对象还没有完整的数据,所以我们转而使用slugurl标签。

在前台界面打开博客文章,这时候应该可以在文章的每个Tag下面有一个链接按钮。但是现在点击按钮会显示404错误,因为我们还没由定义tags的view。在models.py中添加:

class BlogTagIndexPage(Page):
    def get_context(self, request):
    
    # Filter by tag
    tag = request.GET.get('tag')
    blogpages = BlogPage.objects.filter(tags__name=tag)
    
    # Update template context
    context = super().get_context(request)
    context['blogpages'] = blogpages
    return context

注意这个基于Page的model没有定义任何字段,继承自Page是为了确保它可以在Wagtail中创建,并且可以在admin中编辑title和URL,同时可以重写get_context()方法并且返回一个QuerySet。

Migrate之后,在Admin中创建一个BlogTagIndexPage。确保这个Page作为HomePage的子页面,与之前的Blog列表界面并行,然后在Promote tab中设置slug为“tags”。

访问/tags,这时候Django会提示还没有创建模板,我们添加标签模板blog/blog_tag_index_page.html:

{% extends "base.html" %}
{% load wagtailcore_tags %}

{% block content %}

{% if request.GET.tag %}
    <h4>Showing pages tagged "{{ request.GET.tag }}"</h4>
{% endif %}

{% for blogpage in blogpages %}
    <p>
    <strong><a href="{% pageurl blogpage %}">{{ blogpage.title }}</a></strong><br />
    <small>Revised: {{ blogpage.latest_revision_created_at }}</small><br />
    {% if blogpage.author %}
        <p>By {{ blogpage.author.profile }}</p>
    {% endif %}
    </p>
    
    {% empty %}
     No pages found with that tag.
{% endfor %}

{% endblock %}

上面的模板代码中我们调用Page model内置的latest_revision_created_at字段,很容易理解这个字段总是可用的。

我们还没有为BlogPage添加作者字段,另外我们也没有创建作者model,这些就留给读者自行练习吧。

这时候点击BlogPost下面的tab按钮,将会链接至这个页面:

woocommerce建站教程_新手建站论坛

文章分类Categories

下面我们为博客添加分类系统,博客写作者(主编之类的角色吧)一般在页面编辑的时候为文章设置tag,和Tags不一样的是,Categories一般是一个固定的列表,这个列表通常由站长(网站拥有者)事先在Admin后台维护好。

首先,我们定义一个BlogCategory model. 分类本身不是页面,所以我们将其定义为标准的Django Model。

Wagtail引入了“snippets”的概念,专门用于需要通过Admin管理界面进行管理而无需作为页面的情况。通过添加@register_snippet装饰器,可以将Models注册为snippets。

from wagtail.snippets.models import register_snippet

@register_snippet
class BlogCategory(models.Model):
    name = models.CharField(max_length=255)
    icon = models.ForeignKey(
        'wagtailimages.Image', null=True, blank=True,
        on_delete=models.SET_NULL, related_name='+'
    )

    panels = [
        FieldPanel('name'),
        FieldPanel('icon'),
    ]
    
    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'blog categories'

注意在这里我们使用panels而不是content_panels,主要因为snippets不需要slug或者发布功能,所以admin编辑界面就不区分content/promote/settings了,所以Panels也就不用在细分。

把Model的变化Migrate,然后从后台管理界面的Snippets的菜单找到分类管理,创建几个分类。

现在我们将categories作为many-to-many(多对多)类型添加到BlogPage model,这里我们使用ParentalManyToManyField,这是Django标准ManyToManyField的一个变种,主要可以确保选择的分类可以正确的记录page的版本信息。同样,大多数情况,对于one-to-many(一对多)的情形,使用ParentalKey代替ForeignKey。

# New imports added for forms and ParentalManyToManyField
from django import forms
from django.db import models
from modelcluster.fields import ParentalKey,ParentalManyToManyField
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase

class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
    categories =ParentalManyToManyField('blog.BlogCategory', blank=True)
    # ... (Keep the main_image method and search_fields definition)
    content_panels = Page.content_panels + [
        MultiFieldPanel([
        FieldPanel('date'),
        FieldPanel('tags'),
        FieldPanel('categories', widget=forms.CheckboxSelectMultiple),
    ], heading="Blog information"),
        FieldPanel('intro'),
        FieldPanel('body'),
        InlinePanel('gallery_images', label="Gallery
        images"),
    ]

这里我们指定一个checkbox的widget作为参数传入FieldPanel,这个widget将代替默认的多选下拉框,指定的下拉框使用起来会更用户友好些。

最后,我们更新blog_page.html模板来显示分类:

<h1>{{ page.title }}</h1>
<p class="meta">{{ page.date }}</p>


{% with categories=page.categories.all %}
{% if categories %}
<h3>Posted in:</h3>
<ul>
{% for category in categories %}
    <li style="display:inline">
    {% image category.icon fill-32x32 style="vertical-align:middle" %}
    {{ category.name }}
    </li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}

Wagtail建站入门就到这里,欢迎交流,谢谢。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/11985.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注