#30563: Optimize django.forms.widgets.Media.__add__.
--------------------------------------+------------------------------------
     Reporter:  David Dorothy         |                    Owner:  nobody
         Type:  Cleanup/optimization  |                   Status:  new
    Component:  Forms                 |                  Version:  master
     Severity:  Normal                |               Resolution:
     Keywords:  media                 |             Triage Stage:  Accepted
    Has patch:  0                     |      Needs documentation:  0
  Needs tests:  0                     |  Patch needs improvement:  0
Easy pickings:  0                     |                    UI/UX:  0
--------------------------------------+------------------------------------

Comment (by David Dorothy):

 I apologize for my delay in responding to this. I had to switch tasks for
 a little while to a different project that took a bit longer than
 intended.

 I have done some further research into this issue and have some
 information based on the actual use. I have 194016 Media objects that are
 being added together.  For the JavaScript references when the lists are
 de-duplicated in the way you describe above (in `__add__` not in `merge`)
 the list is trimmed to 13 records. CSS is handled differently and I'm not
 sure it is correct (see code later in this comment). This provides a
 performance on my machine of around 3-5 seconds. This is not as fast as my
 original optimization but is definitely close enough.

 As far as sharing code, I cannot give you access to my repository.
 However, I can show you the code where the adding of Media objects is
 occurring at.

 First, here is my attempt at improving the `Media.__add__` method:

 {{{#!python
 def combine_css(destination, css_list):
     for x in filter(None, css_list):
         for key in x.keys():
             if key not in destination:
                 destination[key] = OrderedSet()
             for item in x[key]:
                 if item:
                     destination[key].add(item)


 class ImprovedMedia(forms.Media):

     def __add__(self, other):
         combined = ImprovedMedia()
         combined._css_lists = list(filter(None, self._css_lists +
 other._css_lists))
         css_lists = {}
         combine_css(css_lists, self._css_lists)
         combine_css(css_lists, other._css_lists)
         combined._css_lists = [css_lists]

         combined._js_lists = list(OrderedSet([tuple(x) for x in
 filter(None, self._js_lists + other._js_lists)]))
         return combined
 }}}

 I am concerned that my `combine_css()` function may not be the best
 implementation because it does keep order but it always results in exactly
 one new `self._css_lists` which may not be the correct solution. I don't
 think I have enough context to know for sure if this is right. Also, I
 have some reservations about how I use `OrderedSet` for `Media._css_lists`
 because in my initial attempts on the `Media._js_lists` I had to convert
 the `OrderedSet` back into a `list` to make things work.

 Second, here is the code where the `__add__` method is called:

 {{{#!python
 class StructuredStreamBlock(StreamBlock):
     js_classes = {}

     # ...

     def all_media(self):
         media = ImprovedMedia()
         all_blocks = self.all_blocks()
         for block in all_blocks:
             media += block.
         return media

     # ...
 }}}

 The original code can be found in wagtail's source code here:
 
https://github.com/wagtail/wagtail/blob/e1d3390a1f62ae4b30c0ef38e7cfa5070d8565dc/wagtail/core/blocks/base.py#L74

 Unfortunately I could not think of a way to monkey patch the Media class
 in Django without actually changing the Django code in my virtual
 environment.

 Should I attempt at this point to create a fork and a branch (and
 hopefully eventually a pull request) and see if the change I make break
 any existing tests or should some others with more familiarity weigh in on
 this first?

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30563#comment:5>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.f0e95627feb7779ca573c5730aad8121%40djangoproject.com.

Reply via email to