Your first Wagtail site
=======================

1. Install Wagtail and its dependencies:

   ``pip install wagtail``

2. Start your site:

   ``wagtail start mysite``

   Wagtail provides a ``start`` command similar to
   ``django-admin.py startproject``. Running ``wagtail start mysite`` in
   your project will generate a new ``mysite`` folder with a few
   Wagtail-specific extras, including the required project settings, a
   ``requirements.txt`` file to track your project's dependencies, and a
   "core" app with a blank ``HomePage`` model and basic templates

3. Create the database:

   ``python manage.py migrate``

   If you haven't updated the project settings, this will be a SQLite
   database file in the project directory.

4. Create an admin user:

   ``python manage.py createsuperuser``.

5. ``python manage.py runserver`` If everything worked,
   http://127.0.0.1:8000 will show you a welcome page

   .. figure:: ../_static/images/tutorial/tutorial_1.png
      :alt: Wagtail welcome message

   You can now access the administrative area at ``/admin``

   .. figure:: ../_static/images/tutorial/tutorial_2.png
      :alt: Administrative screen

Extend the HomePage model
-------------------------

Out of the box you get a blank HomePage model and the core app has a
migration that creates a homepage and configures Wagtail to use it.

This example extends the HomePage model to add a body field.

.. code:: python

    from django.db import models

    from wagtail.wagtailcore.models import Page
    from wagtail.wagtailcore.fields import RichTextField
    from wagtail.wagtailadmin.edit_handlers import FieldPanel


    class HomePage(Page):
        body = RichTextField(blank=True)

        content_panels = Page.content_panels + [
            FieldPanel('title', classname="full title"),
            FieldPanel('intro')
        ]

``body`` is defined as ``RichTextField``, a special Wagtail field. You
can use any of the Django core fields. ``content_panels`` define the
capabilities and the layout of the editing interface. :doc:`More on creating Page models. <../topics/creating_pages>`


Run ``python manage.py makemigrations``, then
``python manage.py migrate`` to update the database with your model
changes. You must run the above commands each time you make changes to
the model definition.

To reflect the model changes, edit
``core/templates/core/home_page.html``. Wagtail uses normal Django
templates to render each page type. It automatically generates a
suggestion by separating capital letters with underscores (e.g. HomePage
becomes home\_page.html).

.. code:: html+django

    {% extends "base.html" %}

    {% load static core_tags wagtailcore_tags %}

    {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}

    {% block content %}
        {{ self.body|richtext }}
    {% endblock %}

.. figure:: ../_static/images/tutorial/tutorial_3.png
   :alt: Updated homepage

A basic blog
------------

We are now ready to create a blog. To do so run
``python manage.py startapp blog`` to create a new app in your Wagtail
site.

The following example defines a basic blog post model in
``blog/models.py``

.. code:: python

    from django.db import models

    from wagtail.wagtailcore.models import Page
    from wagtail.wagtailcore.fields import RichTextField
    from wagtail.wagtailadmin.edit_handlers import FieldPanel
    from wagtail.wagtailsearch import index


    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('title', classname="full title"),
            FieldPanel('date'),
            FieldPanel('intro'),
            FieldPanel('body', classname="full")
        ]

Add the new ``blog`` app to ``INSTALLED_APPS`` in
``mysite/settings/base.py``. Run ``python manage.py makemigrations`` and
``python manage.py migrate``.

.. figure:: ../_static/images/tutorial/tutorial_4.png
   :alt: Create page screen

.. figure:: ../_static/images/tutorial/tutorial_5.png
   :alt: Page edit screen

Image support
~~~~~~~~~~~~~

Wagtail provides support for images out of the box. To add them to your
model:

.. code:: python

    from django.db import models

    from wagtail.wagtailcore.models import Page
    from wagtail.wagtailcore.fields import RichTextField
    from wagtail.wagtailadmin.edit_handlers import FieldPanel
    from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
    from wagtail.wagtailsearch import index


    class BlogPage(Page):
        main_image = models.ForeignKey(
            'wagtailimages.Image',
            null=True,
            blank=True,
            on_delete=models.SET_NULL,
            related_name='+'
        )
        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('title', classname="full title"),
            FieldPanel('date'),
            ImageChooserPanel('main_image'),
            FieldPanel('intro'),
            FieldPanel('body'),
        ]

Adjust your BlogPage template to output the image:

