From German to English

After a long time with no activity and after migrating from blogspot to WordPress, I would like to announce the next change to this blog. I will try to switch from German (which is my mother language) to English blog posts, just out of two very similar reasons:

  1. Content reach
  2. Language improvement

First of, I know that there are maybe some German speaking techies that will be looking for German content that I will lose as my audience, but actually I assume that most people in IT are just looking for English content anyway, so it makes much more sense to switch to English for my posts.

Furthermore, my network of colleagues is far gone from being German only and in my job I use more English than German anyway. Actually it started to feel strange to write about coding topics in German, and lots of times I struggle translating specific words into German, so it seems to be only logical to stick with English completely.

I hope the (few) people that actually read my posts do not mind, and I hope I will in return start to post more frequently again.

Cordova – Windows 10 Build erstellen

  1. node.js installieren
  2. cordova installieren (npm install -g cordova)
  3. cordova windows herunterladen (https://www.apache.org/dist/cordova/platforms/)
  4. alle Dateien der cordova Applikation (Inhalt des www Ordners und config Datei) in den package Ordner von Cordova Windows verschieben
    (cordova-windows-*.*.*
    |_package
    |_  .cordova
    |_ www
    |_ config
    |_ …)
  5. Powershell öffnen und in den package Ordner wechseln
  6. cordova build windows –release –archs=x64 –appx=uap
  7. Unter platforms/windows/AppPackages den Ordner der App öffnen, APPX Datei doppelklicken und App installieren (oder .ps1 Skript ausführen)

Requirements

  • Microsoft Build Tools

Websocket Support für Django – Channels

Schon lange juckt es mich in den Fingern mal etwas mit Websockets zu machen. Ich habe mich bereits etwas in den Client Teil dazu eingelesen, aber auf Server Seite kam ich bisher noch nie dazu mich dem Thema wirklich anzunehmen.

Ich wusste dass es z.B. mit Java oder node.js guten Support für Websockets gibt, meine aktuellen Projekte liefen aber alle mit Django und dort konnte ich bisher nie irgendwas schlaues finden zu diesem Thema – bis jetzt!

Mit Hack Zurich vor der Tür kam ich mit einem Kollegen im Brainstorming auch eben wieder genau auf diese Websocket Thematik zu sprechen.

Angeregt vom Gespräch machte ich mich im Anschluss gleich daran zu recherchieren, was denn die komfortabelste serverseitige Lösung für Websockets wäre. Dabei kam ich wieder auf node.js und irgendwelche Java Implementationen.

Nun wollte ich es doch nochmals wissen, gab es tatsächlich keine Möglichkeit Websockets auch mit Django zu nutzen? Immerhin schimpft sich Django ein Webframework für Minimalisten mit Deadlines zu sein und Websockets sollten da doch wohl auch zur Ausstattung gehören?

Django Channels

Und siehe da! Scheinbar wurde erst auf der Pycon 2016 eine Lösung dafür präsentiert und zwar von keinem geringeren als Andrew Godwin, einem Core Entwickler von Django, der unter anderem auch für South (das Datenbank-Migrations-Tool von Django) verantwortlich war.

Kurzum: Godwin hat ein Projekt gestartet welches momentan noch nicht zum Django Core gehört, dies jedoch in Zukunft möglicherweise wird.

Alle Infos zum Projekt findet man auf https://channels.readthedocs.io

Ich versuche hier die wichtigsten Infos aus der Dokumentation zu wiedergeben. Für weitere Details lohnt sich ein Blick in die Doku selber.

Django Channels ist eine Django app, welche eine neue Ebene zu Django hinzufügt, die es erlaubt WebSockets zu verwalten. Die App teilt Django in zwei Prozess Typen:

  • Einer der HTTP und Websockets verwaltet
  • Einer der Views, Websocket Handlers und Hintergrundtasks ausführt (Consumer)

Diese Prozesse kommunizieren über ein Protokoll namens ASGI (Asynchronous Server Gateway Interface), welches ähnlich funktioniert wie WSGI (Web Server Gateway Interface), aber über ein Netzwerk läuft und weitere Protokoll Typen erlaubt.

Was ist ein Channel?

Das Herzstück des Systems ist eine Datenstruktur namens channel. Es ist eine geordnete First-In-First-Out (FIFO) Queue mit message expiry (Nachrichten Verfall) bei der Nachrichten höchstens einmal zugestellt werden und zwar nur an einen Listener aufs Mal.

Channels werden nach Producer / Consumer Pattern genutzt, wie eine Task Queue. Der Producer schickt eine Nachricht an den Channel und werden dann von nur einem der wartenden Consumer abgeholt.

Innerhalb eines Netzwerks werden Channels über einen Namen identifiziert. Schreiben mehrere Maschinen in einen Channel mit demselben Namen, so schreiben sie in denselben Channel.

Gruppen

Channels sind immer nur zwischen zwei Maschinen (One to One) Deshalb braucht man Gruppen um gleichzeitig mehrere Maschinen zu bedienen. Es ist möglich mehrere Channels in einer Gruppe zusammenzufassen.

Channel Implementationen

Es gibt verschiedene Channel Implementationen die verwendet werden können. Standardmässig wird die in-memory Variante verwendet. Diese speichert ganz einfach alle Daten in einem dict im Memory und ist deshalb auch nicht cross-process fähig. Das funktioniert deshalb eigentlich nur im runserver Modus.

Eine Variante für das produktive Umfeld mit cross-process Unterstützung ist das Redis Backend asgi_redis.

Dieses muss zuerst installiert

pip install asgi_redis

und danach konfiguriert werden

# In settings.py
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "asgi_redis.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("localhost", 6379)],
        },
        "ROUTING": "myproject.routing.channel_routing",
    },
}

