├── faq ├── views │ ├── __init__.py │ ├── deep.py │ ├── normal.py │ └── shallow.py ├── templates │ ├── search │ │ └── indexes │ │ │ └── faq │ │ │ ├── question_text.txt │ │ │ └── topic_text.txt │ └── faq │ │ ├── base.html │ │ ├── question_detail.html │ │ ├── topic_detail.html │ │ └── topic_list.html ├── locale │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── es │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── urls │ ├── __init__.py │ ├── shallow.py │ ├── normal.py │ └── deep.py ├── __init__.py ├── search_indexes.py ├── settings.py ├── forms.py ├── admin.py ├── tests.py ├── models.py └── fixtures │ └── test_data.json ├── pip ├── requirements.txt ├── optional-haystack.txt └── optional-whoosh.txt ├── .gitignore ├── docs ├── getting_started.rst ├── index.rst ├── Makefile ├── make.bat └── conf.py ├── MANIFEST.in ├── INSTALL ├── setup.py ├── LICENSE └── README.rst /faq/views/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pip/requirements.txt: -------------------------------------------------------------------------------- 1 | Django>=1.2 2 | -------------------------------------------------------------------------------- /pip/optional-haystack.txt: -------------------------------------------------------------------------------- 1 | django-haystack<2 2 | django-haystack>=1 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .DS_Store 3 | build/ 4 | dist/ 5 | docs/_build 6 | MANIFEST 7 | -------------------------------------------------------------------------------- /pip/optional-whoosh.txt: -------------------------------------------------------------------------------- 1 | # If you want to get Haystack running fast, use Whoosh. 2 | Whoosh<=1.2 3 | -------------------------------------------------------------------------------- /faq/templates/search/indexes/faq/question_text.txt: -------------------------------------------------------------------------------- 1 | {{ object.question }} 2 | 3 | {{ object.answer }} 4 | -------------------------------------------------------------------------------- /faq/templates/search/indexes/faq/topic_text.txt: -------------------------------------------------------------------------------- 1 | {{ object.title }} 2 | 3 | {{ object.description }} 4 | -------------------------------------------------------------------------------- /docs/getting_started.rst: -------------------------------------------------------------------------------- 1 | .. _getting_started: 2 | 3 | Getting Started 4 | =============== 5 | 6 | Overview 7 | -------- 8 | -------------------------------------------------------------------------------- /faq/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/django-faq/master/faq/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /faq/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/django-faq/master/faq/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /faq/urls/__init__.py: -------------------------------------------------------------------------------- 1 | from faq.urls.normal import * 2 | # This serves as both backwords-compatability and a shortcut to the default. 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | include MANIFEST.in 4 | recursive-include docs * 5 | recursive-include faq/locale * 6 | recursive-include faq/templates * -------------------------------------------------------------------------------- /faq/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A Frequently Asked Question (FAQ) management application for Django apps. 3 | 4 | """ 5 | 6 | from django.utils.translation import ugettext_lazy as _ 7 | 8 | 9 | VERSION = '0.8.2' 10 | 11 | # Mark the app_label for translation. 12 | _(u'faq') 13 | -------------------------------------------------------------------------------- /faq/templates/faq/base.html: -------------------------------------------------------------------------------- 1 | 2 | {% load i18n %} 3 | {% get_current_language as language %} 4 | 5 | 6 | 7 | {% block title %}{% endblock %} 8 | 9 |

{% block header %}{% endblock %}

10 | 11 | {% block content %} 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. _index: 2 | .. module:: faq 3 | 4 | Django FAQ 5 | ========== 6 | 7 | Overview 8 | -------- 9 | 10 | ``django-faq`` is 11 | 12 | 13 | 14 | Contents 15 | -------- 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | getting_started 21 | 22 | 23 | Indices and tables 24 | ------------------ 25 | 26 | * :ref:`genindex` 27 | * :ref:`modindex` 28 | * :ref:`search` 29 | 30 | -------------------------------------------------------------------------------- /faq/urls/shallow.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | from faq.views.shallow import topic_list, topic_detail, question_detail 4 | 5 | 6 | # Include these patterns if you want URLs like: 7 | # 8 | # /faq/ 9 | # /faq/#topic 10 | # /faq/#question 11 | # 12 | 13 | urlpatterns = patterns('', 14 | url(r'^$', topic_list, name='faq-topic-list'), 15 | url(r'^(?P[-\w]+)/$', topic_detail, name='faq-topic-detail'), 16 | url(r'^(?P[-\w]+)/(?P[-\w]+)/$', question_detail, 17 | name='faq-question-detail'), 18 | ) 19 | -------------------------------------------------------------------------------- /faq/urls/normal.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | from faq.views.shallow import topic_list 4 | from faq.views.normal import topic_detail, question_detail 5 | 6 | 7 | # Include these patterns if you want URLs like: 8 | # 9 | # /faq/ 10 | # /faq/topic/ 11 | # /faq/topic/#question 12 | # 13 | 14 | urlpatterns = patterns('', 15 | url(r'^$', topic_list, name='faq-topic-list'), 16 | url(r'^(?P[-\w]+)/$', topic_detail, name='faq-topic-detail'), 17 | url(r'^(?P[-\w]+)/(?P[-\w]+)/$', question_detail, 18 | name='faq-question-detail'), 19 | ) 20 | -------------------------------------------------------------------------------- /faq/templates/faq/question_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "faq/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | 6 | {# This template will only be used if the ``faq.urls.deep`` patterns are used. #} 7 | 8 | {% block title %}{% blocktrans with question.question as question %}FAQ: {{ question }}{% endblocktrans %}{% endblock %} 9 | 10 | 11 | {% block header %} 12 | {% trans "FAQ" %} › 13 | {{ topic }} › 14 | {{ question }} 15 | {% endblock %} 16 | 17 | 18 | {% block content %} 19 | {{ question.answer|linebreaks|urlize }} 20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /faq/urls/deep.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | from faq.views.shallow import topic_list 4 | from faq.views.normal import topic_detail 5 | from faq.views.deep import question_detail 6 | 7 | 8 | # Include these patterns if you want URLs like: 9 | # 10 | # /faq/ 11 | # /faq/topic/ 12 | # /faq/topic/question/ 13 | # 14 | 15 | urlpatterns = patterns('', 16 | url(r'^$', topic_list, name='faq-topic-list'), 17 | url(r'^(?P[-\w]+)/$', topic_detail, name='faq-topic-detail'), 18 | url(r'^(?P[-\w]+)/(?P[-\w]+)/$', question_detail, 19 | name='faq-question-detail'), 20 | ) 21 | -------------------------------------------------------------------------------- /faq/search_indexes.py: -------------------------------------------------------------------------------- 1 | from haystack import indexes 2 | from haystack.sites import site 3 | 4 | from faq.settings import SEARCH_INDEX 5 | from faq.models import Topic, Question 6 | 7 | 8 | class FAQIndexBase(SEARCH_INDEX): 9 | 10 | text = indexes.CharField(document=True, use_template=True) 11 | url = indexes.CharField(model_attr='get_absolute_url', indexed=False) 12 | 13 | 14 | class TopicIndex(FAQIndexBase): 15 | 16 | def get_queryset(self): 17 | return Topic.objects.published() 18 | 19 | 20 | class QuestionIndex(FAQIndexBase): 21 | 22 | def get_queryset(self): 23 | return Question.objects.published() 24 | 25 | 26 | site.register(Topic, TopicIndex) 27 | site.register(Question, QuestionIndex) 28 | -------------------------------------------------------------------------------- /faq/views/deep.py: -------------------------------------------------------------------------------- 1 | from django.views.generic.list_detail import object_detail 2 | 3 | from faq.models import Topic, Question 4 | 5 | 6 | def question_detail(request, topic_slug, slug): 7 | """ 8 | A detail view of a Question. 9 | 10 | Templates: 11 | :template:`faq/question_detail.html` 12 | Context: 13 | question 14 | A :model:`faq.Question`. 15 | topic 16 | The :model:`faq.Topic` object related to ``question``. 17 | 18 | """ 19 | extra_context = { 20 | 'topic': Topic.objects.published().get(slug=topic_slug), 21 | } 22 | 23 | return object_detail(request, queryset=Question.objects.published(), 24 | extra_context=extra_context, template_object_name='question', 25 | slug=slug) 26 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Thanks for downloading django-faq. 2 | 3 | To install it, run the following command inside this directory:: 4 | 5 | python setup.py install 6 | 7 | If you have the Python ``pip`` utility available, you can 8 | also type the following to download and install in one step:: 9 | 10 | pip install django-faq 11 | 12 | Or if you're still using ``easy_install``:: 13 | 14 | easy_install django-faq 15 | 16 | Or if you’d prefer you can simply place the included ``faq`` 17 | directory somewhere on your Python path, or symlink to it from 18 | somewhere on your Python path; this is useful if you’re working from a 19 | Git checkout. 20 | 21 | Note that this application requires Python 2.4 or newer, and a 22 | functional installation of Django 1.2 or newer. You can obtain Python 23 | from http://www.python.org/ and Django from 24 | https://www.djangoproject.com/. 25 | -------------------------------------------------------------------------------- /faq/settings.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | 5 | # Status settings. 6 | # It's unlikely that you should need to change these. But if 7 | # you do, here you go. 8 | 9 | DRAFTED = getattr(settings, 'FAQ_DRAFTED', 1) 10 | PUBLISHED = getattr(settings, 'FAQ_PUBLISHED', 2) 11 | REMOVED = getattr(settings, 'FAQ_REMOVED', 3) 12 | 13 | STATUS_CHOICES = ( 14 | (DRAFTED, _(u'drafted')), 15 | (PUBLISHED, _(u'published')), 16 | (REMOVED, _(u'removed')), 17 | ) 18 | STATUS_CHOICES = getattr(settings, 'FAQ_STATUS_CHOICES', STATUS_CHOICES) 19 | 20 | 21 | # Haystack settings. 22 | # The default search index used for the app is the default haystack index. 23 | # But possibly you want to use haystack.indexes.RealTimeSearchIndex, or another 24 | # of your own making. Go ahead. 25 | try: 26 | from haystack.indexes import SearchIndex 27 | SEARCH_INDEX = getattr(settings, 'FAQ_SEARCH_INDEX', SearchIndex) 28 | except ImportError: 29 | SEARCH_INDEX = None 30 | -------------------------------------------------------------------------------- /faq/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from faq.models import Question 4 | 5 | 6 | class QuestionForm(forms.ModelForm): 7 | """A form whose only purpose is to manage fields for the QuestionInline.""" 8 | 9 | class Meta: 10 | # InlineModelAdmin does not support ``fields``, so if we want to order 11 | # the fields in an InlineModelAdmin, we must do so with a custom 12 | # ModelForm. This is not ideal, but at least it gets the job done. 13 | # 14 | # Note that ``slug`` is left out of the fields list. This is because 15 | # we don't show the slug when adding an Question as an inline to a 16 | # topic because InlineModelAdmin does not support 17 | # ``prepopulated_fields`` either, and it's evil to expect the user 18 | # supply a slug by hand. 19 | # 20 | # If the user really wants to edit the slug, they can do so on the 21 | # Question change page. 22 | fields = ('question', 'answer', 'ordering', 'status') 23 | model = Question 24 | -------------------------------------------------------------------------------- /faq/templates/faq/topic_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "faq/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | 6 | {% comment %} 7 | This template will be used when either ``faq.urls.normal`` (default) or 8 | ``faq.urls.deep`` patterns are used. Note that you will want to code this 9 | differently depending on the patterns. This template is coded for ``normal``. 10 | {% endcomment %} 11 | 12 | {% block title %}{% blocktrans with topic.title as topic %}FAQ: {{ topic }}{% endblocktrans %}{% endblock %} 13 | 14 | 15 | {% block header %} 16 | {% trans "FAQ" %} › {{ topic }} 17 | {% endblock %} 18 | 19 | 20 | {% block content %} 21 |

