$30 off During Our Annual Pro Sale. View Details »

We Made the PyCon TW 2016 Website

We Made the PyCon TW 2016 Website

We are the PyCon Taiwan 2016 Web Team. All your PyCon Taiwan website are belong to us.

You probably have seen our website. In this talk, I will outline how it’s built—with Django, and how we collaborated with other teams in the PyCon Taiwan staff.

The PyCon Taiwan 2016 website is made from countless little gems. I will talk about how we approach this task, from the ground up: How we chose from existing solutions, customised components in it, and built additional functionalities on top of it. The talk will include topics on registration handling, running common tasks with Django utilities, adding generic Python modules, and using tools to simplify collaboration.

Oh, and did you submit a proposal? I hope so—Our proposal system is awesome! I’ll also tell you how we implemented the proposal-review process (sharing some secrets in the process).

Tzu-ping Chung

June 03, 2016
Tweet

More Decks by Tzu-ping Chung

Other Decks in Programming

Transcript

  1. No More CMS • We are all programmers here •

    Redundant content separation • RDBS • Flat pages • Git is our content database
  2. Make This the Last • Do we need a new

    site every year? • Less dependency = More time-proof • Did not make it — design mistakes :( • More on this later
  3. Third-party Apps • As few as possible • Django has

    more than you think • Easy to make simple solutions
  4. Tests • We don’t have very good tests • Not

    enough team discipline • Unit tests on important components • Make sure we don’t serve errors • Important for maintenance
  5. Test Coverage • I do hope it could be higher

    • Numbers can be misleading • Django is too declarative • Test the important parts first
  6. Testing • pytest-django • unittest.mock + pytest-mock • Travis CI

    • Codecov.io • Staging server (manual inspection)
  7. Markdown Support • You don’t need server-side rendering • One

    custom form widget is enough • Render with JavaScript
  8. class SimpleMDEWidget(forms.Textarea): class Media: css = {'all': ['simplemde.min.css']} js =

    ['simplemde.js', 'simplemde-setup.js'] def render(self, name, value, attrs=None): attrs = self.build_attrs(attrs, **{ 'name': name, 'data-simplemde': True, }) return format_html( '<textarea{attrs}>\r\n' '{content}</textarea>', attrs=flatatt(attrs), content=force_text(value), )
  9. <textarea cols="40" rows="10" id="id_xxx" name="xxx" data-simplemde> Rain artisanal range-rover girl

    wonton soup A.I. silent hacker sensory. Boy media advert systemic realism silent rain shoes range-rover receding plastic j-pop. Cartel Chiba tanto construct receding systemic saturation point market wristwatch stimulate pen jeans motion rifle. Car silent grenade tube meta-claymore mine tank- traps neural sign bicycle modem Shibuya media long-chain hydrocarbons.</textarea>
  10. {% if object.detailed_description %} <h2>{% trans 'Description' %}</h2> <div class="editor-readonly">

    <div class="editor-preview"> {{ object.detailed_description }} </div> </div> {% endif %}
  11. East Asian Width • Unicode Standard Annex #11 • “Wide”

    and “narrow” characters • And ambiguous (not going there)
  12. _EAW_LENS = { 'Na': 1, # Narrow - 1 'H':

    1, # Halfwidth - 1 'W': 2, # Wide - 2 'F': 2, # Fullwidth - 2 'N': 1, # Neutral - 1 'A': 2, # Ambiguous - 2 } from unicodedata import east_asian_width as eaw class EAWMaxLengthValidator(MaxLengthValidator): def clean(self, value): return sum( _EAW_LENS[eaw(c)] for c in value )
  13. function getCharacterCount(e) { var text = e.textContent || e.innerText; if

    (!text) { return 0; } text = text .replace(/^\s+|\s+$/g, '') .replace(/\r?\n/g, '\r\n')); return eastasianwidth.length(text); }
  14. Email-Based User • No idea where this came from •

    A lot copied from Symposion • Some of our own touch
  15. from django.conf.urls.i18n import i18n_patterns urlpatterns = i18n_patterns( url(r'^$', index, name='index'),

    # ... more URL patterns. ) urlpatterns += [ url(r'^set-language/$', set_language), url(r'^admin/', include(admin.site.urls)), ]
  16. # This is in i18n_patterns(...). # url(r'^(?P<path>.*)/$', content_page) def content_page(request,

    path): template_path = '/'.join([ CONTENT_TEMPLATE_PREFIX, request.LANGUAGE_CODE, path + '.html', ]) return render(request, template_path)
  17. Patching Django from django.conf import locale if 'en-us' not in

    locale.LANG_INFO: locale.LANG_INFO['en-us'] = { 'bidi': False, 'code': 'en-us', 'name': 'English (US)', 'name_local': 'English (US)', }
  18. Translations locale/ !"" _src/ # !"" LC_MESSAGES/ # $"" README.txt

    !"" en_US/ # $"" LC_MESSAGES $"" zh_Hant/ $"" LC_MESSAGES
  19. GitHub git push Travis CI Trigger master? Transifex tx push

    Manual Translation tx pull Local Repository
  20. GitHub git push Travis CI Trigger master? Transifex tx push

    Manual Translation tx pull Local Repository Some Remote Repository git push [no-ci]
  21. class LocaleFallbackMiddleware: def process_request(self, request): if not settings.USE_I18N: return match

    = FALLBACK_PAT.match(request.path_info) if not match: return lang = match.group('lang') fallback = settings.FALLBACK_LANS[lang] prefix = get_script_prefix() path = request.get_full_path().replace( prefix + lang, prefix + fallback, 1, ) return HttpResponsePermanentRedirect(path)
  22. # Settings. FALLBACK_LANS = { 'zh': 'zh-hant', 'en': 'en-us', }

    # For middleware. FALLBACK_PREFIX_PATTERN = re.compile( r'^/(?P<lang>{})(?:/?|/.+)$'.format( '|'.join(settings.FALLBACK_LANS.keys()), ), re.UNICODE, )
  23. If I Do This Again • Better code • Better

    dev-op • Better management
  24. Better code • Plan to throw (at least) one away

    • Migration can be messy • Can’t revert design decisions • Coding styles • Indentation (size and style) • Translation unit • Tests! More! Better!
  25. Better Dev-op • Transifex integration • Staging server for each

    branch • R/O production database mirroring? • Tighter production cycle
  26. Better Management • Time is a big problem • Need

    better cohesion • Who is available? • What can I do now? • Tight development cycle without too much managing — How?
  27. So… 2017? • Start as early as possible • Do

    things upfront • Repeat as little as possible