Wie nutzen wir Channels?

Es gibt bereits einige gute Tutorials wie man mithilfe von Channels in kurzer Zeit eine eigene Chat Applikation bauen kann:

An Introduction to WebSockets

Quellen / weitere Infos

http://www.html5rocks.com/en/tutorials/websockets/basics/

MySQL Wochennummer Liste

MySql Skript zur Erstellung einer Wochennummer Tabelle

Da je nach Datenbank, Programmiersprache, Systemeinstellungen die Wochennummern verschieden gezählt werden können, ist es üblich bei Anwendungen welche Einträge auf Wochenbasis bearbeiten / planen müssen, eine Tabelle mit Einträgen zu erfassen, welche die Wochennummern, Start- und Enddatum eines oder mehrerer Jahre beinhalten. Um dies vereinfacht zu machen und nicht alles manuell einzugeben, habe ich ein SQL Skript für MySQL erstellt, welches für ein gewisses Intervall (maximal ca. 300 Jahre), ebendiese Informationen ausgibt.

SELECT week_no, 
       year_no, 
       first_date, 
       last_date 
FROM  (SELECT WEEKOFYEAR(selected_date)                                     AS 
              week_no 
                    , 
              CASE 
                WHEN YEAR(SUBDATE(selected_date, INTERVAL WEEKDAY(selected_date) 
                                                 day)) 
                     != YEAR 
                     ( 
                            ADDDATE(selected_date, 
                            INTERVAL 6-WEEKDAY(selected_date) 
                            day)) 
                     AND WEEKOFYEAR(SUBDATE(selected_date, 
                                    INTERVAL WEEKDAY(selected_date) day 
                                    )) != 1 THEN YEAR(SUBDATE(selected_date, 
                INTERVAL WEEKDAY(selected_date) day)) 
                ELSE YEAR(ADDDATE(selected_date, 
                          INTERVAL 6-WEEKDAY(selected_date) day 
                          )) 
              end                                                           AS 
              year_no 
                    , 
              SUBDATE(selected_date, INTERVAL WEEKDAY(selected_date) 
                                     day)   AS first_date, 
              ADDDATE(selected_date, INTERVAL 6-WEEKDAY(selected_date) day) AS 
                    last_date 
       FROM   (SELECT * 
               FROM   (SELECT ADDDATE('1970-01-01', T4.i * 10000 + T3.i * 1000 + 
                                                    T2.i * 100 + 
                                                            T1.i * 10 + 
                              T0.i) selected_date 
                       FROM   (SELECT 0 i UNION 
                               SELECT 1 UNION 
                               SELECT 2 UNION 
                               SELECT 3 UNION 
                               SELECT 4 UNION 
                               SELECT 5 UNION 
                               SELECT 6 UNION 
                               SELECT 7 UNION 
                               SELECT 8 UNION 
                               SELECT 9) T0, 
                              (SELECT 0 i UNION 
                               SELECT 1 UNION 
                               SELECT 2 UNION 
                               SELECT 3 UNION 
                               SELECT 4 UNION 
                               SELECT 5 UNION 
                               SELECT 6 UNION 
                               SELECT 7 UNION 
                               SELECT 8 UNION 
                               SELECT 9) T1, 
                              (SELECT 0 i UNION 
                               SELECT 1 UNION 
                               SELECT 2 UNION 
                               SELECT 3 UNION 
                               SELECT 4 UNION 
                               SELECT 5 UNION 
                               SELECT 6 UNION 
                               SELECT 7 UNION 
                               SELECT 8 UNION 
                               SELECT 9) T2, 
                              (SELECT 0 i UNION 
                               SELECT 1 UNION 
                               SELECT 2 UNION 
                               SELECT 3 UNION 
                               SELECT 4 UNION 
                               SELECT 5 UNION 
                               SELECT 6 UNION 
                               SELECT 7 UNION 
                               SELECT 8 UNION 
                               SELECT 9) T3, 
                              (SELECT 0 i UNION 
                               SELECT 1 UNION 
                               SELECT 2 UNION 
                               SELECT 3 UNION 
                               SELECT 4 UNION 
                               SELECT 5 UNION 
                               SELECT 6 UNION 
                               SELECT 7 UNION 
                               SELECT 8 UNION 
                               SELECT 9) T4) V 
               WHERE  selected_date BETWEEN '2016-01-01' AND '2239-12-31') DATES 
      ) 
      WDATES 
