This & that

Django et le frontend

Le samedi 21 mai 2016 j’ai présenté une session sur Django et le frontend où comment utiliser React/Redux (ou autres projets front) dans un projet Django de façon simple.

Vous pouvez voir les slides sur Speakerdeck et le code du projet est sur Github. Revoyons les grandes étapes de la mise en place.

Django

Installation de django-webpack-loader Ajout dans les settings des morceaux suivants

'webpack_loader' # INSTALLED_APPS

# Ajout du répertoire avec l'application
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'assets'),
)

Toutes les autres valeurs sont celles par défaut de django-webpack-loader.

Javascript

Sans répéter le code qui se trouve sur Github les étapes sont les suivantes:

N’hésitez pas à envoyer vos questions sur Twitter.

ReactEurope 2015 in Paris

ReactEurope just took place in Paris on July 2nd and 3rd, 2015.

It was a great occasion to meet the growing community and learn more about the React ecosystem. All 19 sessions plus lightning talk and panels were filled with great content.

There are a few things I found interesting in all the content:

React gives a great developer experience, is fun to work with and makes maintenance easier because components are easy to reason about, you can come back to to your code after a while and still understand it.

React-native has the potential to be a real game-changer for many domains. People can work on web, iOS or Android apps depending what they prefer using the same skills. I like the “learn-once, write anywhere” mantra.

React and its ecosystem may not apply to you but be sure to check it out before you dismiss it.

Interacting with mailchimp with django

I recently needed to interact with Mailchimp from a Django application.

After reading forums posts, looking at different options I ended up choosing the official Python package from Mailchimp. It lives on PyPi https://pypi.python.org/pypi/mailchimp. This package seemed to be the best option as it is up-to-date whereas alternatives like django-mailchimp-1.3 do not seem to be. I was also not sure which ones work with Mailchimp API v2.

One important thing to note is mailchimp python package code is generated and is not the most readable. All parameters are documented so with a bit of reading you can get most of what you need. Even though it is not as straightforward as it could.

A simple example to add a user to a mailing-list with additionnal merge vars looks like the following. Hopefully it will help and put you on the right track.

from django.conf import settings


def add_user_to_list(user):
    api_key = settings.MAILCHIMP_API_KEY

    try:
        m = mailchimp.Mailchimp(api_key)
    except ConnectionError:
        print "Cannot connect to Maichimp"
        return False

    try:
        m.helper.ping()
    except mailchimp.Error:
        print "Invalid API key"
        return False
    except ConnectionError:
        print "Cannot connect to Maichimp"
        return False

    merge_vars = {
        'FNAME': user.first_name
    }

    try:
        m.lists.subscribe(
            settings.MAILCHIMP_LIST_ID,
            {'email': user.email},
            merge_vars=merge_vars,
            double_optin=False
        )
    except (ListDoesNotExistError, EmailNotExistsError, ListAlreadySubscribedError) as e:
        print (
            "Cannot add user {0} to the list, an exception occured {1}".format(
                user, type(e).__name__
            )
        )

When adding a user you can pass the optionnal parameter double_optin, it avoids sending a confirmation email to the person asking for consent. As Mailchimp indicates you do not want to abuse this, so make sure you use it responsibly.

Django application with libsass-python, minification and compression on heroku

Now that the SEO title is out of the way, say you want to deploy a django app to Heroku. You also use SASS files and would like to use django-pipeline to manage the assets. You also want to use cssmin and uglifyjs to minify and compress your css and javascript files.

You would also prefer to not have to build on your machine and commit the files to your repository. You can always git reset but where is the beauty?

There are unfortunately not that many ressources on this subject. This post is an attempt to remedy that and will show one way it can be achieved.

So the goal is to have a django app deployed to heroku with SASS compiling using libsass-python, using django-pipeline, running cssmin and uglifyjs for production, all of that happening on the collectstatic step.

We will also host assets directly on the dyno thanks to whitenoise, and use cloudfront (or another CDN).

To achieve all of the above you will want to use the multi-buildpack feature. First we need the nodejs buildpack to have cssmin and uglifyjs and second we need the python buildpack for django and libsass-python.

Part 1 : Django

Create an empty directory and create a django app. You can use cookicutter for example.

cookiecutter https://github.com/pydanny/cookiecutter-django.git
# fill in the fields

You now have your sample project. You can add the necessary requirements for pip.

# add those to requirements/base.txt
whitenoise==1.0.6
libsass==0.6.2
django-pipeline==1.4.3

SASS

Configure pipeline by editing relevant files : #c0d9289. This is where you put the libsass configuration.

We use the sassc command-line tool provided by the project. This is fairly straightforward.

Part 2 : Heroku

Now we can move on to the heroku part proper. Create an app if you don’t have one.

Configure buildpack.

heroku config:set BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-multi.git

You then add a .buildpacks file to indicate which buildpack to use. We will use the nodejs one and a fork of the python one that forces pythonpath for collectstatic. When using the cookiecutter layout it is necessary to have the collectstatic command work.

You need to configure your STATIC_URL for production. If using django-configurations set it to a SecretValue, that way it has to be se as an environment variable.

STATIC_URL = values.SecretValue()

for example:

heroku config:set DJANGO_STATIC_URL=https://d11111.cloudfront.net/static/

Set other needed variables if you used the cookiecutter example project otherwise ignore.

heroku config:set DJANGO_SECRET_KEY=insert_key_here
heroku addons:add heroku-postgresql:dev
heroku pg:promote DATABASE_URL
heroku config:set DJANGO_CONFIGURATION=Production
heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME=example
heroku config:set DJANGO_AWS_ACCESS_KEY_ID=example
heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY=example
heroku config:set DJANGO_EMAIL_HOST_USER=example

To have whitenoise and pipeline work together you need to setup a custom storage that mixes all of them. For example you can use this django 1.7+ storage.

from django.contrib.staticfiles.storage import ManifestStaticFilesStorage

from whitenoise.django import GzipStaticFilesMixin

from pipeline.storage import PipelineMixin


class WhiteNoisePipeline(GzipStaticFilesMixin, PipelineMixin, ManifestStaticFilesStorage):
    pass

Change your settings to use this storage.

STATICFILES_STORAGE = 'heroku-libsass-python.storage.WhiteNoisePipeline'

Compression and minification

This is one of the most annoying bit to get working. This is needed because paths variables are not set yet in the build stage as far as I understood.

In order to get it working you need to use the following settings for production. In the cookie-cutter example it means editing the production.py.

    PIPELINE_UGLIFYJS_BINARY = 'PATH=/app/.heroku/node/bin:$PATH /app/node_modules/.bin/uglifyjs'

    PIPELINE_CSSMIN_BINARY = 'PATH=/app/.heroku/node/bin:$PATH /app/node_modules/.bin/cssmin'

Conclusion

Push to heroku and see the magic happen.

Your assets will be compiled, compressed, gzipped and have far-future expire headers. This will make your deployment workflow simpler. I am aware you can use a shell script or other means to achieve this I like the simplicity of this, even if the setup takes a bit of time.

You can find a sample git project : https://github.com/arnaudlimbourg/heroku-libsass-python

I hope this will be useful.