.. code:: html+django

    {% extends "base.html" %}

    {% load static core_tags wagtailcore_tags wagtailimages_tags %}

    {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}

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

        {% if self.main_image %}
          {% image self.main_image width-400 %}
        {% endif %}

        <div class="intro">{% self.intro %}</div>

        {{ self.body | richtext }}

    {% endblock %}

.. figure:: ../_static/images/tutorial/tutorial_6.png
   :alt: A blog post sample

You can read more about using images in templates in the
:doc:`docs <../topics/images>`.

Blog Index
~~~~~~~~~~

Let us extend the Blog app to provide an index.

.. code:: python

    class BlogIndexPage(Page):
        intro = RichTextField(blank=True)

        content_panels = Page.content_panels + [
            FieldPanel('title', classname="full title"),
            FieldPanel('intro', classname="full")
        ]

The above creates an index type to collect all our blog posts.

``blog/templates/blog/blog_index_page.html``

.. code:: html+django

    {% extends "base.html" %}

    {% load static core_tags wagtailcore_tags %}

    {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}

    {% block content %}
        <h1>{{ self.title }}</h1>

        <div class="intro">{{ self.intro }}</div>
    {% endblock %}

Related items
~~~~~~~~~~~~~

Let's extend the BlogIndexPage to add related links. The related links
can be BlogPages or external links. Change ``blog/models.py`` to

.. code:: python

    from django.db import models

    from modelcluster.fields import ParentalKey

    from wagtail.wagtailcore.models import Page, Orderable
    from wagtail.wagtailcore.fields import RichTextField
    from wagtail.wagtailadmin.edit_handlers import (FieldPanel,
                                                    InlinePanel,
                                                    MultiFieldPanel,
                                                    PageChooserPanel)
    from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
    from wagtail.wagtailsearch import index


    class BlogPage(Page):
        main_image = models.ForeignKey(
            'wagtailimages.Image',
            null=True, blank=True,
            on_delete=models.SET_NULL,
            related_name='+'
        )
        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('title', classname="full title"),
            FieldPanel('date'),
            ImageChooserPanel('main_image'),
            FieldPanel('intro'),
            FieldPanel('body'),
        ]


    class LinkFields(models.Model):
        link_external = models.URLField("External link", blank=True)
        link_page = models.ForeignKey(
            'wagtailcore.Page',
            null=True,
            blank=True,
            related_name='+'
        )

        @property
        def link(self):
            if self.link_page:
                return self.link_page.url
            else:
                return self.link_external

        panels = [
            FieldPanel('link_external'),
            PageChooserPanel('link_page'),
        ]

        class Meta:
            abstract = True


    # Related links

    class RelatedLink(LinkFields):
        title = models.CharField(max_length=255, help_text="Link title")

        panels = [
            FieldPanel('title'),
            MultiFieldPanel(LinkFields.panels, "Link"),
        ]

        class Meta:
            abstract = True


    class BlogIndexRelatedLink(Orderable, RelatedLink):
        page = ParentalKey('BlogIndexPage', related_name='related_links')


    class BlogIndexPage(Page):
        intro = RichTextField(blank=True)

        content_panels = Page.content_panels + [
            FieldPanel('title', classname="full title"),
            InlinePanel('related_links', label="Related links"),
        ]

.. figure:: ../_static/images/tutorial/tutorial_7.png
   :alt: Blog index edit screen

Extend ``blog_index_page.html`` to show related items

.. code:: html+django

    {% extends "base.html" %}

    {% load static core_tags wagtailcore_tags %}

    {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}

    {% block content %}
        <h1>{{ self.title }}</h1>

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

        {% if self.related_links.all %}
            <ul>
                {% for item in self.related_links.all %}
                    <li><a href="{{ item.link }}">{{ item.title }}</a></li>
                {% endfor %}
            </ul>
        {% endif %}
    {% endblock %}

You now have a fully working blog with featured blog posts.

.. figure:: ../_static/images/tutorial/tutorial_8.png
   :alt: Barebones blog index

Where next
----------

-  Read the Wagtail :doc:`topics <../topics/index>` and :doc:`reference <../reference/index>` documentation
-  Learn how to implement :doc:`StreamField <../topics/streamfield>` for freeform page content
-  Browse through the :doc:`advanced topics <../advanced_topics/index>` section and read :doc:`third-party tutorials <../advanced_topics/third_party_tutorials>`