GROUP  BY year_no, 
          week_no, 
          first_date, 
          last_date 
ORDER  BY year_no, 
          week_no

Django Admin – Objekte filtern für Nicht-Superuser

Für eine Django Webapplikation welche ich gerade momentan entwickle, möchte ich für den ersten Beta Release den Usern direkt Django Admin als Benutzeroberfläche für die Dateneingabe zur Verfügung stellen.

Filtern in der Listenansicht

Allerdings soll jeder User (abgesehen von Superusern) nur die Objekte bearbeiten können, welche seiner Organisation zugehörig sind. Um diese Relation von User zu Organisation herzustellen habe ich ein weiteres Model namens ‚Person‘ erstellt, welches eine OneToOne Relation auf einen User, sowie einen ForeignKey auf eine Organisation besitzt.

Die Methode ‚get_queryset‘ welche die im Django Admin sichtbaren Objekte definiert, kann nun ungefähr folgendermassen angepasst werden um dies zu bewerkstelligen:

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(MyModelAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        elif hasattr(request.user, 'person'):
            return qs.filter(organisation=request.user.person.organisation)
        else:
            return []

Filtern in der Detailansicht

Dasselbe wollte ich natürlich auch in der Detailansicht haben. Es soll zum Beispiel nicht möglich sein, dass ein User der Organisation X einen neuen Eintrag für die Organisation Y erstellen kann. Dazu muss man irgendwie die angezeigten Auswahlmöglichkeiten beim ForeignKey Feld eingrenzen.

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "organisation":
            if request.user.is_superuser:
                # no limitations for superusers
                pass
            elif hasattr(request.user, 'person'):
                # for users of an organisation, return only their organisation
                kwargs["queryset"] = Organisation.objects.filter(organisation=request.user.person.organisation)
            else:
                # for anyone else, return empty queryset
                kwargs["queryset"] = []
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

Quellen:

 

TensorFlow Installation auf Windows

TensorFlow ist eine Machine Learning Library von Google, welches diese Woche der Öffentlichkeit zugänglich gemacht wurde, um den Austausch über das Thema anzuregen und ein einheitliches Werkzeug und bewährtes Werkzeug anzubieten. Die Library ist für C, C++ sowie für Python verfügbar und mit sämtlichen Linux Systemen kompatibel.

Die Installation unter Windows wird offiziell nicht unterstützt. Die einfachste Variante es dennoch unter Windows nutzen zu können, ist mit Hilfe von Docker. Die Installation mit Docker ist ganz simpel:

docker run -it b.gcr.io/tensorflow/tensorflow-full

Quelle: TensorFlow – Get Started

Docker installieren auf Windows

Docker ist die Virtualisierungssoftware der Stunde. Es scheint als ob sie gerade überall verwendet wird und so ist es an der Zeit sich einmal hier auf dem Blog damit auseinander zu setzen. Wer Docker nicht kennt, dem sei nahegelegt, sich auf der offiziellen Docker Seite kurz durch „What is Docker“ durchzulesen.

Kurz zusammengefasst könnte man wohl sagen, Docker ist eine Virtualisierungslösung für leichtgewichtige Entwicklungsumgebungen ohne unnötigen Ballast. Im Unterschied zu herkömmlichen virtuellen Maschinen enthalten die sogenannten Container allerdings wirklich nur Applikationsdaten und teilen sich einen gemeinsamen Kernel, d.h. sie benötigen kein eigenes Betriebsystem.

Docker Aufbau
VirtualMachine Aufbau (z.B. VMWare, Hyperview, Virtualbox..)

Installation unter Windows

Quelle: Install Docker for Windows

 Um Docker unter Windows zu installieren, wird ein

  1. Windows Version prüfen
    Docker for Windows setzt mindestens Windows 7.1 voraus. Ich habe es bei mir unter Windows 10 installiert und das ging auch ohne Probleme.
  2. Hardware Virtualisierung aktivieren
    Unter Windows 8 und 10 kann man im Task Manager unter dem Performance Tab nachschauen ob dies bereits aktiviert ist. Falls nicht müsst ihr euch bei eurem Laptophersteller erkunden wie ihr das aktivieren könnt. In der Regel findet sich dafür eine Einstellung im BIOS.
  3. Docker Toolbox installieren
    Während der Installation von Docker wird auch VirtualBox installiert. Darin läuft danach die Docker Engine. Falls Virtualbox auf eurem System bereits installiert ist, versichert euch dass ihr es nicht durch Docker re-installiert und dass Virtualbox nicht im Hintergrund läuft während der Installation.
    1. Docker Toolbox Installer laden und Installation durchführen
  4.  Installation überprüfen
    1. Im Startmenü sollte nun im Docker Ordner der Menüpunkt „Docker Quickstart Terminal“ vorhanden sein. Dieses starten wir nun. Im Hintergrund wird dadurch die Docker Toolbox eingerichtet (unter anderem wird eine virtuelle Maschine in Virtualbox angelegt für die Docker Engine).
    2. Sobald der Quickstart Terminal fertig durchgelaufen ist, sollte das Terminal auf Eingabe warten. Um zu schauen ob alles läuft, laden wir uns den Hello World Container und starten ihn:
      docker run hello-world
      Wenn alles geklappt hat solltet ihr folgende Meldung sehen:

Wie weiter? 

  • Docker Images laden und Container erstellen
  • Mit dem GUI herumspielen (Kitematic)
  • TensorFlow Container aufsetzen?

Woocommerce – Falsche Steuerberechnung auf Gutschein

Seit dem Update auf Woocommerce 2.3.11 (eventuell sogar noch länger), gab es bei mir im Shop Probleme mit der Darstellung der Gutscheinbeträge auf den Bestellungen im WordPress Backend.
Und zwar wurden die Gutscheinbeträge stets abzüglich der MwSt (8%) angezeigt.
Wäre also ein Gutschein von Fr. 10.- auf einer Bestellung verwendet wordern, wurde mir im Backend stattdessen Fr. 9.20 als Gutscheinbetrag angezeigt.

Dieses Problem liess sich beheben durch das Deaktivieren der Option „Steuern und Berechnung aktivieren“, im „Mehrwersteuer“ Tab der Woocommerce Einstellungen.

Deaktivieren von „Steuern und deren Berechnung aktivieren“

Bei bestehenden Bestellungen kann der Wert danach mit einem Klick auf „Steuern berechnen“ korrigiert werden.

„Steuern berechnen“ klicken zum Korrigieren des Gutscheinbetrages

Weitere Infos zu Gutscheinen und Steuern: