<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wagtail</title>
    <description>The latest articles on DEV Community by Wagtail (@wagtail).</description>
    <link>https://dev.to/wagtail</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1239%2Fee902099-3997-45c8-94a4-9bf95fe37958.png</url>
      <title>DEV Community: Wagtail</title>
      <link>https://dev.to/wagtail</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wagtail"/>
    <language>en</language>
    <item>
      <title>Wagtail API - how to customize the detail URL</title>
      <dc:creator>Dan Braghiș</dc:creator>
      <pubDate>Fri, 13 Dec 2019 15:42:15 +0000</pubDate>
      <link>https://dev.to/wagtail/wagtail-api-how-to-customize-the-detail-url-2j3l</link>
      <guid>https://dev.to/wagtail/wagtail-api-how-to-customize-the-detail-url-2j3l</guid>
      <description>&lt;p&gt;A while ago, a member of the Wagtail community wanted to customize the &lt;code&gt;PagesAPIEndpoint&lt;/code&gt; to access the specific page detail view via its slug (&lt;code&gt;/api/v2/pages/the-page-slug&lt;/code&gt;, rather than id (&lt;code&gt;/api/v2/pages/123&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.wagtail.io/en/v2.7/advanced_topics/api/v2/configuration.html"&gt;Wagtail API&lt;/a&gt; builds on the &lt;a href="https://www.django-rest-framework.org"&gt;Django REST Framework&lt;/a&gt; (DRF), so the natural place to check was the DRF docs. The &lt;a href="https://www.django-rest-framework.org/api-guide/generic-views/#get_objectself"&gt;generic views documentation page&lt;/a&gt; points to changing &lt;code&gt;lookup_field&lt;/code&gt;, however that does not work because &lt;code&gt;BaseAPIEndpoint.get_object_detail_urlpath&lt;/code&gt; from which &lt;code&gt;PagesAPIEndpoint&lt;/code&gt; is derived uses &lt;code&gt;pk&lt;/code&gt; explicitly. The next logical place was to override the &lt;code&gt;detail_url&lt;/code&gt; method for the model serializer (ref: &lt;a href="https://github.com/wagtail/wagtail/blob/v2.7/wagtail/api/v2/serializers.py#L240"&gt;BaseSerializer&lt;/a&gt; and &lt;a href="https://github.com/wagtail/wagtail/blob/v2.7/wagtail/api/v2/serializers.py#L30"&gt;DetailUrlField&lt;/a&gt;, with no success.&lt;/p&gt;

&lt;p&gt;Digging further into the Wagtail API implementation internals reveals that the API router gets the URL information from each endpoint via &lt;code&gt;get_urlpatterns&lt;/code&gt;  and the &lt;code&gt;BaseAPIEndpoint&lt;/code&gt;  defines them as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# https://github.com/wagtail/wagtail/blob/v2.7/wagtail/api/v2/endpoints.py#L340
&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;'^$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'listing_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'listing'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;'^(?P&amp;lt;pk&amp;gt;\d+)/$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'detail_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'detail'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;'^find/$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'find_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'find'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that in hand, we can then define our own endpoint that can handle both &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;slug&lt;/code&gt; as parameters for  the detail view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# api.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wagtail.api.v2.endpoints&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PagesAPIEndpoint&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wagtail.api.v2.router&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WagtailAPIRouter&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyPagesAPIEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PagesAPIEndpoint&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Our custom Pages API endpoint that allows finding pages by pk or slug
    """&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detail_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'slug'&lt;/span&gt;
            &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;detail_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_urlpatterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""
        This returns a list of URL patterns for the endpoint
        """&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'listing_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'listing'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;int:pk&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'detail_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'detail'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;slug:slug&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'detail_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'detail'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'find/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'find_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'find'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Create the router. “wagtailapi” is the URL namespace
&lt;/span&gt;&lt;span class="n"&gt;api_router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WagtailAPIRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'wagtailapi'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;api_router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pages'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyPagesAPIEndpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the above works, slugs are only unique within a parent in Wagtail. It is, therefore, possible to have multiple pages with the same slug, but in different sections of the site (e.g.&lt;code&gt;our-team&lt;/code&gt; in &lt;code&gt;/about/our-team&lt;/code&gt; and &lt;code&gt;/blog/our-team&lt;/code&gt;). This would lead to a &lt;code&gt;MultipleObjectsReturned&lt;/code&gt; exception. To account for that, you need to do some defensive programming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultipleObjectsReturned&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wagtail.api.v2.endpoints&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PagesAPIEndpoint&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wagtail.api.v2.router&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WagtailAPIRouter&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyPagesAPIEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PagesAPIEndpoint&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Our custom Pages API endpoint that allows finding pages by pk or slug
    """&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detail_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'slug'&lt;/span&gt;
            &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;detail_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;MultipleObjectsReturned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Redirect to the listing view, filtered by the relevant slug
&lt;/span&gt;            &lt;span class="c1"&gt;# The router is registered with the `wagtailapi` namespace,
&lt;/span&gt;            &lt;span class="c1"&gt;# `pages` is our endpoint namespace and `listing` is the listing view url name.
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'wagtailapi:pages:listing'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_field&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_urlpatterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""
        This returns a list of URL patterns for the endpoint
        """&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'listing_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'listing'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;int:pk&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'detail_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'detail'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;slug:slug&amp;gt;/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'detail_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'detail'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'find/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'find_view'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'find'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Create the router. “wagtailapi” is the URL namespace
&lt;/span&gt;&lt;span class="n"&gt;api_router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WagtailAPIRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'wagtailapi'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;api_router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pages'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyPagesAPIEndpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this technique we can provide additional endpoint URL patterns and make the Wagtail API cater for even more project specific requirements.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>wagtail</category>
      <category>api</category>
    </item>
    <item>
      <title>Wagtail + Hacktoberfest = ️</title>
      <dc:creator>Dan Braghiș</dc:creator>
      <pubDate>Wed, 16 Oct 2019 15:03:59 +0000</pubDate>
      <link>https://dev.to/wagtail/wagtail-hacktoberfest-2gg5</link>
      <guid>https://dev.to/wagtail/wagtail-hacktoberfest-2gg5</guid>
      <description>&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/wagtail"&gt;
        wagtail
      &lt;/a&gt; / &lt;a href="https://github.com/wagtail/wagtail"&gt;
        wagtail
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Django content management system focused on flexibility and user experience
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
    &lt;a rel="noopener noreferrer" href="https://github.com/wagtail/wagtail.github/wagtail.svg#gh-light-mode-only"&gt;&lt;img width="343" src="https://res.cloudinary.com/practicaldev/image/fetch/s--cWimp_ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/wagtail/wagtail.github/wagtail.svg%23gh-light-mode-only" alt="Wagtail"&gt;&lt;/a&gt;
    &lt;a rel="noopener noreferrer" href="https://github.com/wagtail/wagtail.github/wagtail-inverse.svg#gh-dark-mode-only"&gt;&lt;img width="343" src="https://res.cloudinary.com/practicaldev/image/fetch/s--gCGtgQQJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/wagtail/wagtail.github/wagtail-inverse.svg%23gh-dark-mode-only" alt="Wagtail"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;
    &lt;br&gt;
    &lt;a href="https://github.com/wagtail/wagtail/actions"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_6vKzYK4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/wagtail/wagtail/workflows/Wagtail%2520CI/badge.svg" alt="Build Status"&gt;
    &lt;/a&gt;
    &lt;a href="https://opensource.org/licenses/BSD-3-Clause" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/44c92aa855b3a4b0b5c6f84818afb96ab66b53a102115f5167a396a3f0ff8f3a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4253442d626c75652e737667" alt="License"&gt;
    &lt;/a&gt;
    &lt;a href="https://pypi.python.org/pypi/wagtail/" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/617e12a091e776f960fa1ea62d1316a1b53b1e83e0e25af3ceca5d1f47222e71/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f7761677461696c2e737667" alt="Version"&gt;
    &lt;/a&gt;
    &lt;a href="https://lgtm.com/projects/g/wagtail/wagtail/alerts/" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/17b529d73de8e08769ef36975511ed2cdb8c7d5cf18807646a610f6956403428/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f616c657274732f672f7761677461696c2f7761677461696c2e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Total alerts"&gt;
    &lt;/a&gt;
    &lt;a href="https://lgtm.com/projects/g/wagtail/wagtail/context:python" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/e12b526565a0dbf892faab1ed1386281871161dbd6ffceea83bdb7afc39c45f1/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f67726164652f707974686f6e2f672f7761677461696c2f7761677461696c2e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Language grade: Python"&gt;
    &lt;/a&gt;
    &lt;a href="https://lgtm.com/projects/g/wagtail/wagtail/context:javascript" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/fed5b4422fb10693a46fcecaeb0529d99d7c3b71ee19d8044fd552128363cc9c/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f67726164652f6a6176617363726970742f672f7761677461696c2f7761677461696c2e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Language grade: JavaScript"&gt;
    &lt;/a&gt;
    &lt;a href="https://pypi.python.org/pypi/wagtail/" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/5c59c8f6914b1f7da2ec34febdc60e827232cae63e987b93f1c396a020fef205/68747470733a2f2f696d672e736869656c64732e696f2f707970692f646d2f7761677461696c3f6c6f676f3d446f776e6c6f616473" alt="Monthly downloads"&gt;
    &lt;/a&gt;
    &lt;a href="https://twitter.com/WagtailCMS" rel="nofollow"&gt;
        &lt;img src="https://camo.githubusercontent.com/6dbfbb0f1af0a5b4ae9cec04ab328288c8984df9fd159ccba8d1ee0f40e84bc3/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f5761677461696c434d533f7374796c653d736f6369616c266c6f676f3d74776974746572" alt="follow on Twitter"&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Wagtail is an open source content management system built on Django, with a strong community and commercial support. It's focused on user experience, and offers precise control for designers and developers.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/47ac64c7965fa100c59991b794a85e6eacd1cc157dd41668149dbd3c282a9dee/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7761677461696c2f7761677461696c406d61696e2f2e6769746875622f7761677461696c2d73637265656e73686f742d776974682d62726f777365722e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/47ac64c7965fa100c59991b794a85e6eacd1cc157dd41668149dbd3c282a9dee/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7761677461696c2f7761677461696c406d61696e2f2e6769746875622f7761677461696c2d73637265656e73686f742d776974682d62726f777365722e706e67" alt="Wagtail screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
🔥 Features&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A fast, attractive interface for authors&lt;/li&gt;
&lt;li&gt;Complete control over front-end design and structure&lt;/li&gt;
&lt;li&gt;Scales to millions of pages and thousands of editors&lt;/li&gt;
&lt;li&gt;Fast out of the box, cache-friendly when you need it&lt;/li&gt;
&lt;li&gt;Content API for 'headless' sites with de-coupled front-end&lt;/li&gt;
&lt;li&gt;Runs on a Raspberry Pi or a multi-datacenter cloud platform&lt;/li&gt;
&lt;li&gt;StreamField encourages flexible content without compromising structure&lt;/li&gt;
&lt;li&gt;Powerful, integrated search, using Elasticsearch or PostgreSQL&lt;/li&gt;
&lt;li&gt;Excellent support for images and embedded content&lt;/li&gt;
&lt;li&gt;Multi-site and multi-language ready&lt;/li&gt;
&lt;li&gt;Embraces and extends Django&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Find out more at &lt;a href="https://wagtail.org/" rel="nofollow"&gt;wagtail.org&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
👉 Getting started&lt;/h3&gt;

&lt;p&gt;Wagtail works with &lt;a href="https://www.python.org/downloads/" rel="nofollow"&gt;Python 3&lt;/a&gt;, on any platform.&lt;/p&gt;

&lt;p&gt;To get started with using Wagtail, run the following in a virtual environment:&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/wagtail/wagtail.github/install-animation.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xhZmRdTj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://github.com/wagtail/wagtail.github/install-animation.gif" alt="Installing Wagtail"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install wagtail
wagtail start mysite
&lt;span class="pl-c1"&gt;cd&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/wagtail/wagtail"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;This year is our third #hacktoberfest. We have had a great number of contributions this Hacktober. Thank you to everyone who contributed so far!&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I help? 👩‍💻👨‍💻
&lt;/h2&gt;

&lt;p&gt;Head over to the &lt;a href="https://github.com/wagtail/wagtail/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest"&gt;#Hacktoberfest&lt;/a&gt; issues list on GitHub and pick any that is not being worked on.&lt;/p&gt;

&lt;p&gt;Any and all contributions are welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  I don't know where to start 🤷‍♂️
&lt;/h2&gt;

&lt;p&gt;To get started with Wagtail, see our &lt;a href="https://docs.wagtail.io/en/stable/"&gt;docs&lt;/a&gt;, the &lt;a href="https://docs.wagtail.io/en/stable/contributing/developing.html"&gt;Development&lt;/a&gt; section in particular. Try the &lt;a href="https://github.com/wagtail/bakerydemo/"&gt;Wagtail demo project&lt;/a&gt; or learn Wagtail at &lt;a href="https://learnwagtail.com"&gt;https://learnwagtail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
