![](static/hkis-home.png)

::: notes

Remercier ceux qui nous hébergent.

# HackInScience

<!-- .slide: data-background="static/background.jpg" -->

## Hackinscience

<br/>

<b>Julien Palard</b>

<tt>Paris.Py #16</tt>


## Julien Palard

- Python core dev / freelance
- CPython documentation translator (french only)
- Python teacher/coach, at
  - Makina Corpus
  - Center for Research and Interdisciplinarity
  - Sup'Internet
  - …

julien@python.org, @sizeof, https://mdk.fr


# HackInScience

Back in 2015, we started a project with the CRI of Paris Descartes: A
one-week intensive Python class.  ![](descartes-and-cri.jpg)

::: notes

"The Center for Research and Interdisciplinarity" en anglais.

- Ouvert à tous : élèves de l'université, chercheurs, public.


## Pedagogy

We were aiming for 50 students per week, so we had to adapt,
we needed:

- A short Python introduction (slides and a teacher).
- Lots of exercises, sorted by difficulty.
- A bot to correct exercises, live.
- 2 to 3 highly available teachers in the room.
- Short optional lessons about very specific topics.
- Rules, teaching best practices.

::: notes

Rules like: never touch a student keyboard: they're here to learn.


## 2015: Focus on content

We started by focusing on exercises (needed to give a course) and the
correction bot (needed to scale).

Workflow from a student point of view:

- Clone the exercise repo
- Do exercises
- git push
- Receive a mail with the correction

::: notes

It was crude, but it worked.

We automated exercises corrections (like exercises unit tests) using a
Python script.


## 2016: Focus on confort

Antoine Angot developped a website so students do no longer needed to
use git. Emails were no longer needed, which is nice too.

::: notes

Thx bro!

Turns out that teaching git took a lot of time over teaching Python...

And emails were easily marked as spam even with SPF and DKIM configured properly.


## 2017: Focus on content, again

The year to enhance existing parts, to rely on them, this is also the
year of... many repositories:

- One for the website
- One for the exercises (markdown files)
- One for our internal documentation
- One for the correction bot
- One for the ansible playbook

::: notes

Exercises had a check.py and a solution.py

Internal documentation == teaching best practices.


## 2018: Migrating to Django

Jérôme Schneider started to migrate the website to Django.<br/>
(So we could modify it more easily.)


::: notes

Thx bro :)
A nice part was templates: the syntax was almost the same.


# Show me the code!

So what is it now? 181 lines of Python (first fully working version), it
should fit in a few slides ;)

::: notes

Today it's more like 700 lines of code, mainly little tweaks
and personalisation.


# Django models

```python
class Exercise(models.Model):
    title = models.CharField(max_length=255)
    check = models.TextField()
    solution = models.TextField()
    wording = models.TextField()
```

::: notes

Already know Django? Focus on the content.


## Django models

Helps in generating:

- DB migrations;
- Admin pages;
- Forms;
- Views (Using class-based views);
- API (Using DRF);
- Queries ("ORM" as humans say).

::: notes

A Django Model makes the code aware of the database structure.

- Autocompletion
- ...


# Django view

```python
class ExerciseListView(LoginRequiredMixin, ListView):
    model = Exercise
    template_name = "hkis/exercises.html"

```

::: notes

How to read this Mixin thing?

Read: ExerciseListView inherite first from LoginRequiredMixin, then on ListView.
So LoginRequiredMixin can place its method before ListView, like intercepting them.


## Django view


![](static/hkis-exercises.png)


## Django view

```python
class ExerciseView(LoginRequiredMixin, DetailView):
    model = Exercise
    template_name = "hkis/exercise.html"

    def get_context_data(self, **kwargs):
        """Add student answers.
        """
        context = super().get_context_data(**kwargs)
        context["answers"] = self.object.answers.filter(
            user=self.request.user
        ).order_by("-id")
        return context
```

## Django view

![](static/hkis-exercise.png)


# Need an API now

```python
class ExerciseSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Exercise
        fields = '__all__'

class ExerciseViewSet(viewsets.ModelViewSet):
    queryset = Exercise.objects.all()
    serializer_class = ExerciseSerializer

router = routers.DefaultRouter()
router.register('exercises', ExerciseViewSet)
```

::: notes

Why DRF use a router? Because there's many views in a ViewSet.

## Need an API now


![](static/hkis-api.png)

::: notes

A nice feature: The API replies with HTML when asked for, so
it's browsable using a web browser.


# Need an admin interface now

```python
from django.contrib import admin
from website.models import Answer, Exercise

admin.site.register(Answer)
admin.site.register(Exercise)
```

## Admin interface

![](static/hkis-admin.png)

## Admin interface

![](static/hkis-admin-markdown.png)

::: notes

We're using markdown to redact exercises.

## Admin interface

![](static/hkis-admin-check.png)

::: notes

This is the Python script used to check an exercise.


# We need lives updates, now!

So when a student submit an answer, he gets a correction as soon as possible.

We can use `Django Channels` for this.


## Django Channels

Need first to setup some kind of high level router:

```python
application = ProtocolTypeRouter(
    {"websocket": AuthMiddlewareStack(
        URLRouter(website.routing.websocket_urlpatterns))}
)
```

and

```python
websocket_urlpatterns = [
    url(
        r"^ws/answers/(?P<user_id>[0-9]+)/(?P<exercise_id>[0-9]+)/$",
        consumers.AnswerConsumer,
    )
]
```

## Django Channels

Note the `ws/` prefix, it's usefull once in production:

- nginx → gunicorn, for HTTP
- nginx → daphne, for websockets


## Django Channels


We're disambiguating it nginx side:

```
location /ws {
    proxy_pass http://unix:/run/hkis-website/daphne.sock;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}

location / {
    proxy_pass http://unix:/run/hkis-website/website.sock;
    proxy_set_header Host $host;
}
```

# The future

Display exercises as a tree, with subjects like datascience, web,
low-level, and so on as group of leafs of the tree.

::: notes

So one could navigate to its preferred subject.


# Questions?

- julien@python.org
- Twitter: @sizeof
- IRC: mdk on #python-fr (freenode)
- https://mdk.fr
- https://hackinscience.org
