Package: django-easy-faq
django-easy-faqdjango-easy-faq is a Django app to allow for a simple yet feature rich faq app. with categories, commenting voting of questions and answers all as an optional part of the app. To see screenshots of what this django-easy-faq could look like with bootstrap 5 stylingclick here.Quick startpip install:pip install django-easy-faqAdd "faq" to your INSTALLED_APPS setting like this:INSTALLED_APPS=[...'faq',]Include the easy-faq URLconf in your project urls.py like this::#…path('faq/',include('faq.urls')),#…AddFAQ_SETTINGS = []to yoursettings.pyRunpython manage.py makemigrationsto create the faq models migrations.Runpython manage.py migrateto create the faq models.Start the development server and visithttp://127.0.0.1:8000/admin/to create a category (you'll need the Admin app enabled).(categories part of the app can be disabled)Visithttp://127.0.0.1:8000/faq/to see the categories.Settingsyou can change most things in settings below is a list of all settings
add any or all to change to desired behavior::FAQ_SETTINGS = ['your_settings_here',]no_category_description                  - add if using categories but don't want descriptions for themno_category                              - add if don't want to use categorieslogged_in_users_can_add_question         - add if you want any logged in user to be able to ask a questionlogged_in_users_can_answer_question      - add if you want any logged in user to be able to answer a questionallow_multiple_answers                   - add if you want a question to be able to be answered multiple timesno_comments                              - add if don't want to use commentsanonymous_user_can_comment               - add if you want any user to be able to comment including anonymous usersview_only_comments                       - add if you want users to see posted comments but not be able to add any moreno_votes                                 - add if don't want any voting for useful questions or answersno_answer_votes                         - add if only want question votingno_question_votes                       - add if only want answer votingallow_unicode                           - add if you want to allow unicode slugslogin_required                          - add if you want to only let logged in users see FAQ'sTemplatesall of the templates are meant to be overwritten
to overwrite them create a faq directory inside of the templates directory and add a html file with the same name to itif this doesn't work make sure that the templates setting has 'DIRS': ['templates'], in it::TEMPLATES = [
    {
        ...
        'DIRS': ['templates'],
        ...
    },
]here is a list of templates and there default template  you can overwritecategories_list.html - faq main view if using categories::<h1>select a FAQ category</h1>
 {% for category in categories %}
     <h3><a href="{% url 'faq:category_detail' category.slug %}">{{category.name}}</a></h3>
     {% if category.description %}
         <p>{{category.description}}</p>
     {% endif %}
     <hr>
 {% endfor %}category_detail.html - faq category detail view if using categories::<h1>choose a FAQ Question</h1>
 <h2>{{category}}</h2>
 {% if category.description %}
 <p>{{category.description}}</p>
 {% endif %}
 <hr>
 {% for question in category.question_set.all %}
     <h3><a href="{% url 'faq:question_detail' category.slug question.slug %}">{{question.question}}</a></h3>
 {% endfor %}
 <hr>
 <a href="{% url 'faq:index_view' %}">back</a>
 {% if can_add_question %}
     <a href="{% url 'faq:add_question' category.slug %}">add question</a>
 {% endif %}questions_list.html - lists all questions if not using categories::<h1>choose a FAQ Question</h1>
 {% for question in questions %}
     <h3><a href="{% url 'faq:question_detail' question.slug %}">{{question.question}}</a></h3>
 {% endfor %}

 {% if can_add_question %}
     <hr>
     <a href="{% url 'faq:add_question' %}">add question</a>
 {% endif %}question_detail.html - the question detail page::{% extends 'faq/question_base.html' %}

 {% block question_content %}
 {% if allow_multiple_answers %}
 <h3>answers</h3>
 <ul>
     {% for answer in question.answer_set.all %}
         <li><b>{{answer.answer}}</b>
             {% if can_vote_answer %}
              | found this answer helpful?
             <form style="display: inline;" action="{% if category_enabled %}{% url 'faq:vote_answer' question.category.slug question.slug answer.slug %}{% else %}{% url 'faq:vote_answer' question.slug answer.slug %}{% endif %}" method="post">
                 {% csrf_token %}
                 <input type="hidden" value=True name="vote">
                 <button type="submit">yes({{answer.helpful}})</button>
             </form>
             <form style="display: inline;" action="{% if category_enabled %}{% url 'faq:vote_answer' question.category.slug question.slug answer.slug %}{% else %}{% url 'faq:vote_answer' question.slug answer.slug %}{% endif %}" method="post">
                 {% csrf_token %}
                 <input type="hidden" value=False name="vote">
                 <button type="submit">no({{answer.not_helpful}})</button>
             </form>
             {% endif %}
         </li>
     {% endfor %}
 </ul>

 {% else %}
     {% if question.answer_set.exists %}
         <p>answer:</p>
         <h3>{{question.answer_set.first.answer}}</h3>
         {% if can_vote_answer %}
          found this answer helpful?
         <form style="display: inline;" action="{% if category_enabled %}{% url 'faq:vote_answer' question.category.slug question.slug question.answer_set.first.slug %}{% else %}{% url 'faq:vote_answer' question.slug question.answer_set.first.slug %}{% endif %}" method="post">
             {% csrf_token %}
             <input type="hidden" value=True name="vote">
             <button type="submit">yes({{question.answer_set.first.helpful}})</button>
         </form>
         <form style="display: inline;" action="{% if category_enabled %}{% url 'faq:vote_answer' question.category.slug question.slug question.answer_set.first.slug %}{% else %}{% url 'faq:vote_answer' question.slug question.answer_set.first.slug %}{% endif %}" method="post">
             {% csrf_token %}
             <input type="hidden" value=False name="vote">
             <button type="submit">no({{question.answer_set.first.not_helpful}})</button>
         </form>
         {% endif %}
     {% else %}
         no answers yet
     {% endif %}
 {% endif %}


 {% if can_answer_question %}
     {% if category_enabled %}
         <a href="{% url 'faq:answer_question' question.category.slug question.slug %}">answer question</a>
     {% else %}
         <a href="{% url 'faq:answer_question' question.slug %}">answer question</a>
     {% endif %}
 {% endif %}
 <hr>
 {% if comments_allowed %}
     {% include 'faq/comments.html' %}
 {% endif %}

 {% endblock %}answer_form.html - form to add answer to question::<h1>Answer Question</h1>
 <a href="{{question.get_absolute_url}}"><h3>{{question.question}}</h3></a>
 <form method="post">
     {% csrf_token %}
     {{form}}
     <input type="submit">
 </form>comment_form.html - form to add comments to question (only shows up when form has error because view only gets posted to)::<h1>Post A Comment</h1>
 <a href="{{question.get_absolute_url}}"><h3>{{question.question}}</h3></a>
 <form method="post">
     {% csrf_token %}
     {{form}}
     <input type="submit">
 </form>question_form.html - form to add a new question::<h1>Add Your Question</h1>
 <form method="post">
     {% csrf_token %}
     {{form}}
     <input type="submit">
 </form>vote_form.html - form for voting questions and answers (only shows up when form has error because view only gets posted to)::<h1>vote</h1>
 <form method="post">
     {% csrf_token %}
     {{form}}
     <input type="submit">
 </form>comments.html - if comments are allowed this template is included in the question detail.html::<h3>comments</h3>
 <ul>
     {% for comment in question.faqcomment_set.all %}
         <li><h4>{{comment.comment}}</h4>
             posted by {% if comment.user%}{{comment.user}}{% else %}anonymous{% endif %} {{comment.post_time|timesince}} ago</li>
     {% endfor %}
 </ul>
 {% if add_new_comment_allowed %}
     {% if category_enabled %}
     <form method="post" action="{% url 'faq:add_comment' question.category.slug question.slug %}">
     {% else %}
     <form method="post" action="{% url 'faq:add_comment' question.slug %}">
     {% endif %}
     <fieldset>
         <legend>Post Your Comment Here:</legend>
         {% csrf_token %}
         {{comment_form}}
         <input type="submit" name="post">
     </fieldset>
     </form>
 {% endif %}Template Variablescategories_list.html
