Initial commit
parent
1d7ea8cafc
commit
a2e52d453c
@ -0,0 +1,5 @@
|
|||||||
|
pytest
|
||||||
|
pytest-cov
|
||||||
|
flake8
|
||||||
|
black
|
||||||
|
wagtail
|
@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# This file is autogenerated by pip-compile
|
||||||
|
# To update, run:
|
||||||
|
#
|
||||||
|
# pip-compile --output-file dev_requirements.txt dev_requirements.in
|
||||||
|
#
|
||||||
|
--trusted-host pypi.python.org
|
||||||
|
|
||||||
|
appdirs==1.4.3 # via black
|
||||||
|
atomicwrites==1.2.1 # via pytest
|
||||||
|
attrs==18.2.0 # via black, pytest
|
||||||
|
beautifulsoup4==4.6.0 # via wagtail
|
||||||
|
black==18.9b0
|
||||||
|
certifi==2018.10.15 # via requests
|
||||||
|
chardet==3.0.4 # via requests
|
||||||
|
click==7.0 # via black
|
||||||
|
coverage==4.5.1 # via pytest-cov
|
||||||
|
django-modelcluster==4.2 # via wagtail
|
||||||
|
django-taggit==0.23.0 # via wagtail
|
||||||
|
django-treebeard==4.3 # via wagtail
|
||||||
|
django==2.1.2 # via django-taggit, django-treebeard, wagtail
|
||||||
|
djangorestframework==3.9.0 # via wagtail
|
||||||
|
draftjs-exporter==2.1.3 # via wagtail
|
||||||
|
flake8==3.6.0
|
||||||
|
html5lib==1.0.1 # via wagtail
|
||||||
|
idna==2.7 # via requests
|
||||||
|
mccabe==0.6.1 # via flake8
|
||||||
|
more-itertools==4.3.0 # via pytest
|
||||||
|
pillow==5.3.0 # via wagtail
|
||||||
|
pluggy==0.8.0 # via pytest
|
||||||
|
py==1.7.0 # via pytest
|
||||||
|
pycodestyle==2.4.0 # via flake8
|
||||||
|
pyflakes==2.0.0 # via flake8
|
||||||
|
pytest-cov==2.6.0
|
||||||
|
pytest==3.9.3
|
||||||
|
pytz==2018.7 # via django, django-modelcluster, wagtail
|
||||||
|
requests==2.20.0 # via wagtail
|
||||||
|
six==1.11.0 # via html5lib, more-itertools, pytest, wagtail
|
||||||
|
toml==0.10.0 # via black
|
||||||
|
unidecode==1.0.22 # via wagtail
|
||||||
|
urllib3==1.24 # via requests
|
||||||
|
wagtail==2.3
|
||||||
|
webencodings==0.5.1 # via html5lib
|
||||||
|
willow==1.1 # via wagtail
|
@ -0,0 +1,21 @@
|
|||||||
|
FROM python:3.7
|
||||||
|
LABEL maintainer="drew@androiddrew.comw"
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
ENV DJANGO_ENV dev
|
||||||
|
|
||||||
|
COPY ./requirements.txt /code/requirements.txt
|
||||||
|
RUN pip install -r /code/requirements.txt
|
||||||
|
RUN pip install gunicorn
|
||||||
|
|
||||||
|
COPY . /code/
|
||||||
|
WORKDIR /code/
|
||||||
|
|
||||||
|
RUN python manage.py migrate
|
||||||
|
|
||||||
|
RUN useradd wagtail
|
||||||
|
RUN chown -R wagtail /code
|
||||||
|
USER wagtail
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
CMD exec gunicorn cms.wsgi:application --bind 0.0.0.0:8000 --workers 3
|
@ -0,0 +1,149 @@
|
|||||||
|
"""
|
||||||
|
Django settings for cms project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 2.1.2.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/2.1/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/2.1/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
import os
|
||||||
|
|
||||||
|
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
BASE_DIR = os.path.dirname(PROJECT_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
"home",
|
||||||
|
"search",
|
||||||
|
"wagtail.contrib.forms",
|
||||||
|
"wagtail.contrib.redirects",
|
||||||
|
"wagtail.embeds",
|
||||||
|
"wagtail.sites",
|
||||||
|
"wagtail.users",
|
||||||
|
"wagtail.snippets",
|
||||||
|
"wagtail.documents",
|
||||||
|
"wagtail.images",
|
||||||
|
"wagtail.search",
|
||||||
|
"wagtail.admin",
|
||||||
|
"wagtail.core",
|
||||||
|
"modelcluster",
|
||||||
|
"taggit",
|
||||||
|
"django.contrib.admin",
|
||||||
|
"django.contrib.auth",
|
||||||
|
"django.contrib.contenttypes",
|
||||||
|
"django.contrib.sessions",
|
||||||
|
"django.contrib.messages",
|
||||||
|
"django.contrib.staticfiles",
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
"django.middleware.security.SecurityMiddleware",
|
||||||
|
"wagtail.core.middleware.SiteMiddleware",
|
||||||
|
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = "cms.urls"
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
|
"DIRS": [os.path.join(PROJECT_DIR, "templates")],
|
||||||
|
"APP_DIRS": True,
|
||||||
|
"OPTIONS": {
|
||||||
|
"context_processors": [
|
||||||
|
"django.template.context_processors.debug",
|
||||||
|
"django.template.context_processors.request",
|
||||||
|
"django.contrib.auth.context_processors.auth",
|
||||||
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = "cms.wsgi.application"
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
|
||||||
|
|
||||||
|
# DATABASES = {
|
||||||
|
# 'default': {
|
||||||
|
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
|
||||||
|
},
|
||||||
|
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
|
||||||
|
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||||
|
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/2.1/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
|
TIME_ZONE = "UTC"
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/2.1/howto/static-files/
|
||||||
|
|
||||||
|
STATICFILES_FINDERS = [
|
||||||
|
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||||
|
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||||
|
]
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [os.path.join(PROJECT_DIR, "static")]
|
||||||
|
|
||||||
|
# ManifestStaticFilesStorage is recommended in production, to prevent outdated
|
||||||
|
# Javascript / CSS assets being served from cache (e.g. after a Wagtail upgrade).
|
||||||
|
# See https://docs.djangoproject.com/en/2.1/ref/contrib/staticfiles/#manifeststaticfilesstorage
|
||||||
|
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
|
||||||
|
|
||||||
|
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||||
|
MEDIA_URL = "/media/"
|
||||||
|
|
||||||
|
|
||||||
|
# Wagtail settings
|
||||||
|
|
||||||
|
WAGTAIL_SITE_NAME = "datasketch.io"
|
||||||
|
|
||||||
|
# Base URL to use when referring to full URLs within the Wagtail admin backend -
|
||||||
|
# e.g. in notification emails. Don't include '/admin' or a trailing slash
|
||||||
|
BASE_URL = "https://datasketch.io"
|
@ -0,0 +1,28 @@
|
|||||||
|
from .base import *
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = "gi5#h%%co$&cnxt36b8g13o2$$=)!3v+v^iyp)7!^qvrhr)w3+"
|
||||||
|
|
||||||
|
# SECURITY WARNING: define the correct hosts in production!
|
||||||
|
ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": "datasketch",
|
||||||
|
"USER": "datasketch",
|
||||||
|
"PASSWORD": os.environ.get("DB_PASSWD") if os.environ.get("DB_PASSWD") else "",
|
||||||
|
"HOST": os.environ.get("DB_HOST") if os.environ.get("DB_HOST") else "127.0.0.1",
|
||||||
|
"PORT": "5432",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .local import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
@ -0,0 +1,8 @@
|
|||||||
|
from .base import *
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .local import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block body_class %}template-404{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Page not found</h1>
|
||||||
|
|
||||||
|
<h2>Sorry, this page could not be found.</h2>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="no-js">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Internal server error</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Internal server error</h1>
|
||||||
|
|
||||||
|
<h2>Sorry, there seems to be an error. Please try again soon.</h2>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,41 @@
|
|||||||
|
{% load static wagtailuserbar %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="no-js">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>
|
||||||
|
{% block title %}
|
||||||
|
{% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block title_suffix %}
|
||||||
|
{% with self.get_site.site_name as site_name %}
|
||||||
|
{% if site_name %}- {{ site_name }}{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock %}
|
||||||
|
</title>
|
||||||
|
<meta name="description" content="" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
{# Global stylesheets #}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/tachyons.min.css' %}">
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/cms.css' %}">
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{# Override this in templates to add extra stylesheets #}
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="{% block body_class %}{% endblock %}">
|
||||||
|
{% wagtailuserbar %}
|
||||||
|
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
|
||||||
|
{# Global javascript #}
|
||||||
|
<script type="text/javascript" src="{% static 'js/cms.js' %}"></script>
|
||||||
|
|
||||||
|
{% block extra_js %}
|
||||||
|
{# Override this in templates to add extra javascript #}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,32 @@
|
|||||||
|
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"),
|
||||||
|
# For anything not caught by a more specific rule above, hand over to
|
||||||
|
# Wagtail's page serving mechanism. This should be the last pattern in
|
||||||
|
# the list:
|
||||||
|
url(r"", include(wagtail_urls)),
|
||||||
|
# Alternatively, if you want Wagtail pages to be served from a subpath
|
||||||
|
# of your site, rather than the site root:
|
||||||
|
# url(r'^pages/', include(wagtail_urls)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
|
|
||||||
|
# Serve static and media files from development server
|
||||||
|
urlpatterns += staticfiles_urlpatterns()
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for cms project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings.dev")
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("wagtailcore", "0040_page_draft_title")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="HomePage",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"page_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="wagtailcore.Page",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
options={"abstract": False},
|
||||||
|
bases=("wagtailcore.page",),
|
||||||
|
)
|
||||||
|
]
|
@ -0,0 +1,54 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def create_homepage(apps, schema_editor):
|
||||||
|
# Get models
|
||||||
|
ContentType = apps.get_model("contenttypes.ContentType")
|
||||||
|
Page = apps.get_model("wagtailcore.Page")
|
||||||
|
Site = apps.get_model("wagtailcore.Site")
|
||||||
|
HomePage = apps.get_model("home.HomePage")
|
||||||
|
|
||||||
|
# Delete the default homepage
|
||||||
|
# If migration is run multiple times, it may have already been deleted
|
||||||
|
Page.objects.filter(id=2).delete()
|
||||||
|
|
||||||
|
# Create content type for homepage model
|
||||||
|
homepage_content_type, __ = ContentType.objects.get_or_create(
|
||||||
|
model="homepage", app_label="home"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a new homepage
|
||||||
|
homepage = HomePage.objects.create(
|
||||||
|
title="Home",
|
||||||
|
draft_title="Home",
|
||||||
|
slug="home",
|
||||||
|
content_type=homepage_content_type,
|
||||||
|
path="00010001",
|
||||||
|
depth=2,
|
||||||
|
numchild=0,
|
||||||
|
url_path="/home/",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a site with the new homepage set as the root
|
||||||
|
Site.objects.create(hostname="localhost", root_page=homepage, is_default_site=True)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_homepage(apps, schema_editor):
|
||||||
|
# Get models
|
||||||
|
ContentType = apps.get_model("contenttypes.ContentType")
|
||||||
|
HomePage = apps.get_model("home.HomePage")
|
||||||
|
|
||||||
|
# Delete the default homepage
|
||||||
|
# Page and Site objects CASCADE
|
||||||
|
HomePage.objects.filter(slug="home", depth=2).delete()
|
||||||
|
|
||||||
|
# Delete content type for homepage model
|
||||||
|
ContentType.objects.filter(model="homepage", app_label="home").delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("home", "0001_initial")]
|
||||||
|
|
||||||
|
operations = [migrations.RunPython(create_homepage, remove_homepage)]
|
@ -0,0 +1,7 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from wagtail.core.models import Page
|
||||||
|
|
||||||
|
|
||||||
|
class HomePage(Page):
|
||||||
|
pass
|
@ -0,0 +1,7 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block body_class %}helvetica{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Welcome to Datasketch.io!</h1>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings.dev")
|
||||||
|
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
execute_from_command_line(sys.argv)
|
@ -0,0 +1,3 @@
|
|||||||
|
Django>=2.1,<2.2
|
||||||
|
wagtail>=2.3,<2.4
|
||||||
|
psycopg2>=2.7.5
|
@ -0,0 +1,38 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static wagtailcore_tags %}
|
||||||
|
|
||||||
|
{% block body_class %}template-searchresults{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}Search{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Search</h1>
|
||||||
|
|
||||||
|
<form action="{% url 'search' %}" method="get">
|
||||||
|
<input type="text" name="query"{% if search_query %} value="{{ search_query }}"{% endif %}>
|
||||||
|
<input type="submit" value="Search" class="button">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if search_results %}
|
||||||
|
<ul>
|
||||||
|
{% for result in search_results %}
|
||||||
|
<li>
|
||||||
|
<h4><a href="{% pageurl result %}">{{ result }}</a></h4>
|
||||||
|
{% if result.search_description %}
|
||||||
|
{{ result.search_description }}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% if search_results.has_previous %}
|
||||||
|
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.previous_page_number }}">Previous</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if search_results.has_next %}
|
||||||
|
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.next_page_number }}">Next</a>
|
||||||
|
{% endif %}
|
||||||
|
{% elif search_query %}
|
||||||
|
No results found
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,35 @@
|
|||||||
|
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from wagtail.core.models import Page
|
||||||
|
from wagtail.search.models import Query
|
||||||
|
|
||||||
|
|
||||||
|
def search(request):
|
||||||
|
search_query = request.GET.get("query", None)
|
||||||
|
page = request.GET.get("page", 1)
|
||||||
|
|
||||||
|
# Search
|
||||||
|
if search_query:
|
||||||
|
search_results = Page.objects.live().search(search_query)
|
||||||
|
query = Query.get(search_query)
|
||||||
|
|
||||||
|
# Record hit
|
||||||
|
query.add_hit()
|
||||||
|
else:
|
||||||
|
search_results = Page.objects.none()
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
paginator = Paginator(search_results, 10)
|
||||||
|
try:
|
||||||
|
search_results = paginator.page(page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
search_results = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
search_results = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"search/search.html",
|
||||||
|
{"search_query": search_query, "search_results": search_results},
|
||||||
|
)
|
Loading…
Reference in New Issue