Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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. We Made the
    PyCon TW 2016 Website

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. Web Lead

    View Slide

  7. Not Web Lead

    View Slide

  8. େਓతݪҼʁ (ʉ㦝 ʉ )

    View Slide

  9. Me
    • Call me TP
    • Follow @uranusjr
    • https://uranusjr.com

    View Slide

  10. View Slide

  11. View Slide

  12. http://macdown.uranusjr.com

    View Slide

  13. www. .com

    View Slide

  14. View Slide

  15. PyCon APAC 2014
    PyCon APAC 2015

    View Slide

  16. PyCon TW 2016

    View Slide

  17. No More CMS
    • We are all programmers here
    • Redundant content separation
    • RDBS
    • Flat pages
    • Git is our content database

    View Slide

  18. 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

    View Slide

  19. Built to Last

    View Slide

  20. Dependency

    View Slide

  21. The web framework for perfectionists with deadlines.

    View Slide

  22. Third-party Apps
    • As few as possible
    • Django has more than you think
    • Easy to make simple solutions

    View Slide

  23. 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

    View Slide

  24. Test Coverage
    • I do hope it could be higher
    • Numbers can be misleading
    • Django is too declarative
    • Test the important parts first

    View Slide

  25. Testing
    • pytest-django
    • unittest.mock + pytest-mock
    • Travis CI
    • Codecov.io
    • Staging server (manual inspection)

    View Slide

  26. PYTEST IS AWESOME
    BECAUSE

    View Slide

  27. View Slide

  28. Content Management
    With Templates!

    View Slide

  29. # url(r'^(?P.*)/$', content_page)
    def content_page(request, path):
    template_path = '/'.join([
    CONTENT_TEMPLATE_PREFIX,
    request.LANGUAGE_CODE,
    path + '.html',
    ]
    return render(request, template_path)

    View Slide

  30. GET /events/keynotes/
    path = 'events/keynotes'
    template_path =
    'contents/events/keynotes.html'
    HttpResponse

    View Slide

  31. class TemplateExistanceStatusResponse(
    TemplateResponse):
    def resolve_template(self, template):
    try:
    return super().resolve_template(
    template=template,
    )
    except TemplateDoesNotExist:
    raise Http404

    View Slide

  32. Do It Yourself

    View Slide

  33. Markdown Support
    • You don’t need server-side rendering
    • One custom form widget is enough
    • Render with JavaScript

    View Slide

  34. View Slide

  35. 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(
    '\r\n'
    '{content}',
    attrs=flatatt(attrs),
    content=force_text(value),
    )

    View Slide

  36. 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.

    View Slide

  37. var nodeList = document.querySelector(
    'textarea[data-simplemde]');
    Array.prototype.forEach.call(nodeList, (e) => {
    new SimpleMDE({
    'element': e,
    // ... Whatever options you want.
    });
    });

    View Slide

  38. View Slide

  39. class EventInfo(models.Model):
    # ...
    detailed_description = models.TextField(
    verbose_name=_('detailed description'),
    blank=True,
    help_text=_(...),
    )
    # ...

    View Slide

  40. {% if object.detailed_description %}
    {% trans 'Description' %}


    {{ object.detailed_description }}


    {% endif %}

    View Slide

  41. var render = SimpleMDE.prototype.markdown;
    var els = document.querySelectorAll('.markdown');
    Array.prototype.forEach.call(els, function (e) {
    var source = e.textContent || e.innerText;
    e.innerHTML = render(source);
    });

    View Slide

  42. Character counter
    • Why not CharField(max_length=...)
    • Character-word ratio
    • Front-end user experience

    View Slide

  43. East Asian Width
    • Unicode Standard Annex #11
    • “Wide” and “narrow” characters
    • And ambiguous (not going there)

    View Slide

  44. Ken Lunde
    㼭卌⶛
    https://www.linkedin.com/in/kenlunde

    View Slide

  45. _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
    )

    View Slide

  46. http://d.hatena.ne.jp/takenspc/20111126

    View Slide

  47. 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);
    }

    View Slide

  48. Email-Based User
    • No idea where this came from
    • A lot copied from Symposion
    • Some of our own touch

    View Slide

  49. Internalisation

    View Slide

  50. 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)),
    ]

    View Slide

  51. https://tw.pycon.org/2016/zh-hant/events/talks/
    Chinese (Traditional)
    Matched URL path

    View Slide

  52. # This is in i18n_patterns(...).
    # url(r'^(?P.*)/$', content_page)
    def content_page(request, path):
    template_path = '/'.join([
    CONTENT_TEMPLATE_PREFIX,
    request.LANGUAGE_CODE,
    path + '.html',
    ])
    return render(request, template_path)

    View Slide

  53. Does English need
    translation?

    View Slide

  54. Yes!

    View Slide

  55. Translation
    • en or en-us?
    • Non-ASCII characters
    • English is not the base language

    View Slide

  56. 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)',
    }

    View Slide

  57. Translations
    locale/
    !"" _src/
    # !"" LC_MESSAGES/
    # $"" README.txt
    !"" en_US/
    # $"" LC_MESSAGES
    $"" zh_Hant/
    $"" LC_MESSAGES

    View Slide

  58. https://www.transifex.com/pycon-taiwan/pycon-tw-2016/

    View Slide

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

    View Slide

  60. GitHub
    git push
    Travis CI
    Trigger
    master?
    Transifex
    tx push
    Manual
    Translation
    tx pull
    Local
    Repository
    Some Remote
    Repository
    git push [no-ci]

    View Slide

  61. U+1F937 SHRUG (Unicode 9.0)

    View Slide

  62. Compatibility
    https://tw.pycon.org/2013/[en|ja|zh]/
    https://tw.pycon.org/2014apac/[en|ja|zh]/
    https://tw.pycon.org/2015apac/[en|ja|zh]/
    https://tw.pycon.org/2016/[en-us|zh-hant]/

    View Slide

  63. 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)

    View Slide

  64. # Settings.
    FALLBACK_LANS = {
    'zh': 'zh-hant',
    'en': 'en-us',
    }
    # For middleware.
    FALLBACK_PREFIX_PATTERN = re.compile(
    r'^/(?P{})(?:/?|/.+)$'.format(
    '|'.join(settings.FALLBACK_LANS.keys()),
    ),
    re.UNICODE,
    )

    View Slide

  65. Lessons Learnt

    View Slide

  66. If I Do This Again
    • Better code
    • Better dev-op
    • Better management

    View Slide

  67. 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!

    View Slide

  68. Better Dev-op
    • Transifex integration
    • Staging server for each branch
    • R/O production database mirroring?
    • Tighter production cycle

    View Slide

  69. 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?

    View Slide

  70. Next Steps

    View Slide

  71. So… 2017?
    • Start as early as possible
    • Do things upfront
    • Repeat as little as possible

    View Slide

  72. Sponsorship?

    View Slide

  73. pip install conferencekit
    * Does not work yet

    View Slide

  74. ⸈Ⰵ㉻⸈Ⰵ㉻⸈Ⰵ㉻⸈Ⰵ㉻⸈Ⰵ㉻
    ⸈Ⰵ㉻⸈Ⰵ㉻⸈Ⰵ㉻⸈Ⰵ㉻⸈Ⰵ㉻

    View Slide