tutorial.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. Your first Wagtail site
  2. =======================
  3. 1. Install Wagtail and its dependencies:
  4. ``pip install wagtail``
  5. 2. Start your site:
  6. ``wagtail start mysite``
  7. Wagtail provides a ``start`` command similar to
  8. ``django-admin.py startproject``. Running ``wagtail start mysite`` in
  9. your project will generate a new ``mysite`` folder with a few
  10. Wagtail-specific extras, including the required project settings, a
  11. ``requirements.txt`` file to track your project's dependencies, and a
  12. "core" app with a blank ``HomePage`` model and basic templates
  13. 3. Create the database:
  14. ``python manage.py migrate``
  15. If you haven't updated the project settings, this will be a SQLite
  16. database file in the project directory.
  17. 4. Create an admin user:
  18. ``python manage.py createsuperuser``.
  19. 5. ``python manage.py runserver`` If everything worked,
  20. http://127.0.0.1:8000 will show you a welcome page
  21. .. figure:: ../_static/images/tutorial/tutorial_1.png
  22. :alt: Wagtail welcome message
  23. You can now access the administrative area at ``/admin``
  24. .. figure:: ../_static/images/tutorial/tutorial_2.png
  25. :alt: Administrative screen
  26. Extend the HomePage model
  27. -------------------------
  28. Out of the box you get a blank HomePage model and the core app has a
  29. migration that creates a homepage and configures Wagtail to use it.
  30. This example extends the HomePage model to add a body field.
  31. .. code:: python
  32. from django.db import models
  33. from wagtail.wagtailcore.models import Page
  34. from wagtail.wagtailcore.fields import RichTextField
  35. from wagtail.wagtailadmin.edit_handlers import FieldPanel
  36. class HomePage(Page):
  37. body = RichTextField(blank=True)
  38. content_panels = Page.content_panels + [
  39. FieldPanel('title', classname="full title"),
  40. FieldPanel('intro')
  41. ]
  42. ``body`` is defined as ``RichTextField``, a special Wagtail field. You
  43. can use any of the Django core fields. ``content_panels`` define the
  44. capabilities and the layout of the editing interface. :doc:`More on creating Page models. <../topics/creating_pages>`
  45. Run ``python manage.py makemigrations``, then
  46. ``python manage.py migrate`` to update the database with your model
  47. changes. You must run the above commands each time you make changes to
  48. the model definition.
  49. To reflect the model changes, edit
  50. ``core/templates/core/home_page.html``. Wagtail uses normal Django
  51. templates to render each page type. It automatically generates a
  52. suggestion by separating capital letters with underscores (e.g. HomePage
  53. becomes home\_page.html).
  54. .. code:: html+django
  55. {% extends "base.html" %}
  56. {% load static core_tags wagtailcore_tags %}
  57. {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}
  58. {% block content %}
  59. {{ self.body|richtext }}
  60. {% endblock %}
  61. .. figure:: ../_static/images/tutorial/tutorial_3.png
  62. :alt: Updated homepage
  63. A basic blog
  64. ------------
  65. We are now ready to create a blog. To do so run
  66. ``python manage.py startapp blog`` to create a new app in your Wagtail
  67. site.
  68. The following example defines a basic blog post model in
  69. ``blog/models.py``
  70. .. code:: python
  71. from django.db import models
  72. from wagtail.wagtailcore.models import Page
  73. from wagtail.wagtailcore.fields import RichTextField
  74. from wagtail.wagtailadmin.edit_handlers import FieldPanel
  75. from wagtail.wagtailsearch import index
  76. class BlogPage(Page):
  77. date = models.DateField("Post date")
  78. intro = models.CharField(max_length=250)
  79. body = RichTextField(blank=True)
  80. search_fields = Page.search_fields + (
  81. index.SearchField('intro'),
  82. index.SearchField('body'),
  83. )
  84. content_panels = Page.content_panels + [
  85. FieldPanel('title', classname="full title"),
  86. FieldPanel('date'),
  87. FieldPanel('intro'),
  88. FieldPanel('body', classname="full")
  89. ]
  90. Add the new ``blog`` app to ``INSTALLED_APPS`` in
  91. ``mysite/settings/base.py``. Run ``python manage.py makemigrations`` and
  92. ``python manage.py migrate``.
  93. .. figure:: ../_static/images/tutorial/tutorial_4.png
  94. :alt: Create page screen
  95. .. figure:: ../_static/images/tutorial/tutorial_5.png
  96. :alt: Page edit screen
  97. Image support
  98. ~~~~~~~~~~~~~
  99. Wagtail provides support for images out of the box. To add them to your
  100. model:
  101. .. code:: python
  102. from django.db import models
  103. from wagtail.wagtailcore.models import Page
  104. from wagtail.wagtailcore.fields import RichTextField
  105. from wagtail.wagtailadmin.edit_handlers import FieldPanel
  106. from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
  107. from wagtail.wagtailsearch import index
  108. class BlogPage(Page):
  109. main_image = models.ForeignKey(
  110. 'wagtailimages.Image',
  111. null=True,
  112. blank=True,
  113. on_delete=models.SET_NULL,
  114. related_name='+'
  115. )
  116. date = models.DateField("Post date")
  117. intro = models.CharField(max_length=250)
  118. body = RichTextField(blank=True)
  119. search_fields = Page.search_fields + (
  120. index.SearchField('intro'),
  121. index.SearchField('body'),
  122. )
  123. content_panels = Page.content_panels + [
  124. FieldPanel('title', classname="full title"),
  125. FieldPanel('date'),
  126. ImageChooserPanel('main_image'),
  127. FieldPanel('intro'),
  128. FieldPanel('body'),
  129. ]
  130. Adjust your BlogPage template to output the image:
  131. .. code:: html+django
  132. {% extends "base.html" %}
  133. {% load static core_tags wagtailcore_tags wagtailimages_tags %}
  134. {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}
  135. {% block content %}
  136. <h1>{{ self.title }}</h1>
  137. <p class="meta">{{ self.date }}</p>
  138. {% if self.main_image %}
  139. {% image self.main_image width-400 %}
  140. {% endif %}
  141. <div class="intro">{% self.intro %}</div>
  142. {{ self.body | richtext }}
  143. {% endblock %}
  144. .. figure:: ../_static/images/tutorial/tutorial_6.png
  145. :alt: A blog post sample
  146. You can read more about using images in templates in the
  147. :doc:`docs <../topics/images>`.
  148. Blog Index
  149. ~~~~~~~~~~
  150. Let us extend the Blog app to provide an index.
  151. .. code:: python
  152. class BlogIndexPage(Page):
  153. intro = RichTextField(blank=True)
  154. content_panels = Page.content_panels + [
  155. FieldPanel('title', classname="full title"),
  156. FieldPanel('intro', classname="full")
  157. ]
  158. The above creates an index type to collect all our blog posts.
  159. ``blog/templates/blog/blog_index_page.html``
  160. .. code:: html+django
  161. {% extends "base.html" %}
  162. {% load static core_tags wagtailcore_tags %}
  163. {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}
  164. {% block content %}
  165. <h1>{{ self.title }}</h1>
  166. <div class="intro">{{ self.intro }}</div>
  167. {% endblock %}
  168. Related items
  169. ~~~~~~~~~~~~~
  170. Let's extend the BlogIndexPage to add related links. The related links
  171. can be BlogPages or external links. Change ``blog/models.py`` to
  172. .. code:: python
  173. from django.db import models
  174. from modelcluster.fields import ParentalKey
  175. from wagtail.wagtailcore.models import Page, Orderable
  176. from wagtail.wagtailcore.fields import RichTextField
  177. from wagtail.wagtailadmin.edit_handlers import (FieldPanel,
  178. InlinePanel,
  179. MultiFieldPanel,
  180. PageChooserPanel)
  181. from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
  182. from wagtail.wagtailsearch import index
  183. class BlogPage(Page):
  184. main_image = models.ForeignKey(
  185. 'wagtailimages.Image',
  186. null=True, blank=True,
  187. on_delete=models.SET_NULL,
  188. related_name='+'
  189. )
  190. date = models.DateField("Post date")
  191. intro = models.CharField(max_length=250)
  192. body = RichTextField(blank=True)
  193. search_fields = Page.search_fields + (
  194. index.SearchField('intro'),
  195. index.SearchField('body'),
  196. )
  197. content_panels = Page.content_panels + [
  198. FieldPanel('title', classname="full title"),
  199. FieldPanel('date'),
  200. ImageChooserPanel('main_image'),
  201. FieldPanel('intro'),
  202. FieldPanel('body'),
  203. ]
  204. class LinkFields(models.Model):
  205. link_external = models.URLField("External link", blank=True)
  206. link_page = models.ForeignKey(
  207. 'wagtailcore.Page',
  208. null=True,
  209. blank=True,
  210. related_name='+'
  211. )
  212. @property
  213. def link(self):
  214. if self.link_page:
  215. return self.link_page.url
  216. else:
  217. return self.link_external
  218. panels = [
  219. FieldPanel('link_external'),
  220. PageChooserPanel('link_page'),
  221. ]
  222. class Meta:
  223. abstract = True
  224. # Related links
  225. class RelatedLink(LinkFields):
  226. title = models.CharField(max_length=255, help_text="Link title")
  227. panels = [
  228. FieldPanel('title'),
  229. MultiFieldPanel(LinkFields.panels, "Link"),
  230. ]
  231. class Meta:
  232. abstract = True
  233. class BlogIndexRelatedLink(Orderable, RelatedLink):
  234. page = ParentalKey('BlogIndexPage', related_name='related_links')
  235. class BlogIndexPage(Page):
  236. intro = RichTextField(blank=True)
  237. content_panels = Page.content_panels + [
  238. FieldPanel('title', classname="full title"),
  239. InlinePanel('related_links', label="Related links"),
  240. ]
  241. .. figure:: ../_static/images/tutorial/tutorial_7.png
  242. :alt: Blog index edit screen
  243. Extend ``blog_index_page.html`` to show related items
  244. .. code:: html+django
  245. {% extends "base.html" %}
  246. {% load static core_tags wagtailcore_tags %}
  247. {% block body_class %}template-{{ self.get_verbose_name|slugify }}{% endblock %}
  248. {% block content %}
  249. <h1>{{ self.title }}</h1>
  250. <div class="intro">{{ self.intro }}</div>
  251. {% if self.related_links.all %}
  252. <ul>
  253. {% for item in self.related_links.all %}
  254. <li><a href="{{ item.link }}">{{ item.title }}</a></li>
  255. {% endfor %}
  256. </ul>
  257. {% endif %}
  258. {% endblock %}
  259. You now have a fully working blog with featured blog posts.
  260. .. figure:: ../_static/images/tutorial/tutorial_8.png
  261. :alt: Barebones blog index
  262. Where next
  263. ----------
  264. - Read the Wagtail :doc:`topics <../topics/index>` and :doc:`reference <../reference/index>` documentation
  265. - Learn how to implement :doc:`StreamField <../topics/streamfield>` for freeform page content
  266. - Browse through the :doc:`advanced topics <../advanced_topics/index>` section and read :doc:`third-party tutorials <../advanced_topics/third_party_tutorials>`