From 5fc3b1a4a446715d859440b474ae206ff672b4cd Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 22 Feb 2013 13:35:58 +0100 Subject: [PATCH 1/1] Enable questions tagging. --- prawokultury/settings.d/50-contrib.py | 2 + questions/admin.py | 3 +- .../0003_auto__add_tag__add_tagitem.py | 77 +++++++++++++++++++ questions/models.py | 20 ++++- .../templates/questions/question_detail.html | 8 ++ .../templates/questions/question_list.html | 31 +++++++- questions/urls.py | 7 +- questions/views.py | 30 ++++++++ requirements.txt | 2 +- 9 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 questions/migrations/0003_auto__add_tag__add_tagitem.py diff --git a/prawokultury/settings.d/50-contrib.py b/prawokultury/settings.d/50-contrib.py index 10b4f39..4423184 100644 --- a/prawokultury/settings.d/50-contrib.py +++ b/prawokultury/settings.d/50-contrib.py @@ -17,3 +17,5 @@ CAS_SERVER_URL = 'http://logowanie.nowoczesnapolska.org.pl/cas/' CAS_VERSION = '1' HONEYPOT_FIELD_NAME='miut' + +TAGGIT_AUTOSUGGEST_MODEL = ('questions', 'Tag') diff --git a/questions/admin.py b/questions/admin.py index 9db5ff7..ec6d715 100755 --- a/questions/admin.py +++ b/questions/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Question +from .models import Question, Tag class QuestionAdmin(admin.ModelAdmin): model = Question @@ -22,3 +22,4 @@ class QuestionAdmin(admin.ModelAdmin): admin.site.register(Question, QuestionAdmin) +admin.site.register(Tag) diff --git a/questions/migrations/0003_auto__add_tag__add_tagitem.py b/questions/migrations/0003_auto__add_tag__add_tagitem.py new file mode 100644 index 0000000..7bf22f7 --- /dev/null +++ b/questions/migrations/0003_auto__add_tag__add_tagitem.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Tag' + db.create_table('questions_tag', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=100)), + )) + db.send_create_signal('questions', ['Tag']) + + # Adding model 'TagItem' + db.create_table('questions_tagitem', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('object_id', self.gf('django.db.models.fields.IntegerField')(db_index=True)), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='questions_tagitem_tagged_items', to=orm['contenttypes.ContentType'])), + ('tag', self.gf('django.db.models.fields.related.ForeignKey')(related_name='items', to=orm['questions.Tag'])), + )) + db.send_create_signal('questions', ['TagItem']) + + + def backwards(self, orm): + # Deleting model 'Tag' + db.delete_table('questions_tag') + + # Deleting model 'TagItem' + db.delete_table('questions_tagitem') + + + models = { + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'questions.question': { + 'Meta': {'ordering': "['-created_at']", 'object_name': 'Question'}, + '_answer_rendered': ('django.db.models.fields.TextField', [], {}), + 'answer': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True', 'blank': 'True'}), + 'answer_markup_type': ('django.db.models.fields.CharField', [], {'default': "'textile_pl'", 'max_length': '30', 'blank': 'True'}), + 'answered': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), + 'answered_at': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'edited_question': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), + 'published_at': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'question': ('django.db.models.fields.TextField', [], {'db_index': 'True'}) + }, + 'questions.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'}) + }, + 'questions.tagitem': { + 'Meta': {'object_name': 'TagItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions_tagitem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['questions.Tag']"}) + } + } + + complete_apps = ['questions'] \ No newline at end of file diff --git a/questions/models.py b/questions/models.py index 2955ddb..1540191 100644 --- a/questions/models.py +++ b/questions/models.py @@ -7,9 +7,27 @@ from django.db import models from django.template import loader, Context from django.utils.translation import ugettext_lazy as _ from markupfield.fields import MarkupField +from taggit.models import TagBase, GenericTaggedItemBase from taggit_autosuggest.managers import TaggableManager +from fnpdjango.utils.text.slughifi import slughifi +class Tag(TagBase): + def slugify(self, tag, i=None): + slug = slughifi(tag) + if i is not None: + slug += "_%d" % i + return slug + + class Meta: + verbose_name = _("Tag") + verbose_name_plural = _("Tags") + + +class TagItem(GenericTaggedItemBase): + tag = models.ForeignKey(Tag, related_name="items") + + class Question(models.Model): email = models.EmailField(_('contact e-mail'), null=True, blank=True) question = models.TextField(_('question'), db_index=True) @@ -27,7 +45,7 @@ class Question(models.Model): help_text=_('Check to display answered question on site.')) published_at = models.DateTimeField(_('published at'), null=True, blank=True, db_index=True) - tags = TaggableManager() + tags = TaggableManager(through=TagItem) class Meta: ordering = ['-created_at'] diff --git a/questions/templates/questions/question_detail.html b/questions/templates/questions/question_detail.html index 2fc5ce0..dea7e14 100755 --- a/questions/templates/questions/question_detail.html +++ b/questions/templates/questions/question_detail.html @@ -6,6 +6,14 @@

{{ question|linebreaksbr }}

+{% if question.tags.all.count %} +

Tematy: +{% for tag in question.tags.all %} + {{ tag }}{% if not forloop.last %} / {% endif %} +{% endfor %} +{% endif %} +

+ {{ question.answer }}

Wróć do listy pytań.

diff --git a/questions/templates/questions/question_list.html b/questions/templates/questions/question_list.html index 4cad0e9..06fb866 100755 --- a/questions/templates/questions/question_list.html +++ b/questions/templates/questions/question_list.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load url from future %} +{% load pagination_tags fnp_prevnext %} {% block "titleextra" %}Pierwsza pomoc w prawie autorskim :: {% endblock %} {% block "body" %} @@ -26,13 +27,39 @@ autorem szeregu publikacji naukowych poświęconych korzystaniu z technologii informacyjno-komunikacyjnych oraz posiada wieloletnie doświadczenie doradcze w tej tematyce.

-

Odpowiedzi na już zadane pytania:

+Tematy: +{% if tag %}wszystkie +{% else %}wszystkie +{% endif %} + +{% for atag in tags %} / + {% if atag == tag %}{{ atag }} + {% else %}{{ atag }} + {% endif %} +{% endfor %} + +

Odpowiedzi na już zadane pytania + {% if tag %}na temat: {{ tag }}{% endif %} + ({{ object_list.count }}):

+ +{% autopaginate object_list 1 %} +
+{% prevnext %} + + {% endblock %} diff --git a/questions/urls.py b/questions/urls.py index 2f3c5f2..3073290 100755 --- a/questions/urls.py +++ b/questions/urls.py @@ -3,14 +3,13 @@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from django.conf.urls import patterns, url -from django.views.generic import DetailView, ListView, TemplateView +from django.views.generic import DetailView, TemplateView from .models import Question -from .views import QuestionFormView +from .views import QuestionFormView, QuestionListView urlpatterns = patterns('', url(r'^$', - ListView.as_view(queryset=Question.objects.filter(published=True - ).order_by('-published_at')), + QuestionListView.as_view(), name="questions" ), url(r'^(?P\d+)/$', diff --git a/questions/views.py b/questions/views.py index 1c918c8..b68d24b 100644 --- a/questions/views.py +++ b/questions/views.py @@ -1,6 +1,12 @@ +# -*- coding: utf-8 -*- +# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# from django.core.urlresolvers import reverse_lazy +from django.views.generic import ListView from django.views.generic.edit import FormView from .forms import QuestionForm +from .models import Question, Tag class QuestionFormView(FormView): @@ -11,3 +17,27 @@ class QuestionFormView(FormView): def form_valid(self, form): form.save() return super(QuestionFormView, self).form_valid(form) + + +class QuestionListView(ListView): + def get(self, request, *args, **kwargs): + self.tag = None + if 'tag' in request.GET: + try: + self.tag = Tag.objects.get(slug=request.GET['tag']) + except Tag.DoesNotExist: + pass + return super(QuestionListView, self).get(request, *args, **kwargs) + + def get_queryset(self): + qs = Question.objects.filter(published=True + ).order_by('-published_at') + if 'tag' in self.request.GET: + qs = qs.filter(tags__slug=self.request.GET['tag']) + return qs + + def get_context_data(self, *args, **kwargs): + context = super(QuestionListView, self).get_context_data(*args, **kwargs) + context['tags'] = Tag.objects.all() + context['tag'] = self.tag + return context diff --git a/requirements.txt b/requirements.txt index ef0a9ff..7697e38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ django-pagination django-honeypot django-migdal>=0.3.1,<0.4 -fnpdjango>=0.1.4,<0.2 +fnpdjango>=0.1.5,<0.2 textile django-markupfield -- 2.20.1