categories - all the categories (category queryset)categories_detail.html
category - the category chosen (category object)
can_add_question - bool if the user can add a question (depends on the settings)questions_list.html
questions - all the questions (question queryset)
can_add_question - bool if the user can add a question (depends on the settings)question_detail.html
question - the question chosen (question object)
can_vote_question - bool if the user can vote a question (depends on the settings)
category_enabled - bool if category enabled in settings
allow_multiple_answers - bool if multiple answers allowed in settings
can_vote_answer - bool if the user can vote an answer (depends on the settings)
can_answer_question - bool if current user can answer question (depends on the settings)
comments_allowed - bool if using comments in settings
add_new_comment_allowed - bool if current user can add comment (depends on the settings)
comment_form - form to submit a new commentanswer_form.html
question - the question to add answer to (question object)
form - form to add new answercomment_form.html
question - the question to add comment to (question object)
form - form to add new commentquestion_form.html
form - form to add new questionvote_form.html
form - form to vote for a question or answerUrlsall of the following urls are by name then additional
the app name for the urls is'faq'index_viewno argumentsdisplays all the categories if categories are enabled otherwise shows questionscategory_detailneeds category slug as slugdisplays all the questions given the category when categories are enabledadd_questionif categories are enabled needs category slug as slugif logged_in_users_can_add_question then displays form for logged in users to ask a new questionquestion_detailneeds question slug as question | if categories are enabled needs category slug as slugdisplays the main FAQ page with the question all the comments and answersanswer_questionneeds question slug as question | if categories are enabled needs category slug as categorydisplays the answer question formadd_commentneeds question slug as question | if categories are enabled needs category slug as categoryonly works if using commentsused to post comment form from question_detail to databasevote_answerneeds question slug as question | needs answer slug as answer | if categories are enabled needs category slug as categoryonly works if using answer votingused to post hidden input vote = 1 or vote = 0 depending on vote up or downvote_questionneeds question slug as question | if categories are enabled needs category slug as categoryonly works if using question votingused to post hidden input vote = 1 or vote = 0 depending on vote up or downContributingdjango-easy-faq aims to be the best faq app for django. It welcomes  contributions of all types - issues, bugs, feature requests, documentation updates, tests and pull requestschange log0.4 fixed bug that logged out users can vote - which then raises exceptions0.5 fixed migrations1.0 added pypi distribution1.1 added more templates to override easily1.2 fixed bug in pypi distro not including faq app1.3 fixed bug where a slug must be filled out in admin even though slug gets auto generated to save for questions, answers, and categories. made questions, answers, categories slugs readonly in admin1.4 added unicode option to add unicode slugs1.5 added login_required setting to allow faq app to be available to only logged in users1.6 fixed bug where no_category_description did not do remove the category description in the admin1.7 added support for django 5.0