{{ topic.description }}

22 | 23 |
    24 | {% for question in question_list %} 25 |
  1. 26 |

    {{ question.question }} 27 |

    28 | {{ question.answer|linebreaks|urlize }} 29 |
  2. 30 | {% comment %} For ``deep`` you may do something like the following. 31 |
  3. {{ question.question }}
  4. 32 | {% endcomment %} 33 | {% endfor %} 34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from distutils.core import setup 3 | from faq import VERSION 4 | 5 | def read(fname): 6 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 7 | 8 | setup( 9 | name='django-faq', 10 | version=VERSION, 11 | description='Frequently Asked Question (FAQ) management for Django apps.', 12 | url='https://github.com/benspaulding/django-faq/', 13 | author='Ben Spaulding', 14 | author_email='ben@benspaulding.us', 15 | license='BSD', 16 | download_url='http://github.com/benspaulding/django-faq/tarball/v%s' % VERSION, 17 | long_description = read('README.rst'), 18 | packages = ['faq', 'faq.urls', 'faq.views'], 19 | package_data = {'faq': ['locale/*/LC_MESSAGES/*', 20 | 'templates/faq/*', 21 | 'templates/search/indexes/faq/*']}, 22 | classifiers=['Development Status :: 4 - Beta', 23 | 'Environment :: Web Environment', 24 | 'Framework :: Django', 25 | 'Intended Audience :: Developers', 26 | 'License :: OSI Approved :: BSD License', 27 | 'Operating System :: OS Independent', 28 | 'Programming Language :: Python', 29 | 'Topic :: Internet :: WWW/HTTP :: Site Management'], 30 | ) 31 | -------------------------------------------------------------------------------- /faq/templates/faq/topic_list.html: -------------------------------------------------------------------------------- 1 | {% extends "faq/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | 6 | {% comment %} 7 | This template will be used regardless of what ``faq.urls`` patterns are used. 8 | But note that you will want to code this differently depending on the 9 | patterns used. This template is coded for either ``normal`` or ``deep``. 10 | {% endcomment %} 11 | 12 | {% block title %}{% trans "Frequently Asked Questions" %}{% endblock %} 13 | {% block header %}{% trans "Frequently Asked Questions" %}{% endblock %} 14 | 15 | 16 | {% block content %} 17 |
    18 | {% for topic in topic_list %} 19 |
  1. {{ topic.title }}
  2. 20 | {% comment %} For ``faq.urls.shallow`` you may do something like the following. 21 |
  3. 22 |

    {{ topic.title }}

    23 |
      24 | {% for question in topic.questions.published %} 25 |
    1. 26 |

      {{ question.question }} 27 |

      28 | {{ question.answer|linebreaks|urlize }} 29 |
    2. 30 | {% endfor %} 31 |
    32 |
  4. 33 | {% endcomment %} 34 | {% endfor %} 35 |
36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /faq/views/normal.py: -------------------------------------------------------------------------------- 1 | from django.core.urlresolvers import reverse 2 | from django.shortcuts import get_object_or_404, redirect 3 | from django.views.generic.list_detail import object_detail 4 | 5 | from faq.models import Topic, Question 6 | from faq.views.shallow import _fragmentify 7 | 8 | 9 | def topic_detail(request, slug): 10 | """ 11 | A detail view of a Topic 12 | 13 | Templates: 14 | :template:`faq/topic_detail.html` 15 | Context: 16 | topic 17 | An :model:`faq.Topic` object. 18 | question_list 19 | A list of all published :model:`faq.Question` objects that relate 20 | to the given :model:`faq.Topic`. 21 | 22 | """ 23 | extra_context = { 24 | 'question_list': Question.objects.published().filter(topic__slug=slug), 25 | } 26 | 27 | return object_detail(request, queryset=Topic.objects.published(), 28 | extra_context=extra_context, template_object_name='topic', slug=slug) 29 | 30 | 31 | def question_detail(request, topic_slug, slug): 32 | """ 33 | A detail view of a Question. 34 | 35 | Simply redirects to a detail page for the related :model:`faq.Topic` 36 | (:view:`faq.views.topic_detail`) with the addition of a fragment 37 | identifier that links to the given :model:`faq.Question`. 38 | E.g. ``/faq/topic-slug/#question-slug``. 39 | 40 | """ 41 | url = reverse('faq-topic-detail', kwargs={'slug': topic_slug}) 42 | return _fragmentify(Question, slug, url) 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Ben Spaulding 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following 12 | disclaimer in the documentation and/or other materials provided 13 | with the distribution. 14 | * Neither the name of the author nor the names of other 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /faq/views/shallow.py: -------------------------------------------------------------------------------- 1 | from django.core.urlresolvers import reverse 2 | from django.shortcuts import get_object_or_404, redirect 3 | from django.views.generic.list_detail import object_list 4 | 5 | from faq.models import Topic, Question 6 | 7 | 8 | def _fragmentify(model, slug, url=None): 9 | get_object_or_404(model.objects.published().filter(slug=slug)) 10 | url = url or reverse('faq-topic-list') 11 | fragment = '#%s' % slug 12 | 13 | return redirect(url + fragment, permanent=True) 14 | 15 | 16 | def topic_list(request): 17 | """ 18 | A list view of all published Topics 19 | 20 | Templates: 21 | :template:`faq/topic_list.html` 22 | Context: 23 | topic_list 24 | A list of all published :model:`faq.Topic` objects that 25 | relate to the current :model:`sites.Site`. 26 | 27 | """ 28 | return object_list(request, queryset=Topic.objects.published(), 29 | template_object_name='topic') 30 | 31 | 32 | def topic_detail(request, slug): 33 | """ 34 | A detail view of a Topic 35 | 36 | Simply redirects to :view:`faq.views.topic_list` with the addition of 37 | a fragment identifier that links to the given :model:`faq.Topic`. 38 | E.g., ``/faq/#topic-slug``. 39 | 40 | """ 41 | return _fragmentify(Topic, slug) 42 | 43 | 44 | def question_detail(request, topic_slug, slug): 45 | """ 46 | A detail view of a Question. 47 | 48 | Simply redirects to :view:`faq.views.topic_list` with the addition of 49 | a fragment identifier that links to the given :model:`faq.Question`. 50 | E.g. ``/faq/#question-slug``. 51 | 52 | """ 53 | return _fragmentify(Question, slug) 54 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============================================================ 2 | Frequently Asked Question (FAQ) management for Django apps 3 | ============================================================ 4 | 5 | This Django_ application provides the ability to create and manage lists of 6 | Frequently Asked Questions (FAQ), organized by topic. 7 | 8 | This project is still under development, though several medium-to-large 9 | websites are currently using it in production. The plan is to get a stable 10 | version with a full test suite and documentation out the door in the coming 11 | months. 12 | 13 | .. _Django: http://www.djangoproject.com/ 14 | 15 | TODO’s 16 | ------ 17 | 18 | Below are tasks that need done, features under consideration, and some 19 | reminders for the future. 20 | 21 | * Finish writing tests. 22 | * Write general documentation, and specifically, 23 | 24 | * The change of modified date field behavior. (Dropped null=True, now 25 | has a date upon creation.) Write migration if necessary. 26 | * Document removal of custom template name field on Topic. (The feature made 27 | little sense given the various URL/view setups.) Write migration if 28 | necessary. 29 | 30 | * Finalize Django, Haystack, and Whoosh versions in pip requirements/optionals files. 31 | * Bump the version number. 32 | * Roll a release 33 | 34 | * Create git tag 35 | * Get on Read the Docs 36 | * Upload to PyPi 37 | 38 | 39 | Features 40 | ~~~~~~~~ 41 | 42 | * Create a better interface for ordering questions within a topic. 43 | * Consider if/how to add ordering to Topics. (This is complicated because of 44 | site relations.) 45 | 46 | 47 | In the future, when dropping Django 1.2 support 48 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 | 50 | * Update to class-based generic views 51 | * Move from Question.save() to model validation? 52 | -------------------------------------------------------------------------------- /faq/locale/es/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # English translation for the django-faq project. 2 | # Copyright (C) 2011, Ben Spaulding. 3 | # This file is distributed under the same license as the django-faq package. 4 | # Ben Spaulding , 2011. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: django-faq\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-02-01 22:37-0600\n" 11 | "PO-Revision-Date: 2010-01-31 04:35-0600\n" 12 | "Last-Translator: FULL NAME \n" 13 | "MIME-Version: 1.0\n" 14 | "Content-Type: text/plain; charset=UTF-8\n" 15 | "Content-Transfer-Encoding: 8bit\n" 16 | 17 | #: __init__.py:10 18 | msgid "faq" 19 | msgstr "" 20 | 21 | #: admin.py:27 22 | #, python-format 23 | msgid "Changed status to '%s'." 24 | msgstr "" 25 | 26 | #: admin.py:40 27 | #, python-format 28 | msgid "%(count)s %(object)s was successfully %(verb)s." 29 | msgid_plural "%(count)s %(object)s were successfully %(verb)s." 30 | msgstr[0] "" 31 | msgstr[1] "" 32 | 33 | #: admin.py:54 34 | #, python-format 35 | msgid "Draft selected %(verbose_name_plural)s" 36 | msgstr "" 37 | 38 | #: admin.py:60 39 | #, python-format 40 | msgid "Publish selected %(verbose_name_plural)s" 41 | msgstr "" 42 | 43 | #: admin.py:66 44 | #, python-format 45 | msgid "Remove selected %(verbose_name_plural)s" 46 | msgstr "" 47 | 48 | #: admin.py:101 49 | msgid "No. of Questions" 50 | msgstr "" 51 | 52 | #: models.py:76 53 | msgid "date created" 54 | msgstr "" 55 | 56 | #: models.py:77 57 | msgid "date modified" 58 | msgstr "" 59 | 60 | #: models.py:79 61 | msgid "status" 62 | msgstr "" 63 | 64 | #: models.py:81 65 | msgid "" 66 | "Only objects with \"published\" status will be displayed " 67 | "publicly." 68 | msgstr "" 69 | 70 | #: models.py:101 71 | msgid "title" 72 | msgstr "" 73 | 74 | #: models.py:102 models.py:130 75 | msgid "slug" 76 | msgstr "" 77 | 78 | #: models.py:102 79 | msgid "Used in the URL for the topic. Must be unique." 80 | msgstr "" 81 | 82 | #: models.py:104 83 | msgid "description" 84 | msgstr "" 85 | 86 | #: models.py:105 87 | msgid "A short description of this topic." 88 | msgstr "" 89 | 90 | #: models.py:106 91 | msgid "sites" 92 | msgstr "" 93 | 94 | #: models.py:108 95 | msgid "template name" 96 | msgstr "" 97 | 98 | #: models.py:109 99 | msgid "" 100 | "Optional template to use for this topic's detail page, e.g., " 101 | "\"faq/topics/special.html\". If not given the standard template " 102 | "will be used." 103 | msgstr "" 104 | 105 | #: models.py:115 models.py:133 106 | msgid "topic" 107 | msgstr "" 108 | 109 | #: models.py:116 110 | msgid "topics" 111 | msgstr "" 112 | 113 | #: models.py:129 models.py:142 114 | msgid "question" 115 | msgstr "" 116 | 117 | #: models.py:130 118 | msgid "Used in the URL for the Question. Must be unique." 119 | msgstr "" 120 | 121 | #: models.py:132 122 | msgid "answer" 123 | msgstr "" 124 | 125 | #: models.py:135 126 | msgid "ordering" 127 | msgstr "" 128 | 129 | #: models.py:136 130 | msgid "" 131 | "An integer used to order the question amongst others related to " 132 | "the same topic. If not given this question will be last in the " 133 | "list." 134 | msgstr "" 135 | 136 | #: models.py:143 137 | msgid "questions" 138 | msgstr "" 139 | 140 | #: settings.py:14 141 | msgid "drafted" 142 | msgstr "" 143 | 144 | #: settings.py:15 145 | msgid "published" 146 | msgstr "" 147 | 148 | #: settings.py:16 149 | msgid "removed" 150 | msgstr "" 151 | 152 | #: templates/faq/question_detail.html:8 153 | #, python-format 154 | msgid "FAQ: %(question)s" 155 | msgstr "" 156 | 157 | #: templates/faq/question_detail.html:12 templates/faq/topic_detail.html:16 158 | msgid "FAQ" 159 | msgstr "" 160 | 161 | #: templates/faq/topic_detail.html:12 162 | #, python-format 163 | msgid "FAQ: %(topic)s" 164 | msgstr "" 165 | 166 | #: templates/faq/topic_list.html:12 templates/faq/topic_list.html.py:13 167 | msgid "Frequently Asked Questions" 168 | msgstr "" 169 | -------------------------------------------------------------------------------- /faq/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # English "translation" for the django-faq project. 2 | # Copyright (C) 2011, Ben Spaulding. 3 | # This file is distributed under the same license as the django-faq package. 4 | # Ben Spaulding , 2011. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: django-faq\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2010-02-01 22:37-0600\n" 11 | "PO-Revision-Date: 2010-01-31 04:35-0600\n" 12 | "Last-Translator: Ben Spaulding \n" 13 | "MIME-Version: 1.0\n" 14 | "Content-Type: text/plain; charset=UTF-8\n" 15 | "Content-Transfer-Encoding: 8bit\n" 16 | 17 | #: __init__.py:10 18 | msgid "faq" 19 | msgstr "FAQ" 20 | 21 | #: admin.py:27 22 | #, python-format 23 | msgid "Changed status to '%s'." 24 | msgstr "" 25 | 26 | #: admin.py:40 27 | #, python-format 28 | msgid "%(count)s %(object)s was successfully %(verb)s." 29 | msgid_plural "%(count)s %(object)s were successfully %(verb)s." 30 | msgstr[0] "" 31 | msgstr[1] "" 32 | 33 | #: admin.py:54 34 | #, python-format 35 | msgid "Draft selected %(verbose_name_plural)s" 36 | msgstr "" 37 | 38 | #: admin.py:60 39 | #, python-format 40 | msgid "Publish selected %(verbose_name_plural)s" 41 | msgstr "" 42 | 43 | #: admin.py:66 44 | #, python-format 45 | msgid "Remove selected %(verbose_name_plural)s" 46 | msgstr "" 47 | 48 | #: admin.py:101 49 | msgid "No. of Questions" 50 | msgstr "" 51 | 52 | #: models.py:76 53 | msgid "date created" 54 | msgstr "" 55 | 56 | #: models.py:77 57 | msgid "date modified" 58 | msgstr "" 59 | 60 | #: models.py:79 61 | msgid "status" 62 | msgstr "" 63 | 64 | #: models.py:81 65 | msgid "" 66 | "Only objects with \"published\" status will be displayed " 67 | "publicly." 68 | msgstr "" 69 | 70 | #: models.py:101 71 | msgid "title" 72 | msgstr "" 73 | 74 | #: models.py:102 models.py:130 75 | msgid "slug" 76 | msgstr "" 77 | 78 | #: models.py:102 79 | msgid "Used in the URL for the topic. Must be unique." 80 | msgstr "" 81 | 82 | #: models.py:104 83 | msgid "description" 84 | msgstr "" 85 | 86 | #: models.py:105 87 | msgid "A short description of this topic." 88 | msgstr "" 89 | 90 | #: models.py:106 91 | msgid "sites" 92 | msgstr "" 93 | 94 | #: models.py:108 95 | msgid "template name" 96 | msgstr "" 97 | 98 | #: models.py:109 99 | msgid "" 100 | "Optional template to use for this topic's detail page, e.g., " 101 | "\"faq/topics/special.html\". If not given the standard template " 102 | "will be used." 103 | msgstr "" 104 | 105 | #: models.py:115 models.py:133 106 | msgid "topic" 107 | msgstr "" 108 | 109 | #: models.py:116 110 | msgid "topics" 111 | msgstr "" 112 | 113 | #: models.py:129 models.py:142 114 | msgid "question" 115 | msgstr "" 116 | 117 | #: models.py:130 118 | msgid "Used in the URL for the Question. Must be unique." 119 | msgstr "" 120 | 121 | #: models.py:132 122 | msgid "answer" 123 | msgstr "" 124 | 125 | #: models.py:135 126 | msgid "ordering" 127 | msgstr "" 128 | 129 | #: models.py:136 130 | msgid "" 131 | "An integer used to order the question amongst others related to " 132 | "the same topic. If not given this question will be last in the " 133 | "list." 134 | msgstr "" 135 | 136 | #: models.py:143 137 | msgid "questions" 138 | msgstr "" 139 | 140 | #: settings.py:14 141 | msgid "drafted" 142 | msgstr "" 143 | 144 | #: settings.py:15 145 | msgid "published" 146 | msgstr "" 147 | 148 | #: settings.py:16 149 | msgid "removed" 150 | msgstr "" 151 | 152 | #: templates/faq/question_detail.html:8 153 | #, python-format 154 | msgid "FAQ: %(question)s" 155 | msgstr "" 156 | 157 | #: templates/faq/question_detail.html:12 templates/faq/topic_detail.html:16 158 | msgid "FAQ" 159 | msgstr "" 160 | 161 | #: templates/faq/topic_detail.html:12 162 | #, python-format 163 | msgid "FAQ: %(topic)s" 164 | msgstr "" 165 | 166 | #: templates/faq/topic_list.html:12 templates/faq/topic_list.html.py:13 167 | msgid "Frequently Asked Questions" 168 | msgstr "" 169 | -------------------------------------------------------------------------------- /faq/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.contrib.sites.models import Site 3 | from django.utils.translation import ugettext_lazy as _ 4 | from django.utils.translation import ugettext_noop, ungettext 5 | 6 | from faq.settings import DRAFTED, PUBLISHED, REMOVED, STATUS_CHOICES 7 | from faq.models import Topic, Question 8 | from faq.forms import QuestionForm 9 | 10 | 11 | # Actions. 12 | 13 | def update_status(modeladmin, request, queryset, status): 14 | """The workhorse function for the admin action functions that follow.""" 15 | # We loop over the objects here rather than use queryset.update() for 16 | # two reasons: 17 | # 18 | # 1. No one should ever be updating zillions of Topics or Questions, so 19 | # performance is not an issue. 20 | # 2. To be tidy, we want to log what the user has done. 21 | # 22 | for obj in queryset: 23 | obj.status = status 24 | obj.save() 25 | # Now log what happened. 26 | # Use ugettext_noop() 'cause this is going straight into the db. 27 | log_message = ugettext_noop(u'Changed status to \'%s\'.' % 28 | obj.get_status_display()) 29 | modeladmin.log_change(request, obj, log_message) 30 | 31 | # Send a message to the user telling them what has happened. 32 | message_dict = { 33 | 'count': queryset.count(), 34 | 'object': modeladmin.model._meta.verbose_name, 35 | 'verb': dict(STATUS_CHOICES)[status], 36 | } 37 | if not message_dict['count'] == 1: 38 | message_dict['object'] = modeladmin.model._meta.verbose_name_plural 39 | user_message = ungettext( 40 | u'%(count)s %(object)s was successfully %(verb)s.', 41 | u'%(count)s %(object)s were successfully %(verb)s.', 42 | message_dict['count']) % message_dict 43 | modeladmin.message_user(request, user_message) 44 | 45 | # Return None to display the change list page again and allow the user 46 | # to reload the page without getting that nasty "Send the form again ..." 47 | # warning from their browser. 48 | return None 49 | 50 | 51 | def draft(modeladmin, request, queryset): 52 | """Admin action for setting status of selected items to 'drafted'.""" 53 | return update_status(modeladmin, request, queryset, DRAFTED) 54 | draft.short_description = _(u'Draft selected %(verbose_name_plural)s') 55 | 56 | 57 | def publish(modeladmin, request, queryset): 58 | """Admin action for setting status of selected items to 'published'.""" 59 | return update_status(modeladmin, request, queryset, PUBLISHED) 60 | publish.short_description = _(u'Publish selected %(verbose_name_plural)s') 61 | 62 | 63 | def remove(modeladmin, request, queryset): 64 | """Admin action for setting status of selected items to 'removed'.""" 65 | return update_status(modeladmin, request, queryset, REMOVED) 66 | remove.short_description = _(u'Remove selected %(verbose_name_plural)s') 67 | 68 | 69 | # Inlines. 70 | 71 | class QuestionInline(admin.TabularInline): 72 | extra = 1 73 | form = QuestionForm 74 | model = Question 75 | 76 | 77 | # Admins. 78 | 79 | class FAQAdminBase(admin.ModelAdmin): 80 | actions = (draft, publish, remove) 81 | actions_on_top = True 82 | actions_on_bottom = True 83 | list_per_page = 50 84 | 85 | 86 | class TopicAdmin(FAQAdminBase): 87 | fieldsets = ( 88 | (None, { 89 | 'fields': ('title', 'slug', 'description', 'status', 'sites')}), 90 | ) 91 | inlines = (QuestionInline, ) 92 | list_display = ('title', 'description', 'status', 'question_count') 93 | list_filter = ('status', 'sites', 'modified', 'created') 94 | prepopulated_fields = {'slug': ('title', )} 95 | search_fields = ('title', 'description') 96 | 97 | def question_count(self, obj): 98 | """Returns the total number of Questions for this topic.""" 99 | return obj.questions.count() 100 | question_count.short_description = _(u'No. of Questions') 101 | 102 | 103 | class QuestionAdmin(FAQAdminBase): 104 | fieldsets = ( 105 | (None, { 106 | 'fields': ('topic', 'question', 'slug', 'answer', 'status', 107 | 'ordering')}), 108 | ) 109 | list_display = ('question', 'topic', 'status', 'ordering') 110 | list_filter = ('status', 'topic', 'modified', 'created') 111 | prepopulated_fields = {'slug': ('question', )} 112 | search_fields = ('question', 'answer') 113 | 114 | 115 | admin.site.register(Topic, TopicAdmin) 116 | admin.site.register(Question, QuestionAdmin) 117 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | 15 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " singlehtml to make a single large HTML file" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " devhelp to make HTML files and a Devhelp project" 27 | @echo " epub to make an epub" 28 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 29 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 30 | @echo " text to make text files" 31 | @echo " man to make manual pages" 32 | @echo " changes to make an overview of all changed/added/deprecated items" 33 | @echo " linkcheck to check all external links for integrity" 34 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 35 | 36 | clean: 37 | -rm -rf $(BUILDDIR)/* 38 | 39 | html: 40 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 43 | 44 | dirhtml: 45 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 48 | 49 | singlehtml: 50 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 51 | @echo 52 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 53 | 54 | pickle: 55 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 56 | @echo 57 | @echo "Build finished; now you can process the pickle files." 58 | 59 | json: 60 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 61 | @echo 62 | @echo "Build finished; now you can process the JSON files." 63 | 64 | htmlhelp: 65 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 66 | @echo 67 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 68 | ".hhp project file in $(BUILDDIR)/htmlhelp." 69 | 70 | qthelp: 71 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 72 | @echo 73 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 74 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 75 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-faq.qhcp" 76 | @echo "To view the help file:" 77 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-faq.qhc" 78 | 79 | devhelp: 80 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 81 | @echo 82 | @echo "Build finished." 83 | @echo "To view the help file:" 84 | @echo "# mkdir -p $$HOME/.local/share/devhelp/django-faq" 85 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-faq" 86 | @echo "# devhelp" 87 | 88 | epub: 89 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 90 | @echo 91 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 92 | 93 | latex: 94 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 95 | @echo 96 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 97 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 98 | "(use \`make latexpdf' here to do that automatically)." 99 | 100 | latexpdf: 101 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 102 | @echo "Running LaTeX files through pdflatex..." 103 | make -C $(BUILDDIR)/latex all-pdf 104 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 105 | 106 | text: 107 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 108 | @echo 109 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 110 | 111 | man: 112 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 113 | @echo 114 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 115 | 116 | changes: 117 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 118 | @echo 119 | @echo "The overview file is in $(BUILDDIR)/changes." 120 | 121 | linkcheck: 122 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 123 | @echo 124 | @echo "Link check complete; look for any errors in the above output " \ 125 | "or in $(BUILDDIR)/linkcheck/output.txt." 126 | 127 | doctest: 128 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 129 | @echo "Testing of doctests in the sources finished, look at the " \ 130 | "results in $(BUILDDIR)/doctest/output.txt." 131 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | if NOT "%PAPER%" == "" ( 11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 12 | ) 13 | 14 | if "%1" == "" goto help 15 | 16 | if "%1" == "help" ( 17 | :help 18 | echo.Please use `make ^` where ^ is one of 19 | echo. html to make standalone HTML files 20 | echo. dirhtml to make HTML files named index.html in directories 21 | echo. singlehtml to make a single large HTML file 22 | echo. pickle to make pickle files 23 | echo. json to make JSON files 24 | echo. htmlhelp to make HTML files and a HTML help project 25 | echo. qthelp to make HTML files and a qthelp project 26 | echo. devhelp to make HTML files and a Devhelp project 27 | echo. epub to make an epub 28 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 29 | echo. text to make text files 30 | echo. man to make manual pages 31 | echo. changes to make an overview over all changed/added/deprecated items 32 | echo. linkcheck to check all external links for integrity 33 | echo. doctest to run all doctests embedded in the documentation if enabled 34 | goto end 35 | ) 36 | 37 | if "%1" == "clean" ( 38 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 39 | del /q /s %BUILDDIR%\* 40 | goto end 41 | ) 42 | 43 | if "%1" == "html" ( 44 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 45 | if errorlevel 1 exit /b 1 46 | echo. 47 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 48 | goto end 49 | ) 50 | 51 | if "%1" == "dirhtml" ( 52 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 53 | if errorlevel 1 exit /b 1 54 | echo. 55 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 56 | goto end 57 | ) 58 | 59 | if "%1" == "singlehtml" ( 60 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 61 | if errorlevel 1 exit /b 1 62 | echo. 63 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 64 | goto end 65 | ) 66 | 67 | if "%1" == "pickle" ( 68 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 69 | if errorlevel 1 exit /b 1 70 | echo. 71 | echo.Build finished; now you can process the pickle files. 72 | goto end 73 | ) 74 | 75 | if "%1" == "json" ( 76 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished; now you can process the JSON files. 80 | goto end 81 | ) 82 | 83 | if "%1" == "htmlhelp" ( 84 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished; now you can run HTML Help Workshop with the ^ 88 | .hhp project file in %BUILDDIR%/htmlhelp. 89 | goto end 90 | ) 91 | 92 | if "%1" == "qthelp" ( 93 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 94 | if errorlevel 1 exit /b 1 95 | echo. 96 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 97 | .qhcp project file in %BUILDDIR%/qthelp, like this: 98 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-faq.qhcp 99 | echo.To view the help file: 100 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-faq.ghc 101 | goto end 102 | ) 103 | 104 | if "%1" == "devhelp" ( 105 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 106 | if errorlevel 1 exit /b 1 107 | echo. 108 | echo.Build finished. 109 | goto end 110 | ) 111 | 112 | if "%1" == "epub" ( 113 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 117 | goto end 118 | ) 119 | 120 | if "%1" == "latex" ( 121 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 122 | if errorlevel 1 exit /b 1 123 | echo. 124 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 125 | goto end 126 | ) 127 | 128 | if "%1" == "text" ( 129 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished. The text files are in %BUILDDIR%/text. 133 | goto end 134 | ) 135 | 136 | if "%1" == "man" ( 137 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 141 | goto end 142 | ) 143 | 144 | if "%1" == "changes" ( 145 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.The overview file is in %BUILDDIR%/changes. 149 | goto end 150 | ) 151 | 152 | if "%1" == "linkcheck" ( 153 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Link check complete; look for any errors in the above output ^ 157 | or in %BUILDDIR%/linkcheck/output.txt. 158 | goto end 159 | ) 160 | 161 | if "%1" == "doctest" ( 162 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 163 | if errorlevel 1 exit /b 1 164 | echo. 165 | echo.Testing of doctests in the sources finished, look at the ^ 166 | results in %BUILDDIR%/doctest/output.txt. 167 | goto end 168 | ) 169 | 170 | :end 171 | -------------------------------------------------------------------------------- /faq/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.contrib.sites.models import Site 3 | 4 | from faq.settings import DRAFTED 5 | from faq.models import Topic, Question, OnSiteManager 6 | 7 | ## 8 | # Test fragmentify, or just view redirects? 9 | # Test _field_lookups, or just Manager? 10 | # Test admin actions? 11 | ## 12 | 13 | class BaseTestCase(TestCase): 14 | """""" 15 | 16 | fixtures = ['test_data'] 17 | 18 | def setUp(self): 19 | # Setup some new objects. We want these instead of ones from the test 20 | # data because we will be testing for the state of something newly 21 | # created, which the test data does not contain, obviously. 22 | self.topics = { 23 | 'new': Site.objects.get_current().faq_topics.create(title=u'Test Topic', 24 | slug=u'test-topic'), 25 | 'drafted': Topic.objects.get(slug='website'), 26 | 'published': Topic.objects.get(slug='shipping'), 27 | 'removed': Topic.objects.get(slug='black-market-items'), 28 | 'off_site': Topic.objects.get(slug='about-us'), 29 | } 30 | 31 | self. questions = { 32 | 'new1': self.topics['new'].questions.create(question=u'Where am I?', 33 | answer=u'That is classified.'), 34 | 'new2': self.topics['new'].questions.create(question=u'Who are you?', 35 | answer=u'I cannot say.'), 36 | 'drafted': Question.objects.get(slug='in-what-color-box-do-you-ship'), 37 | 'published': Question.objects.get(slug='how-much-does-shipping-cost'), 38 | 'removed': Question.objects.get(slug='what-carrier-do-you-use'), 39 | 'off_site': Question.objects.get(slug='are-you-hiring'), 40 | 'pub_topic_draft': Question.objects.get(slug='do-you-have-an-sla'), 41 | 'pub_topic_removed': Question.objects.get(slug='how-do-you-acquire-black-market-items'), 42 | } 43 | 44 | 45 | # Model and Manager test cases. 46 | 47 | class ManagerTestCase(BaseTestCase): 48 | """""" 49 | 50 | pass 51 | 52 | 53 | class ModelsTestCase(BaseTestCase): 54 | """""" 55 | 56 | def testManager(self): 57 | # Because of our sublcassing with the models, be certain that the 58 | # manager is wired up correctly. 59 | self.assertTrue(isinstance(Topic.objects, OnSiteManager)) 60 | self.assertTrue(isinstance(Question.objects, OnSiteManager)) 61 | 62 | def testUnicode(self): 63 | # Ensure that we don't absent-mindedly change what the `__unicode__()` 64 | # method returns. 65 | self.assertEqual(self.topics['new'].__unicode__(), 66 | self.topics['new'].title) 67 | self.assertEqual(self.questions['new1'].__unicode__(), 68 | self.questions['new1'].question) 69 | 70 | def testDefaultStatus(self): 71 | # Items created without choosing a status should be drafted by default. 72 | self.assertEqual(self.topics['new'].status, DRAFTED) 73 | self.assertEqual(self.questions['new1'].status, DRAFTED) 74 | 75 | def testSlugOnSave(self): 76 | # Be sure we are properly creating slugs for questions that are created 77 | # without them (those created as an inline to a topic). 78 | self.assertEqual(self.questions['new1'].slug, u'where-am-i') 79 | self.assertEqual(self.questions['new2'].slug, u'who-are-you') 80 | 81 | def testOrderingOnSave(self): 82 | # Be sure we are properly calculating and filling the ordering field 83 | # when a user leaves it blank. 84 | self.assertEqual(self.questions['new1'].ordering, 1) 85 | self.assertEqual(self.questions['new2'].ordering, 2) 86 | 87 | 88 | # View test case. 89 | 90 | class ViewsBaseTestCase(BaseTestCase): 91 | """""" 92 | 93 | def setUp(self): 94 | # Call `super` first because we used some of the stuff that it set up. 95 | super(ViewsBaseTestCase, self).setUp() 96 | 97 | # Set up some responses. We do this here because we are going to be 98 | # testing on these responses with various methods here and in subclasses. 99 | self.responses = { 100 | 'topic_list': self.client.get('/'), 101 | 'topic_detail': self.client.get( 102 | self.topics['published'].get_absolute_url(), follow=True), 103 | 'question_detail': self.client.get( 104 | self.questions['published'].get_absolute_url(), follow=True), 105 | } 106 | 107 | 108 | class ViewsShallowTestCase(ViewsBaseTestCase): 109 | 110 | urls = 'faq.urls.shallow' 111 | 112 | def testTopicDetail(self): 113 | # Redirects to a fragment identifier on the topic list. 114 | self.assertRedirects(self.responses['topic_detail'], 115 | '/#shipping', status_code=301) 116 | 117 | def testQuestionDetail(self): 118 | # Redirects to a fragment identifier on the topic list. 119 | self.assertRedirects(self.responses['question_detail'], 120 | '/#how-much-does-shipping-cost', status_code=301) 121 | 122 | 123 | class ViewsNormalTestCase(ViewsShallowTestCase): 124 | """""" 125 | 126 | urls = 'faq.urls.normal' 127 | 128 | def testTopicDetail(self): 129 | # Does not redirect. 130 | self.assertEqual(self.responses['topic_detail'].status_code, 200) 131 | # Check for our extra_context. 132 | # Must `list()` the QuerySets because querysets are unique. 133 | self.assertEqual(list(self.responses['topic_detail'].context['question_list']), 134 | list(self.topics['published'].questions.published())) 135 | 136 | def testQuestionDetail(self): 137 | # Redirects to a fragment identifier on the topic detail. 138 | self.assertRedirects(self.responses['question_detail'], 139 | '/shipping/#how-much-does-shipping-cost', status_code=301) 140 | 141 | 142 | class ViewsDeepTestCase(ViewsNormalTestCase): 143 | """""" 144 | 145 | urls = 'faq.urls.deep' 146 | 147 | def testQuestionDetail(self): 148 | # Does not redirect. 149 | self.assertEqual(self.responses['question_detail'].status_code, 200) 150 | # Check for our extra_context. 151 | self.assertEqual(self.responses['question_detail'].context['topic'], 152 | self.questions['published'].topic) 153 | -------------------------------------------------------------------------------- /faq/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.conf import settings 3 | from django.contrib.sites.models import Site 4 | from django.template.defaultfilters import slugify 5 | from django.utils.translation import ugettext_lazy as _ 6 | 7 | from faq.settings import DRAFTED, PUBLISHED, REMOVED, STATUS_CHOICES 8 | 9 | 10 | # Managers. 11 | 12 | def _field_lookups(model, status=None): 13 | """ 14 | Abstraction of field lookups for managers. 15 | 16 | Returns a dictionary of field lookups for a queryset. The lookups 17 | will always filter by site. Optionally, if ``status`` is passed to 18 | the function the objects will also be filtered by the given status. 19 | 20 | This function saves from having to make two different on-site and 21 | published Managers each for `Topic` and `Question`, and having to move 22 | Managers out of the `FAQBase` model and into each of the `Topic` 23 | and `Question` models. 24 | 25 | """ 26 | # Import models here to avoid circular import fail. 27 | from faq.models import Topic, Question 28 | 29 | field_lookups = {} 30 | 31 | if model == Topic: 32 | field_lookups['sites__pk'] = settings.SITE_ID 33 | 34 | if model == Question: 35 | field_lookups['topic__sites__pk'] = settings.SITE_ID 36 | if status: 37 | field_lookups['topic__status'] = status 38 | 39 | # Both Topic & Question have a status field. 40 | if status: 41 | field_lookups['status'] = status 42 | 43 | return field_lookups 44 | 45 | 46 | class OnSiteManager(models.Manager): 47 | """Custom manager providing shortcuts for filtering by status.""" 48 | 49 | def on_site(self): 50 | """Returns only items related to the current site.""" 51 | return self.get_query_set().filter(**_field_lookups(self.model)) 52 | 53 | def drafted(self): 54 | """Returns only on-site items with a status of 'drafted'.""" 55 | return self.get_query_set().filter( 56 | **_field_lookups(self.model, DRAFTED)) 57 | 58 | def published(self): 59 | """Returns only on-site items with a status of 'published'.""" 60 | return self.get_query_set().filter( 61 | **_field_lookups(self.model, PUBLISHED)) 62 | 63 | def removed(self): 64 | """Returns only on-site items with a status of 'removed'.""" 65 | return self.get_query_set().filter( 66 | **_field_lookups(self.model, REMOVED)) 67 | 68 | 69 | # Models. 70 | 71 | class FAQBase(models.Model): 72 | """A model holding information common to Topics and Questions.""" 73 | 74 | created = models.DateTimeField(_(u'date created'), auto_now_add=True) 75 | modified = models.DateTimeField(_(u'date modified'), auto_now=True) 76 | status = models.IntegerField(_(u'status'), choices=STATUS_CHOICES, 77 | # TODO: Genericize/fix the help_text. 78 | db_index=True, default=DRAFTED, help_text=_(u'Only objects with \ 79 | "published" status will be displayed publicly.')) 80 | 81 | objects = OnSiteManager() 82 | 83 | class Meta: 84 | abstract = True 85 | get_latest_by = 'modified' 86 | 87 | 88 | class Topic(FAQBase): 89 | """A topic that a Question can belong to.""" 90 | 91 | title = models.CharField(_(u'title'), max_length=255) 92 | slug = models.SlugField(_(u'slug'), unique=True, help_text=_(u'Used in \ 93 | the URL for the topic. Must be unique.')) 94 | description = models.TextField(_(u'description'), blank=True, 95 | help_text=_(u'A short description of this topic.')) 96 | sites = models.ManyToManyField(Site, verbose_name=_(u'sites'), 97 | related_name='faq_topics') 98 | 99 | class Meta(FAQBase.Meta): 100 | ordering = ('title', 'slug') 101 | verbose_name = _(u'topic') 102 | verbose_name_plural = _(u'topics') 103 | 104 | def __unicode__(self): 105 | return self.title 106 | 107 | @models.permalink 108 | def get_absolute_url(self): 109 | return ('faq-topic-detail', (), {'slug': self.slug}) 110 | 111 | 112 | class Question(FAQBase): 113 | """A frequently asked question.""" 114 | 115 | question = models.CharField(_(u'question'), max_length=255) 116 | slug = models.SlugField(_(u'slug'), unique=True, help_text=_(u'Used in \ 117 | the URL for the Question. Must be unique.')) 118 | answer = models.TextField(_(u'answer')) 119 | topic = models.ForeignKey(Topic, verbose_name=_(u'topic'), 120 | related_name='questions') 121 | ordering = models.PositiveSmallIntegerField(_(u'ordering'), blank=True, 122 | db_index=True, help_text=_(u'An integer used to order the question \ 123 | amongst others related to the same topic. If not given this \ 124 | question will be last in the list.')) 125 | 126 | class Meta(FAQBase.Meta): 127 | ordering = ('ordering', 'question', 'slug') 128 | verbose_name = _(u'question') 129 | verbose_name_plural = _(u'questions') 130 | 131 | def __unicode__(self): 132 | return self.question 133 | 134 | def save(self, *args, **kwargs): 135 | if not self.slug: 136 | # We populate the slug here because the common case for adding an 137 | # Question is as an inline to a Topic and InlineModelAdmin does not 138 | # currently support ``prepopulated_fields`` and it's mean to make 139 | # the user supply a slug by hand. 140 | self.slug = slugify(self.question)[:50] 141 | if not self.ordering: 142 | # When adding an Question to a Topic, it's easy to overlook the 143 | # ordering. We don't want to throw an error if it's left blank, 144 | # so to be nice we'll just put it at the end of the list. 145 | try: 146 | # Find the highest ordering value for all other Questions 147 | # related to the same topic and add 1. 148 | ordering = self.topic.questions.exclude(pk=self.pk).aggregate( 149 | models.Max('ordering'))['ordering__max'] + 1 150 | except TypeError: 151 | # There are no other related Questions, so let's set this 152 | # as no. 1. 153 | ordering = 1 154 | self.ordering = ordering 155 | super(Question, self).save(*args, **kwargs) 156 | 157 | @models.permalink 158 | def get_absolute_url(self): 159 | return ('faq-question-detail', (), {'topic_slug': self.topic.slug, 160 | 'slug': self.slug}) 161 | -------------------------------------------------------------------------------- /faq/fixtures/test_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pk": 3, 4 | "model": "faq.topic", 5 | "fields": { 6 | "status": 3, 7 | "description": "All about \u2026 US!", 8 | "title": "About us", 9 | "created": "2011-06-07 15:21:44", 10 | "modified": "2011-06-07 15:30:31", 11 | "sites": [ 12 | 2 13 | ], 14 | "slug": "about-us" 15 | } 16 | }, 17 | { 18 | "pk": 5, 19 | "model": "faq.topic", 20 | "fields": { 21 | "status": 3, 22 | "description": "Sshhh!", 23 | "title": "Black market items", 24 | "created": "2011-06-07 15:26:07", 25 | "modified": "2011-06-07 15:26:07", 26 | "sites": [ 27 | 1 28 | ], 29 | "slug": "black-market-items" 30 | } 31 | }, 32 | { 33 | "pk": 2, 34 | "model": "faq.topic", 35 | "fields": { 36 | "status": 2, 37 | "description": "All about returning an unwanted item.", 38 | "title": "Returns", 39 | "created": "2011-06-07 11:33:25", 40 | "modified": "2011-06-07 15:29:41", 41 | "sites": [ 42 | 1, 43 | 2 44 | ], 45 | "slug": "returns" 46 | } 47 | }, 48 | { 49 | "pk": 1, 50 | "model": "faq.topic", 51 | "fields": { 52 | "status": 2, 53 | "description": "All about how we ship your purchase to you.", 54 | "title": "Shipping", 55 | "created": "2011-06-07 11:31:15", 56 | "modified": "2011-06-07 15:28:46", 57 | "sites": [ 58 | 1 59 | ], 60 | "slug": "shipping" 61 | } 62 | }, 63 | { 64 | "pk": 4, 65 | "model": "faq.topic", 66 | "fields": { 67 | "status": 1, 68 | "description": "About our website.", 69 | "title": "Website", 70 | "created": "2011-06-07 15:23:59", 71 | "modified": "2011-06-07 15:23:59", 72 | "sites": [ 73 | 1, 74 | 2 75 | ], 76 | "slug": "website" 77 | } 78 | }, 79 | { 80 | "pk": 4, 81 | "model": "faq.question", 82 | "fields": { 83 | "status": 2, 84 | "created": "2011-06-07 15:21:44", 85 | "ordering": 1, 86 | "question": "Are you hiring?", 87 | "modified": "2011-06-07 15:21:44", 88 | "topic": 3, 89 | "answer": "Yes and no. If you are awesome, yes. If you are less than awesome, then not so much.", 90 | "slug": "are-you-hiring" 91 | } 92 | }, 93 | { 94 | "pk": 5, 95 | "model": "faq.question", 96 | "fields": { 97 | "status": 2, 98 | "created": "2011-06-07 15:23:59", 99 | "ordering": 1, 100 | "question": "Do you have an SLA?", 101 | "modified": "2011-06-07 15:23:59", 102 | "topic": 4, 103 | "answer": "No, because people with those get hosed.", 104 | "slug": "do-you-have-an-sla" 105 | } 106 | }, 107 | { 108 | "pk": 6, 109 | "model": "faq.question", 110 | "fields": { 111 | "status": 2, 112 | "created": "2011-06-07 15:26:07", 113 | "ordering": 1, 114 | "question": "How do you acquire black market items?", 115 | "modified": "2011-06-07 15:26:07", 116 | "topic": 5, 117 | "answer": "Very, very carefully", 118 | "slug": "how-do-you-acquire-black-market-items" 119 | } 120 | }, 121 | { 122 | "pk": 3, 123 | "model": "faq.question", 124 | "fields": { 125 | "status": 2, 126 | "created": "2011-06-07 11:33:25", 127 | "ordering": 1, 128 | "question": "How long do I have to return my item?", 129 | "modified": "2011-06-07 11:33:25", 130 | "topic": 2, 131 | "answer": "We are very liberal with this, but it is generally 20-30 minutes.", 132 | "slug": "how-long-do-i-have-to-return-my-item" 133 | } 134 | }, 135 | { 136 | "pk": 1, 137 | "model": "faq.question", 138 | "fields": { 139 | "status": 2, 140 | "created": "2011-06-07 11:31:15", 141 | "ordering": 1, 142 | "question": "How much does shipping cost?", 143 | "modified": "2011-06-07 11:31:15", 144 | "topic": 1, 145 | "answer": "Not much. At last check it was just shy of one frillion dollars.", 146 | "slug": "how-much-does-shipping-cost" 147 | } 148 | }, 149 | { 150 | "pk": 2, 151 | "model": "faq.question", 152 | "fields": { 153 | "status": 2, 154 | "created": "2011-06-07 11:32:14", 155 | "ordering": 2, 156 | "question": "How fast will my item arrive?", 157 | "modified": "2011-06-07 11:32:14", 158 | "topic": 1, 159 | "answer": "Sometime next week. We think.", 160 | "slug": "how-fast-will-my-item-arrive" 161 | } 162 | }, 163 | { 164 | "pk": 7, 165 | "model": "faq.question", 166 | "fields": { 167 | "status": 1, 168 | "created": "2011-06-07 15:28:46", 169 | "ordering": 3, 170 | "question": "In what color box do you ship?", 171 | "modified": "2011-06-07 15:28:46", 172 | "topic": 1, 173 | "answer": "Green, because it is good for the environment. Go us!", 174 | "slug": "in-what-color-box-do-you-ship" 175 | } 176 | }, 177 | { 178 | "pk": 8, 179 | "model": "faq.question", 180 | "fields": { 181 | "status": 3, 182 | "created": "2011-06-07 15:28:46", 183 | "ordering": 4, 184 | "question": "What carrier do you use?", 185 | "modified": "2011-06-07 15:28:46", 186 | "topic": 1, 187 | "answer": "Whomever saves us the most money.", 188 | "slug": "what-carrier-do-you-use" 189 | } 190 | }, 191 | { 192 | "pk": 1, 193 | "model": "sites.site", 194 | "fields": { 195 | "domain": "example.com", 196 | "name": "example.com" 197 | } 198 | }, 199 | { 200 | "pk": 2, 201 | "model": "sites.site", 202 | "fields": { 203 | "domain": "example.us", 204 | "name": "example.us" 205 | } 206 | } 207 | ] 208 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # django-faq documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Sep 17 13:09:21 2011. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] 29 | 30 | intersphinx_mapping = { 31 | 'python': ('http://python.readthedocs.org/en/latest/', None), 32 | 'django': ('http://django.readthedocs.org/en/latest/', None), 33 | 'sphinx': ('http://sphinx.readthedocs.org/en/latest/', None), 34 | } 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | # templates_path = ['_templates'] 38 | 39 | # The suffix of source filenames. 40 | source_suffix = '.rst' 41 | 42 | # The encoding of source files. 43 | #source_encoding = 'utf-8-sig' 44 | 45 | # The master toctree document. 46 | master_doc = 'index' 47 | 48 | # General information about the project. 49 | project = u'django-faq' 50 | copyright = u'2011, Ben Spaulding' 51 | 52 | # The version info for the project you're documenting, acts as replacement for 53 | # |version| and |release|, also used in various other places throughout the 54 | # built documents. 55 | # 56 | # The short X.Y version. 57 | version = '0.8' 58 | # The full version, including alpha/beta/rc tags. 59 | release = '0.8.2' 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | #language = None 64 | 65 | # There are two options for replacing |today|: either, you set today to some 66 | # non-false value, then it is used: 67 | #today = '' 68 | # Else, today_fmt is used as the format for a strftime call. 69 | #today_fmt = '%B %d, %Y' 70 | 71 | # List of patterns, relative to source directory, that match files and 72 | # directories to ignore when looking for source files. 73 | exclude_patterns = ['_build'] 74 | 75 | # The reST default role (used for this markup: `text`) to use for all documents. 76 | #default_role = None 77 | 78 | # If true, '()' will be appended to :func: etc. cross-reference text. 79 | #add_function_parentheses = True 80 | 81 | # If true, the current module name will be prepended to all description 82 | # unit titles (such as .. function::). 83 | #add_module_names = True 84 | 85 | # If true, sectionauthor and moduleauthor directives will be shown in the 86 | # output. They are ignored by default. 87 | #show_authors = False 88 | 89 | # The name of the Pygments (syntax highlighting) style to use. 90 | pygments_style = 'sphinx' 91 | 92 | # A list of ignored prefixes for module index sorting. 93 | #modindex_common_prefix = [] 94 | 95 | 96 | # -- Options for HTML output --------------------------------------------------- 97 | 98 | # The theme to use for HTML and HTML Help pages. See the documentation for 99 | # a list of builtin themes. 100 | html_theme = 'default' 101 | 102 | # Theme options are theme-specific and customize the look and feel of a theme 103 | # further. For a list of options available for each theme, see the 104 | # documentation. 105 | #html_theme_options = {} 106 | 107 | # Add any paths that contain custom themes here, relative to this directory. 108 | #html_theme_path = [] 109 | 110 | # The name for this set of Sphinx documents. If None, it defaults to 111 | # " v documentation". 112 | #html_title = None 113 | 114 | # A shorter title for the navigation bar. Default is the same as html_title. 115 | #html_short_title = None 116 | 117 | # The name of an image file (relative to this directory) to place at the top 118 | # of the sidebar. 119 | #html_logo = None 120 | 121 | # The name of an image file (within the static path) to use as favicon of the 122 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 123 | # pixels large. 124 | #html_favicon = None 125 | 126 | # Add any paths that contain custom static files (such as style sheets) here, 127 | # relative to this directory. They are copied after the builtin static files, 128 | # so a file named "default.css" will overwrite the builtin "default.css". 129 | # html_static_path = ['_static'] 130 | 131 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 132 | # using the given strftime format. 133 | #html_last_updated_fmt = '%b %d, %Y' 134 | 135 | # If true, SmartyPants will be used to convert quotes and dashes to 136 | # typographically correct entities. 137 | #html_use_smartypants = True 138 | 139 | # Custom sidebar templates, maps document names to template names. 140 | #html_sidebars = {} 141 | 142 | # Additional templates that should be rendered to pages, maps page names to 143 | # template names. 144 | #html_additional_pages = {} 145 | 146 | # If false, no module index is generated. 147 | #html_domain_indices = True 148 | 149 | # If false, no index is generated. 150 | #html_use_index = True 151 | 152 | # If true, the index is split into individual pages for each letter. 153 | #html_split_index = False 154 | 155 | # If true, links to the reST sources are added to the pages. 156 | #html_show_sourcelink = True 157 | 158 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 159 | #html_show_sphinx = True 160 | 161 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 162 | #html_show_copyright = True 163 | 164 | # If true, an OpenSearch description file will be output, and all pages will 165 | # contain a tag referring to it. The value of this option must be the 166 | # base URL from which the finished HTML is served. 167 | #html_use_opensearch = '' 168 | 169 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 170 | #html_file_suffix = None 171 | 172 | # Output file base name for HTML help builder. 173 | htmlhelp_basename = 'django-faqdoc' 174 | 175 | 176 | # -- Options for LaTeX output -------------------------------------------------- 177 | 178 | # The paper size ('letter' or 'a4'). 179 | #latex_paper_size = 'letter' 180 | 181 | # The font size ('10pt', '11pt' or '12pt'). 182 | #latex_font_size = '10pt' 183 | 184 | # Grouping the document tree into LaTeX files. List of tuples 185 | # (source start file, target name, title, author, documentclass [howto/manual]). 186 | latex_documents = [ 187 | ('index', 'django-faq.tex', u'django-faq Documentation', 188 | u'Ben Spaulding', 'manual'), 189 | ] 190 | 191 | # The name of an image file (relative to this directory) to place at the top of 192 | # the title page. 193 | #latex_logo = None 194 | 195 | # For "manual" documents, if this is true, then toplevel headings are parts, 196 | # not chapters. 197 | #latex_use_parts = False 198 | 199 | # If true, show page references after internal links. 200 | #latex_show_pagerefs = False 201 | 202 | # If true, show URL addresses after external links. 203 | #latex_show_urls = False 204 | 205 | # Additional stuff for the LaTeX preamble. 206 | #latex_preamble = '' 207 | 208 | # Documents to append as an appendix to all manuals. 209 | #latex_appendices = [] 210 | 211 | # If false, no module index is generated. 212 | #latex_domain_indices = True 213 | 214 | 215 | # -- Options for manual page output -------------------------------------------- 216 | 217 | # One entry per manual page. List of tuples 218 | # (source start file, name, description, authors, manual section). 219 | man_pages = [ 220 | ('index', 'django-faq', u'django-faq Documentation', 221 | [u'Ben Spaulding'], 1) 222 | ] 223 | 224 | 225 | # Example configuration for intersphinx: refer to the Python standard library. 226 | intersphinx_mapping = {'http://docs.python.org/': None} 227 | --------------------------------------------------------------------------------