fix translation, modernize example settings

release40
eric 2017-06-16 16:17:49 -04:00
parent 48d0a4fbf1
commit b9f99a0f14
8 changed files with 185 additions and 226 deletions

178
README.md
View File

@ -1,8 +1,6 @@
FEF Questionnaire
=====================
# FEF Questionnaire
Introduction
------------
## Introduction
FEF Questionnaire is a Django questionnaire app which is easily customizable
and includes advanced dependency support using boolean expressions.
@ -16,8 +14,7 @@ In either mode, an instance can be linked to an arbitrary object via the django
Try out the questionaire on the Unglue.it page for "Open Access Ebooks" https://unglue.it/work/82028/
History
-------
## History
The questionnaire app was originally developed by [Seantis](https://github.com/seantis), itself derived from [rmt](https://github.com/rmt). Eldest Daughter picked up the project and named it [ED-questionnaire](git://github.com/eldest-daughter/ed-questionnaire) because they had been using it and the Seantis version had entered a steady state of development. There are several feature changes they wanted and decided to head up the maintenance themselves.
@ -30,10 +27,9 @@ The old versions are tagged as follows:
The "ED-questionnaire" version was dubbed v3.0. It is not compatible with the v2.x branches.
The "FEF-questionnaire" was created to add the ability to link the questionnaire to individual books in a book database. We'll call this v4.0
The "FEF-questionnaire" version was created to add the ability to link the questionnaire to individual books in a book database. We'll call this v4.0
About this Manual
-----------------
## About this Manual
FEF Questionnaire is not a very well documented app so far to say the least. This manual should give you a general idea of the layout and concepts of it, but it is not as comprehensive as it should be.
@ -44,8 +40,9 @@ What it does cover is the following:
* **Migration** explains how a questionnaire defined with 1.0 can be used in 2.0.
* **2.0 Postmortem** talks about some experiences made during the development of 2.0.
Integration
-----------
## Integration
### Example Setup
This part of the docs will take you through the steps needed to create a questionnaire app from scratch. It should also be quite handy for the task of integrating the questionnaire into an existing site.
@ -56,7 +53,7 @@ First, create a folder for your new site:
Create a virtual environment so your python packages don't influence your system
virtualenv --no-site-packages -p python2.5 .
virtualenv --no-site-packages -p python2.7 .
Activate your virtual environment
@ -64,7 +61,7 @@ Activate your virtual environment
Install Django
pip install django
pip install django==1.8.18
Create your Django site
@ -80,7 +77,7 @@ Clone the questionnaire source
git clone git://github.com/EbookFoundation/fef-questionnaire.git
You should now have a ed-questionnaire folder in your apps folder
You should now have a fef-questionnaire folder in your apps folder
cd fef-questionnaire
@ -90,7 +87,50 @@ The next step is to install the questionnaire.
If you are working with ed-questionnaire from your own fork you may want to use `python setup.py develop` instead, which will save you from running `python setup.py install` every time the questionnaire changes.
Now let's configure your basic questionnaire.
Now let's configure your basic questionnaire OR copy the settings.py and urls.py files from the "example" folder into `mysite/mysite`, then skip down to [initialize your database](#initialize-the-database).
Also add the locale and request cache middleware to MIDDLEWARE_CLASSES:
'questionnaire.request_cache.RequestCacheMiddleware'
Add the questionnaire template directory as well as your own to TEMPLATES:
'DIRS': [os.path.join(BASE_DIR, 'mysite/templates/')],
If you want to use multiple languages, add the i18n context processor to TEMPLATES
'context_processors': ['django.template.context_processors.i18n',]
And finally, add `transmeta`, `questionnaire` to your INSTALLED_APPS:
'transmeta',
'questionnaire',
'questionnaire.page',
Next up we want to edit the `urls.py` file of your project to link the questionnaire views to your site's url configuration. See the example app to see how.
### Initialize the database
Having done that we can initialize our database. (For this to work you must have setup your DATABASES in `settings.py`.). First, in your CLI navigate back to the `mysite` folder:
cd ../..
The check that you are in the proper folder, type `ls`: if you can see `manage.py` in your list of files, you are good. Otherwise, find your way to the folder that contains that file. Then type:
python manage.py syncdb
You will be asked to create a superuser.
The questionnaire expects a `base-questionnaire.html` template to be there, with certain stylesheets and blocks inside. Have a look at `./apps/fef-questionnaire/example/templates/base-questionnaire.html`. if you're adding the app to an existing project.
mkdir templates
cd templates
cp ../apps/fef-questionnaire/questionnaire/templates/base-questionnaire.html .
Congratulations, you have setup the basics of the questionnaire! At this point this site doesn't really do anything, as there are no questionnaires defined.
### Internationalizating the database
First, you want to setup the languages used in your questionnaire. Open up your `mysite` folder in your favorite text editor.
@ -101,90 +141,30 @@ Open `mysite/mysite/settings.py` and add following lines, representing your lang
('de', 'Deutsch')
)
At the top of `settings.py` you should at this point add:
To run more than one language, set
python manage.py sync_transmeta_db
import os.path
We will use that below for the setup of the folders.
In the same file add the questionnaire static directory to your STATICFILES_DIRS:
STATICFILES_DIRS = (
os.path.abspath('./apps/fef-questionnaire/questionnaire/static/'),
)
Also add the locale and request cache middleware to MIDDLEWARE_CLASSES:
'django.middleware.locale.LocaleMiddleware',
'questionnaire.request_cache.RequestCacheMiddleware',
If you are using Django 1.7 you will need to comment out the following line, like so:
# 'django.middleware.security.SecurityMiddleware',
otherwise you will get an error when trying to start the server.
Add the questionnaire template directory as well as your own to TEMPLATE_DIRS:
os.path.abspath('./apps/fef-questionnaire/questionnaire/templates'),
os.path.abspath('./templates'),
And finally, add `transmeta`, `questionnaire` to your INSTALLED_APPS:
'django.contrib.sites',
'transmeta',
'questionnaire',
'questionnaire.page',
To get the "sites" framework working you also need to add the following setting:
SITE_ID = 1
Next up we want to edit the `urls.py` file of your project to link the questionnaire views to your site's url configuration.
For an empty site with enabled admin interface you add:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
# questionnaire urls
url(r'q/', include('questionnaire.urls')),
)
Having done that we can initialize our database. (For this to work you must have setup your DATABASES in `settings.py`.). First, in your CLI navigate back to the `mysite` folder:
cd ../..
The check that you are in the proper folder, type `ls`: if you can see `manage.py` in your list of files, you are good. Otherwise, find your way to the folder that contains that file. Then type:
python manage.py syncdb
python manage.py migrate
The questionnaire expects a `base.html` template to be there, with certain stylesheets and blocks inside. Have a look at `./apps/fef-questionnaire/example/templates/base.html`.
For now you might want to just copy the `base.html` to your own template folder.
mkdir templates
cd templates
cp ../apps/fef-questionnaire/example/templates/base.html .
Congratulations, you have setup the basics of the questionnaire! At this point this site doesn't really do anything, as there are no questionnaires defined.
If you want to use multiple languages, add the i18n context processor to TEMPLATES
'context_processors': ['django.template.context_processors.i18n',]
and set up middleware as described in the [Django translation docs](https://docs.djangoproject.com/en/1.8/topics/i18n/translation/)
To see an example questionnaire you can do the following (Note: this will only work if you have both English and German defined as Languages in `settings.py`):
python manage.py loaddata ./apps/fef-questionnaire/example/fixtures/initial_data.yaml
You may then start your development server:
### Start the server!
Start your development server:
python manage.py runserver
And navigate to [localhost:8000](http://localhost:8000/).
Concepts
--------
## Concepts
The ED Questionnaire has the following tables, described in detail below.
@ -299,23 +279,7 @@ In Poll mode, the landing url links a Questionnaire to an Object and a User to a
Migration of 1.x to 2.0
-----------------------
2.0 added new fields to the questionnaire, but it did so in a backwards compatible way. None of the new fields are mandatory and no changes should be necessary to your existing questionnaire. Since we do not have any relevant testing data however, you might find yourself on your own if it doesn't work. Please file an issue if you think we did something wrong, so we can fix it and help you.
As Django per default does not provide a way to migrate database schemas, we pretty much make use of the bulldozer way of migrating, by exporting the data from one database and import it into a newly created one.
From you existing 1.x site do:
python manage.py dumpdata >> export.yaml
Copy your file to your new site and in your new site, create your empty database:
python manage.py syncdb
You may then import your data from your old site, which should probably work :)
python manage.py loaddata export.yaml
This of course covers only the data migration. How to migrate your custom tailored site to use questionnaire 2.0 is unfortunately something we cannot really document.
Version 4.0 does not support migration of 1.X data files.
2.0 Postmortem
--------------
@ -354,7 +318,9 @@ Version 4.0 has not been tested for compatibility with previous versions.
* We've updated to Bootstrap 3.3.6 and implemented label tags for accessibility
* "landings" have been added so that survey responses can be linked to arbitrary models in an application. template tags have been added that allow questions and answers to refer to those models.
* question types have been added so that choices can be offered without making the question required.
* styling of required questions has been spiffed up
* styling of required questions has been spiffed up.
* export of response data has been fixed.
* compatibility with Django 1.8. Compatibility with other versions of Django has not been tested.

View File

@ -1,129 +1,118 @@
# Django settings for example project.
import os.path
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 1.8.18.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '3b@kp9-x$dxp@)aqct^$vf^*n95^@k%jd)&kx_%*(kj#0s+sty'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'example.sqlite', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Europe/Berlin'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '/media/'
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/static/admin/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = 'j69g6-&t0l43f06iq=+u!ni)9n)g!ygy4dk-dgdbrbdx7%9l*6'
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = os.path.abspath('./static_root')
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
os.path.abspath('./static'),
os.path.abspath('../questionnaire/static/')
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
ALLOWED_HOSTS = []
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.locale.LocaleMiddleware',
'questionnaire.request_cache.RequestCacheMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'example.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.abspath("../questionnaire/templates/"),
os.path.abspath("./templates/"),
)
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.staticfiles',
'transmeta',
'questionnaire',
'questionnaire.page',
)
LANGUAGES = (
('en', 'English'),
('de', 'Deutsch'),
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'questionnaire.request_cache.RequestCacheMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'mysite/templates/')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
# sets the available languages in the questionnaire
LANGUAGES = (
('en', 'English'),
('de', 'Deutsch')
)
# Defines the progressbar behavior in the questionnaire
# the possible options are 'default', 'async' and 'none'
#
@ -152,5 +141,4 @@ QUESTIONNAIRE_PROGRESS = 'async'
# user goes through the steps of the question set.
QUESTIONNAIRE_USE_SESSION = False
try: from local_settings import *
except: pass

View File

@ -13,7 +13,7 @@ def page(request, page_to_render):
return render(request, "pages/{}.html".format(page_to_render),
{ "request" : request,},
)
print request.session[translation.LANGUAGE_SESSION_KEY]
return render(request, "page.html",
{ "request" : request, "page" : p, },
)
@ -33,7 +33,7 @@ def set_language(request):
lang_code = request.GET.get('language', None)
if lang_code and translation.check_for_language(lang_code):
if hasattr(request, 'session'):
request.session['django_language'] = lang_code
request.session[translation.LANGUAGE_SESSION_KEY] = lang_code
else:
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
return response

View File

@ -1,11 +1,11 @@
{% extends "base-questionnaire.html" %}
{% load i18n %}
{% block title %}
{{ block.super }} - {{ page.title }}
{% endblock %}
{% block questionnaire %}
{{ page.body }}
{{ page.body|safe }}
{% if user.is_authenticated %}
<a href="/admin/page/page/{{ page.slug }}/">(edit)</a>
{% endif %}

View File

@ -32,9 +32,11 @@
<label for="{{ question.number }}extra"><span class="extra-block">{{ question.extra }}</span></label>
</li>
{% else %}
{% if qdict.extras %}
<li>
<label for="{{ question.number }}extra">{% trans "Other..." %}</label>
</li>
{% endif %}
{% endif %}
{% if qdict.extras %}
{% for key, value in qdict.extras %}

View File

@ -5,7 +5,8 @@ register = django.template.Library()
@register.simple_tag(takes_context=True)
def render_with_landing(context, text):
if not context.has_key('landing_object') and context.has_key('runinfo'):
context['landing_object'] = context['runinfo'].landing.content_object
landing = context['runinfo'].landing
context['landing_object'] = landing.content_object if landing else ''
if text:
template = Template(text)
return template.render(context)

View File

@ -347,6 +347,8 @@ def questionnaire(request, runcode=None, qs=None):
We only commit on success, to maintain consistency. We also specifically
rollback if there were errors processing the answers for this questionset.
"""
print translation.get_language()
if use_session:
session_runcode = request.session.get('runcode', None)
if session_runcode is not None:
@ -390,7 +392,7 @@ def questionnaire(request, runcode=None, qs=None):
# Only change the language to the subjects choice for the initial
# questionnaire page (may be a direct link from an email)
if hasattr(request, 'session'):
request.session['django_language'] = runinfo.subject.language
request.session[translation.LANGUAGE_SESSION_KEY] = runinfo.subject.language
translation.activate(runinfo.subject.language)
if 'lang' in request.GET:
@ -514,7 +516,7 @@ def questionnaire(request, runcode=None, qs=None):
if next is None: # we are finished
return finish_questionnaire(request, runinfo, questionnaire)
commit()
return redirect_to_qs(runinfo, request)
@ -796,7 +798,7 @@ def set_language(request, runinfo=None, next=None):
lang_code = request.GET.get('lang', None)
if lang_code and translation.check_for_language(lang_code):
if hasattr(request, 'session'):
request.session['django_language'] = lang_code
request.session[translation.LANGUAGE_SESSION_KEY] = lang_code
else:
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
if runinfo:

View File

@ -10,8 +10,8 @@ setup(
version="4.0.0",
description="A Django application for creating online questionnaires/surveys.",
long_description=read("README.md"),
author="Eldest Daughter, LLC.","Free Ebook Foundation"
author_email="gcaprio@eldestdaughter.com", "eric@hellman.net"
author="Eldest Daughter, LLC., Free Ebook Foundation",
author_email="gcaprio@eldestdaughter.com, eric@hellman.net",
license="BSD",
url="https://github.com/EbookFoundation/fef-questionnaire",
packages=find_packages(exclude=["example"]),