Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: divio/django-cms
...
head fork: spookylukey/django-cms
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 3 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jan 03, 2012
@spookylukey spookylukey Improved efficiency of rendering plugins embedded in text plugins usi…
…ng bulk queries

This reduces the rendering of a text plugin with N embedded plugins from 3N
+ 1 queries to 3 queries.
ad773e0
View
40 cms/models/pluginmodel.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+import itertools
import os
import warnings
from datetime import datetime, date
@@ -61,8 +62,35 @@ def __new__(cls, name, bases, attrs):
new_class._meta.db_table = table_name
return new_class
-
-
+
+
+class CMSPluginManager(models.Manager):
+ def bulk_get(self, ids, with_instances=True, select_placeholder=True):
+ """
+ Retrieve a set of CMSPlugin objects, with their plugin model instances,
+ efficiently, and a return as dictionary of {pk:CMSPlugin object}.
+ """
+ from cms.plugin_pool import plugin_pool
+ objs = list(self.get_query_set().filter(id__in=ids))
+ retval = dict([(o.id, o) for o in objs])
+ if with_instances:
+ # group according to plugin_type, and retrieve the child objects in
+ # batches.
+ for plugin_type, parents in itertools.groupby(objs, lambda o: o.plugin_type):
+ parents = list(parents)
+ plugin_class = plugin_pool.get_plugin(parents[0].plugin_type)
+ q = plugin_class.model.objects.filter(id__in=[o.id for o in parents])
+ if select_placeholder:
+ q = q.select_related('placeholder')
+ children = list(q)
+ # Now match them up
+ children_parent_dict = dict([(o.cmsplugin_ptr_id, o) for o in children])
+ for parent in parents:
+ child = children_parent_dict[parent.id]
+ parent._instance = child
+ return retval
+
+
class CMSPlugin(MPTTModel):
'''
The base class for a CMS plugin model. When defining a new custom plugin, you should
@@ -88,7 +116,9 @@ class CMSPlugin(MPTTModel):
lft = models.PositiveIntegerField(db_index=True, editable=False)
rght = models.PositiveIntegerField(db_index=True, editable=False)
tree_id = models.PositiveIntegerField(db_index=True, editable=False)
-
+
+ objects = CMSPluginManager()
+
class Meta:
app_label = 'cms'
@@ -151,6 +181,10 @@ def get_plugin_instance(self, admin=None):
from cms.plugin_pool import plugin_pool
plugin_class = plugin_pool.get_plugin(self.plugin_type)
plugin = plugin_class(plugin_class.model, admin)# needed so we have the same signature as the original ModelAdmin
+
+ if hasattr(self, '_instance'):
+ return self._instance, plugin
+
if plugin.model != self.__class__: # and self.__class__ == CMSPlugin:
# (if self is actually a subclass, getattr below would break)
try:
View
11 cms/plugins/text/utils.py
@@ -38,12 +38,19 @@ def plugin_tags_to_user_html(text, context, placeholder):
context is the template context to use, placeholder is the placeholder name
"""
+ # Collect all the objects at once to minimize DB queries
+ plugin_ids = map(int, set(OBJ_ADMIN_RE.findall(text)))
+ plugin_objs = CMSPlugin.objects.bulk_get(plugin_ids,
+ with_instances=True,
+ select_placeholder=True)
+
+ # Now render and subsitute
def _render_tag(m):
plugin_id = int(m.groups()[0])
try:
- obj = CMSPlugin.objects.get(pk=plugin_id)
+ obj = plugin_objs[plugin_id]
obj._render_meta.text_enabled = True
- except CMSPlugin.DoesNotExist:
+ except KeyError:
# Object must have been deleted. It cannot be rendered to
# end user so just remove it from the HTML altogether
return u''
View
27 cms/tests/plugins.py
@@ -336,6 +336,33 @@ def test_inheritplugin_media(self):
response = self.client.get(page.get_absolute_url())
self.assertTrue('%scms/js/libs/jquery.tweet.js' % settings.STATIC_URL in response.content, response.content)
+ def test_render_textplugin(self):
+ # Setup
+ page = create_page("render test", "nav_playground.html", "en")
+ ph = page.placeholders.get(slot="body")
+ text_plugin = add_plugin(ph, "TextPlugin", "en", body="Hello World")
+ link_plugins = []
+ for i in range(0, 10):
+ link_plugins.append(add_plugin(ph, "LinkPlugin", "en",
+ target=text_plugin,
+ name="A Link",
+ url="http://django-cms.org"))
+ txt = text_plugin.text
+ txt.body = plugin_tags_to_admin_html(
+ '\n'.join(["{{ plugin_object %d }}" % l.cmsplugin_ptr_id
+ for l in link_plugins]))
+ txt.save()
+ text_plugin = self.reload(text_plugin)
+
+ # 1 query for Placeholder object (could be eliminated with select_related
+ # in the right place)
+ # 1 query for the CMSPlugin objects,
+ # 1 query for each type of child object (1 in this case, all are Link)
+ with self.assertNumQueries(3):
+ rendered = text_plugin.render_plugin(placeholder=ph)
+
+ self.assertTrue('A Link' in rendered)
+
def test_copy_textplugin(self):
"""
Test that copying of textplugins replaces references to copied plugins

No commit comments for this range

Something went wrong with that request. Please try again.