Skip to content

Commit 3e62f0c

Browse files
committed
Port to django-fluent-utils, for better code sharing.
* Soft dependencies to django-taggit and django-fluent-pages are more clearly defined now.
1 parent 5a35b7c commit 3e62f0c

File tree

4 files changed

+18
-106
lines changed

4 files changed

+18
-106
lines changed

fluent_faq/admin/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.utils.translation import ugettext, ugettext_lazy as _
66
from fluent_faq import appsettings
77
from fluent_contents.admin import PlaceholderFieldAdmin
8+
from fluent_utils.softdeps.fluent_pages import mixed_reverse
89
from parler.admin import TranslatableAdmin
910
from parler.forms import TranslatableModelForm
1011
from parler.models import TranslationDoesNotExist
@@ -134,7 +135,6 @@ def render_change_form(self, request, context, add=False, change=False, form_url
134135
def _reverse_faqpage_index(self, request, obj=None):
135136
# Internal method with "protected access" to handle translation differences.
136137
# This is only called when 'fluent_pages' is in the INSTALLED_APPS.
137-
from fluent_pages.urlresolvers import mixed_reverse
138138
return mixed_reverse('faqquestion_index')
139139

140140

fluent_faq/models.py

+12-84
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,14 @@
11
from django.conf import settings
2-
from django.contrib.contenttypes.models import ContentType
32
from django.contrib.sites.models import Site
43
from django.db import models
54
from django.utils.translation import ugettext_lazy as _
5+
from fluent_faq import appsettings
66
from parler.models import TranslatableModel, TranslatedFields
7+
from parler.utils.context import switch_language
78
from fluent_contents.models import PlaceholderField, ContentItemRelation
89
from fluent_faq.urlresolvers import faq_reverse
910
from fluent_faq.managers import FaqQuestionManager, FaqCategoryManager
10-
11-
12-
13-
# Optional tagging support
14-
from parler.utils.context import switch_language
15-
16-
TaggableManager = None
17-
if 'taggit_autosuggest' in settings.INSTALLED_APPS:
18-
from taggit_autosuggest.managers import TaggableManager
19-
elif 'taggit_autocomplete_modified' in settings.INSTALLED_APPS:
20-
from taggit_autocomplete_modified.managers import TaggableManagerAutocomplete as TaggableManager
21-
elif 'taggit' in settings.INSTALLED_APPS:
22-
from taggit.managers import TaggableManager
11+
from fluent_utils.softdeps.taggit import TagsMixin
2312

2413

2514
class FaqBaseModel(TranslatableModel):
@@ -97,7 +86,7 @@ def get_relative_url(self):
9786

9887

9988

100-
class FaqQuestion(FaqBaseModel):
89+
class FaqQuestion(TagsMixin, FaqBaseModel):
10190
"""
10291
Category in the FAQ.
10392
"""
@@ -119,12 +108,6 @@ class FaqQuestion(FaqBaseModel):
119108
# Organisation
120109
category = models.ForeignKey(FaqCategory, verbose_name=_("Category"), related_name='questions')
121110

122-
# Make association with tags optional.
123-
if TaggableManager is not None:
124-
tags = TaggableManager(blank=True, help_text=_("Tags are used to find related questions"))
125-
else:
126-
tags = None
127-
128111
objects = FaqQuestionManager()
129112

130113
class Meta:
@@ -143,70 +126,15 @@ def get_relative_url(self):
143126
# Return the link style, using the permalink style setting.
144127
return u'{0}{1}/'.format(self.category.get_relative_url(), self.slug)
145128

146-
147129
def similar_objects(self, num=None, **filters):
148-
tags = self.tags
149-
if not tags:
150-
return []
151-
152-
content_type = ContentType.objects.get_for_model(self.__class__)
153-
filters['content_type'] = content_type
154-
155-
# can't filter, see
156-
# - https://github.com/alex/django-taggit/issues/32
157-
# - http://django-taggit.readthedocs.org/en/latest/api.html#TaggableManager.similar_objects
158-
#
159-
# Otherwise this would be possible:
160-
# return tags.similar_objects(**filters)
161-
162-
lookup_kwargs = tags._lookup_kwargs()
163-
lookup_keys = sorted(lookup_kwargs)
164-
qs = tags.through.objects.values(*lookup_kwargs.keys())
165-
qs = qs.annotate(n=models.Count('pk'))
166-
qs = qs.exclude(**lookup_kwargs)
167-
subq = tags.all()
168-
qs = qs.filter(tag__in=list(subq))
169-
qs = qs.order_by('-n')
170-
171-
# from https://github.com/alex/django-taggit/issues/32#issuecomment-1002491
172-
if filters is not None:
173-
qs = qs.filter(**filters)
174-
175-
if num is not None:
176-
qs = qs[:num]
177-
178-
# Normal taggit code continues
179-
180-
# TODO: This all feels like a bit of a hack.
181-
items = {}
182-
if len(lookup_keys) == 1:
183-
# Can we do this without a second query by using a select_related()
184-
# somehow?
185-
f = tags.through._meta.get_field_by_name(lookup_keys[0])[0]
186-
objs = f.rel.to._default_manager.filter(**{
187-
"%s__in" % f.rel.field_name: [r["content_object"] for r in qs]
188-
})
189-
for obj in objs:
190-
items[(getattr(obj, f.rel.field_name),)] = obj
191-
else:
192-
preload = {}
193-
for result in qs:
194-
preload.setdefault(result['content_type'], set())
195-
preload[result["content_type"]].add(result["object_id"])
196-
197-
for ct, obj_ids in preload.items():
198-
ct = ContentType.objects.get_for_id(ct)
199-
for obj in ct.model_class()._default_manager.filter(pk__in=obj_ids):
200-
items[(ct.pk, obj.pk)] = obj
201-
202-
results = []
203-
for result in qs:
204-
obj = items[
205-
tuple(result[k] for k in lookup_keys)
206-
]
207-
obj.similar_tags = result["n"]
208-
results.append(obj)
209-
return results
130+
"""
131+
Find similar objects using related tags.
132+
"""
133+
#TODO: filter appsettings.FLUENT_FAQ_FILTER_SITE_ID:
134+
# filters.setdefault('parent_site', self.parent_site_id)
135+
136+
# FIXME: Using super() doesn't work, calling directly.
137+
return TagsMixin.similar_objects(self, num=num, **filters)
210138

211139

212140
def _register_anyurlfield_type():

fluent_faq/urlresolvers.py

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
1-
from django.conf import settings
2-
from django.core.urlresolvers import reverse
1+
from fluent_utils.softdeps.fluent_pages import mixed_reverse
32

4-
_HAS_FLUENT_PAGES = ('fluent_pages' in settings.INSTALLED_APPS)
5-
if _HAS_FLUENT_PAGES:
6-
from fluent_pages.urlresolvers import mixed_reverse
73

8-
9-
def faq_reverse(viewname, args=None, kwargs=None, current_app='fluent_faq', current_page=None, language_code=None, multiple=False, ignore_multiple=False):
4+
def faq_reverse(viewname, args=None, kwargs=None, current_app='fluent_faq', **page_kwargs):
105
"""
11-
Reverse a URL to the blog, taking various configuration options into account.
6+
Reverse a URL to the FAQ, taking various configuration options into account.
127
138
This is a compatibility function to allow django-fluent-faq to operate stand-alone.
149
Either the app can be hooked in the URLconf directly, or it can be added as a pagetype of *django-fluent-pages*.
1510
"""
16-
if _HAS_FLUENT_PAGES:
17-
return mixed_reverse(viewname, args=args, kwargs=kwargs, current_page=current_page, language_code=language_code, multiple=multiple, ignore_multiple=ignore_multiple)
18-
else:
19-
return reverse(viewname, args=args, kwargs=kwargs, current_app=current_app)
11+
return mixed_reverse(viewname, args=args, kwargs=kwargs, current_app=current_app, **page_kwargs)
2012

2113

2214
__all__ = (

fluent_faq/views.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
from django.conf import settings
22
from django.http import HttpResponsePermanentRedirect
33
from django.views.generic import DetailView, ListView
4+
from fluent_utils.softdeps.fluent_pages import CurrentPageMixin
45
from fluent_faq.models import FaqCategory, FaqQuestion
56
from parler.views import TranslatableSlugMixin
67

7-
if 'fluent_pages' in settings.INSTALLED_APPS:
8-
# Optional integration with fluent-pages features
9-
from fluent_pages.views import CurrentPageMixin
10-
else:
11-
# Simulate basic features for multilingual improvements!
12-
from parler.views import ViewUrlMixin
13-
class CurrentPageMixin(ViewUrlMixin):
14-
pass
15-
168

179
class FaqQuestionList(CurrentPageMixin, ListView):
1810
"""

0 commit comments

Comments
 (0)