Schnelle Iteration mit Django & Heroku

Die Gründung eines Online-Geschäfts kann sich als äußerst kompliziert erweisen. Obwohl es auf dem Papier einfacher ist, ein Online-Geschäft zu gründen, als ein stationäres Geschäft, kann sich ein Unternehmer in einer Vielzahl von Optionen verlieren. Einige der häufigsten Fallstricke, in die ein Online-Unternehmer steckt, sind:

  • Zu viel zu früh bauen: Zeit verlieren und Geld verbrennen, um ein kompliziertes Produkt aufzubauen. Werden Sie demotiviert, verlieren Sie den Glauben an das Produkt und verlassen Sie das Projekt.
  • Zu viel an die Idee glauben: Bei der ursprünglichen Idee bleiben und nicht iterieren, obwohl die Kunden nicht auftauchen, nicht zahlen oder nicht zufrieden sind.
  • Starten nicht möglich: Wenn jemand mit dem Aufbau eines Webprojekts beginnt, kann er / sie von den scheinbar unendlichen Entscheidungen und Entscheidungen, die getroffen werden müssen, überwältigt werden. Was für ein Hosting? Welche Plattform? Welches WordPress-Theme? Wie baue ich eine Landing-Page mit hohem Conversion-Wert? Welche Programmiersprache und welche Datenbank? Sollten Sie ein Webframework verwenden? Vanilla JavaScript oder jQuery für das Frontend? Vielleicht ein komplexeres Frontend-Framework, da das Projekt eines benötigt, sobald es ausgereift ist?
  • Starten fehlgeschlagen: Beim Erstellen eines Webprojekts können Sie, obwohl Sie sich für Ihren Technologie-Stack entschieden haben, überwältigt sein von den Rückmeldungen, die Sie erhalten. Es ist unabsichtlich ein Fehler, zu viel Feedback zu hören. Es kann das Feedback von Leuten sein, die Ihr Produkt sowieso nicht verwenden würden. Menschen neigen dazu, eine Meinung über alles zu haben, auch wenn sie sich in diesem Bereich nicht vollständig auskennen.

Angesichts der Vielzahl von Möglichkeiten, die man auf der Straße versagen kann, ist es wichtig,

  • Bauen Sie so wenig und so schnell wie möglich auf und zeigen Sie es den Menschen, die Sie als potenzielle Kunden betrachten: Kosten und Aufwand minimieren.
  • Setzen Sie es so schnell wie möglich online: Holen Sie sich Feedback von Menschen zum Produkt, nicht zu Ihrer abstrakten Idee.
  • Nehmen Sie schnell Änderungen vor: Wenn Sie lernen möchten, was der Kunde will, ist es wichtig, dass Sie agil sind und Ihren ersten zahlenden Kunden gute Dienste leisten.

Hier setzt Prototyping an. Ein Unternehmer sollte schlank arbeiten und keine Zeit und Ressourcen verschwenden. Am Anfang so wenig wie möglich zu bauen, kann sich als Tugend erweisen. 

Es gibt viele Denkrichtungen darüber, was ein Prototyp ist und wie er erstellt werden sollte. Einige sagen, dass es nur eine Landing Page sein sollte, andere, dass es eine abgespeckte Version des Endprodukts sein sollte. Ich bin eher ein Fan der Sekunde. Wenn Sie nur eine Zielseite verwenden, kann sich das als unangenehm empfinden. Außerdem erhalten Sie keine Rückmeldung, wie Sie das Problem lösen, sondern nur, wenn das Problem es wert ist, es zu lösen.

Hier ist der Toolbelt eines Smart-Prototyping-Online-Unternehmers:

  • Front-End-Frameworks: Bootstrap, Foundation, jQuery, Vue usw. Durch die Verwendung eines Front-End-Frameworks können Ihre Apps auf verschiedenen Bildschirmgrößen und verschiedenen Browsern mit einem anständigen Design ausgeführt werden.
  • Backend-Frameworks: Django, Ruby on Rails, Laravel. Die Verwendung von Back-End-Frameworks erleichtert Ihnen den Umgang mit HTML-Vorlagen, HTTP-Formularen, Datenbankzugriff, URL-Schemata usw..
  • Plattform-als-Service: Heroku, Google App Engine, AWS Elastic Beanstalk. Die Auswahl eines PaaS-Systems kann Sie von der Verwaltung von Servern, der Protokollaggregation, der Überwachung der Betriebszeit, der Bereitstellungsinfrastruktur und mehr lösen.

In diesem Lernprogramm erstellen wir eine einfache Anwendung im Sinne von Rapid Prototyping. Wir werden Django, Bootstrap CSS und Heroku verwenden. Der Fokus liegt auf dem Backend-Teil und nicht auf dem Frontend. 

Wir werden die Heroku-Plattform nutzen, um etwas früh online zu stellen und neue Funktionen schnell bereitzustellen. Wir werden Django verwenden, um komplexe Datenbankmodelle und Funktionen zu erstellen. Bootstrap CSS gibt uns einen sinnvollen Standardstil für unsere Seiten. Genug geredet, lass uns gehen.

Was wir bauen

Stellen Sie sicher, dass Sie sich für diesen einen Platz nehmen. Die Idee wird Ihre Socken abschrecken. Hier ist die Neigung: Hassen Sie nicht einfach, wie Sie all diese Rabattcodes erhalten, aber Sie vergessen sie zu verwenden und sie verfallen? 

Wäre es nicht cool, die Codes an einem Ort zu speichern, an dem Sie sie suchen können und auch benachrichtigt werden, wenn sie ablaufen? Ich weiß, tolle Idee, richtig? Nun, legen Sie Ihre Kreditkarte aus, Sie werden nicht in diese investieren. Du wirst es bauen.

Fertig machen

In diesem Tutorial werde ich Python 3 verwenden. Wenn Sie Python 2.7 verwenden, sollten die Änderungen relativ einfach sein. Ich gehe auch davon aus, dass Sie damit vertraut sind Setuptools, Python-Virtualenvs und Git. Eine weitere Sache, bevor Sie fortfahren: Stellen Sie sicher, dass Sie über einen GitHub- und einen Heroku-Account verfügen. Um Heroku verwenden zu können, müssen Sie auch die Heroku-CLI installieren. 

Beginnen wir mit der Erstellung einer Virtualenv:

$ mkvirtualenv Coupy

Wie Sie wahrscheinlich herausgefunden haben, lautet unser Anwendungsname Coupy. Wechseln wir zur neuen virtualenv, $ workon Coupy, und installiere Django: 

$ pip installieren Django

Gehen Sie in Ihr GitHub-Konto und erstellen Sie ein neues Projekt. Als nächstes lass uns das Projekt klonen:

$ git clone https://github.com//.git $ cd 

Der nächste logische Schritt ist das Erstellen eines Django-Projekts. Um ein Django-Projekt in Heroku zu implementieren, müssen wir einige Richtlinien befolgen. Glücklicherweise können wir dafür eine Projektvorlage verwenden. So geht's:

$ django-admin.py startproject --template = https: //github.com/heroku/heroku-django-template/archive/master.zip --name = Procfile - Coupy

Möglicherweise müssen Sie sich in einigen Ordnern bewegen. Stellen Sie sicher, dass Ihr Repository-Stammordner folgendermaßen aussieht:

. ├── Procfile ├── README.md ├── Coupy ├── __ __init__.py ├──. Einstellungen.py ├── ├── statisch │ │ └── Menschen.txt │ urls.py ├── ── wsgi.py ├── manage.py ├── Requirements.txt └── Laufzeit.txt

Lassen Sie uns nun die Anforderungen der Vorlage installieren:

$ pip install -r Requirements.txt

Wir möchten nun die neu erstellten Dateien auf GitHub übertragen:

$ git add. $ git commit -m "Init Django-Projekt" $ git Push-Ursprungsmaster

Mal sehen, ob das, was wir bisher gemacht haben, funktioniert:

$ python manage.py runserver

Öffnen Sie nun ein Browserfenster und gehen Sie zu http: // localhost: 8000. Wenn alles gut ist, sollten Sie die klassische Django-Begrüßungsseite sehen. Um sicherzustellen, dass aus Sicht von Heroku alles gut ist, können wir die Anwendung auch so ausführen:

$ heroku lokales web

Um zu beweisen, wie schnell wir online gehen können, machen wir unsere erste Bereitstellung bei Heroku:

$ heroku login $ heroku erstellen

Wir haben jetzt eine Heroku-Anwendung erstellt, aber wir haben keinen Code an Heroku gesendet. Beachten Sie, dass Heroku eine benutzerfreundliche App-ID erstellt hat. Hier ist die Ausgabe, die Sie erhalten sollten:

App erstellen… fertig, ⬢  https: //.herokuapp.com/ | https://git.heroku.com/.git

Jetzt müssen wir unser Repo mit der neu erstellten Heroku-App verknüpfen:

$ heroku git: remote -a  $ git Push Heroku Meister $ Heroku offen

Toll, Sie haben gerade eine App für Heroku bereitgestellt. Es macht nicht viel, aber Sie stellen etwas in Rekordzeit online. Gut gemacht.

Einrichten der Datenbank

Sie werden wahrscheinlich niemals eine nicht triviale Web-App ohne Datenbank erstellen. Die Datenbank ist der Datenspeicher der Web-App. Hier behält die Web-App ihren Status (zumindest den Großteil davon). Hier führen wir die Benutzerkonten und die Anmeldedaten und vieles mehr. Heroku bietet einen verwalteten PostgreSQL-Dienst. 

Das werden wir verwenden. Stellen Sie sicher, dass Sie Postgres auf Ihrem Computer installiert haben, und erstellen Sie eine Datenbankinstanz, die in unserer Anwendung verwendet werden soll. Heroku benötigt eine Umgebungsvariable, um eine Verbindung zum Datenbankdienst herzustellen. Die Variable, die wir setzen müssen, ist DATABASE_URL:

$ export DATABASE_URL = "postgres: //:@localhost: 5432 /"

Lassen Sie uns nun Django sagen, dass er die Migrationen anwenden und die erforderlichen Tabellen erstellen soll:

$ ./manage.py migrieren

Erstellen Sie einen Superuser und melden Sie sich an der Administrationsoberfläche unter http: // localhost: 8000 / admin an.

$ ./manage.py erstellt den Superuser $ ./manage.py-Runserver

Wir können sehen, dass die Tabellen tatsächlich erstellt wurden. Heroku hat Ihrer App bereits standardmäßig eine Datenbankinstanz zugeordnet. Sie können sicherstellen, dass dies der Fall ist, indem Sie Heroku einchecken HEROKU_APP_ID> Einstellungen> Konfigurationsvariablen in Ihrer Heroku Online-Konsole. Sie sollten hier sehen, dass die DATABASE_URL ist auf eine von Heroku generierte Datenbankadresse gesetzt. 

Wir müssen jetzt die Migrationen ausführen und die Super User-Befehle online erstellen. Mal sehen, ob alles wie erwartet funktioniert:

$ heroku run python manage.py migrieren $ heroku run python manage.py erstellt Superuser

Wenn alles gut gegangen ist, wenn wir besuchen https: //.herokuapp.com/admin/, Wir sollten in der Lage sein, sich mit den gerade angegebenen Anmeldeinformationen anzumelden.

Benutzerauthentifizierung

In diesem Abschnitt werden wir eine Django-App initialisieren und vordefinierte Django-Komponenten verwenden, um die Benutzerauthentifizierungsfunktion in unserer App zu erstellen.

$ ./manage.py startapp main

In der neuen App erstellen wir eine urls.py Datei:

importiere URL aus django.conf.urls aus django.contrib.auth importiere Ansichten als auth_views aus django.views.generic.base import RedirectView urlpatterns = [url ('^ $', RedirectView.as_view (url = 'login'), name = "index"), URL (r '^ login $', auth_views.LoginView.as_view (), name = "login"), URL (r '^ logout $'), auth_views.LogoutView.as_view (), name = " Ausloggen"), ] 

Hier verwenden wir drei generische Django-Ansichten:

  • RedirectView: Da die Basis-URL der Anwendung nichts tut, leiten wir zur Anmeldeseite weiter.
  • LoginView: Vordefinierte Django-Ansicht, die das Anmeldeformular erstellt und die Benutzerauthentifizierungsroutine implementiert.
  • LogoutView: Django-vordefinierte Ansicht, die einen Benutzer abmeldet und auf eine bestimmte Seite umleitet.

Ergänzen Sie die Main Anwendung auf die INSTALLED_APPS Liste:

INSTALLED_APPS = ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', # Deaktivieren der eigenen statischen Dateien von Django zugunsten von WhiteNoise, für # größere Konsistenz zwischen gunicorn und './manage.py runserver'. Siehe: http://whitenoise.evans.io/de/stable/django.html#using-whitenoise-in-development 'whitenoise.runserver_nostatic', 'django.contrib.staticfiles', 'main',]

Schließen Sie das an main.urls zum Stamm-URL-Schema:

von der Import-URL von django.conf.urls, von der Import-URL von django.contrib import admin urlpatterns = [url (r '^', include ('main.urls')), url (r '^ admin /', admin.site.urls.) ),]

Um die Formulare mit Stilen, Klassen und allem anderen richtig anzuzeigen, müssen wir sie installieren django-widget-tweaks:

$ pip install django-widget-tweaks $ pip einfrieren> Anforderungen.txt

Hinzufügen django-widget-tweaks zu INSTALLED_APPS:

INSTALLED_APPS = [#… 'main', 'widget_tweaks',]

Wir fügen nun diese beiden Konfigurationen hinzu einstellungen.py:

  • LOGIN_REDIRECT_URL: Teilt Django mit, wohin ein Benutzer nach erfolgreicher Authentifizierung umgeleitet werden soll.
  • LOGOUT_REDIRECT_URL: Teilt Django mit, wohin der Benutzer nach dem Abmelden weitergeleitet werden soll.
# settings.py LOGIN_REDIRECT_URL = 'Dashboard' LOGOUT_REDIRECT_URL = 'Anmeldung'

Lassen Sie uns eine einfache Vorlagenvorlage schreiben base.html und ein dashboard.html Vorlage, die es erweitert. Wir kommen später zurück zum Dashboard.

     % block title% % endblock%   
% block content% % endblock%
% erweitert 'base.html'% % block title% Dashboard % endblock% % block content% 

Instrumententafel

% endblock%

Schreiben Sie die Ansicht, in der das dargestellt wird dashboard.html Vorlage:

von django.shortcuts import rendern von django.core.urlresolvers importieren reverse_lazy @login_required (login_url = reverse_lazy ('login')) def Dashboard (request): return render (request, 'dashboard.html')

Wir sind fertig. Gehe rüber zu http: // localhost: 8000 / login / und testen, dass die Authentifizierung funktioniert. Als nächstes speichern Sie Ihren Fortschritt:

$ git add. $ git commit -m "Login / Logout / Dashboard-Ansichten"

Erstellen Sie das Coupon-Modell

Jetzt haben wir den wichtigsten Teil unserer Anwendung, das Coupon-Modell, entworfen. Wir werden installieren Django-Modell-Utensilien um unseren Modellen zusätzliche Eigenschaften zu verleihen.

$ pip install django-model-utils $ pip einfrieren> Anforderungen.txt

Schreiben Sie die Coupon Modell:

aus model_utils.models importieren TimeStampedModel, TimeFramedModel aus django.db importieren Modelle aus django.contrib.auth.models importieren Benutzerklasse Coupon (TimeStampedModel, TimeFramedModel): owner = models.ForeignKey (User) discount_code = "Discount Code" , max_length = 100) website = models.URLField ("Website") description = models.TextField ("Coupon-Beschreibung")

Das Django-Modell-Utensilien Modelle, die wir erweitert haben, ermöglichen uns:

  • TimeStampedModel hilft uns zu verfolgen, wann das Modell in der Datenbank abgelegt wurde erstellt Feld.
  • TimeFramedModel fügt das hinzu Start und Ende Felder zu unserem Modell. Wir verwenden diese Felder, um die Verfügbarkeit des Gutscheins zu verfolgen.

Haken Sie das Modell an den Admin:

von django.contrib import admin von .models import Coupon @ admin.register (Coupon) Klasse CouponAdmin (admin.ModelAdmin): pass

Migrationen erstellen und anwenden:

$ ./manage.py makemigrations $ ./manage.py migrieren

Fortschritt speichern:

$ git add. $ git commit -m "Coupon-Modell erstellen"

ModelForm für die Couponerstellung

Eine der coolsten Funktionen von Django ist die Möglichkeit, Formulare aus Modellklassen zu erstellen. Wir werden ein solches Formular erstellen, mit dem Benutzer Gutscheine erstellen können. Lass uns einen erstellen forms.py Datei in der Main Anwendung:

von django.forms import ModelForm von .models import Coupon-Klasse CouponForm (ModelForm): Klasse Meta: Modell = Coupon exclude = ('owner',) # Dieses Feld setzen wir selbst

Fügen Sie dieses Formular dem Dashboard hinzu. Wir müssen sowohl die Ansicht als auch die Vorlage ändern:

# views.py aus django.shortcuts import rendern, von django.core.urlresolvers umleiten importieren reverse_lazy aus .forms import CouponForm @login_required (login_url = reverse_lazy ('login')) def Dashboard (request): if request.method == ' POST ': form = CouponForm (request.POST) if form.is_valid (): coupon = form.save (commit = False) coupon.owner = request.user coupon.save () gibt die Weiterleitung ("Dashboard") zurück: else: form = CouponForm () gibt das Rendern zurück (Anfrage, 'dashboard.html', context = 'create_form': form)
% erweitert 'base.html'% % load widget_tweaks% % block title% Dashboard % endblock% % block content% 

Instrumententafel

% csrf_token%
% render_field create_form.discount_code placeholder = "Rabattcode"%
% render_field create_form.website placeholder = "Website"%
% render_field create_form.description placeholder = "Description"%
% render_field create_form.start placeholder = "Verfügbar ab (MM / TT / JJJJ)"%
% render_field create_form.end placeholder = "Verfällt am (MM / TT / JJJJ)"%
% endblock%

Wir haben jetzt eine Möglichkeit, Gutscheine über das Dashboard zu erstellen. Probier es aus. Wir haben keine Möglichkeit, die Gutscheine im Dashboard zu sehen, aber im Admin-Panel. Speichern wir den Fortschritt:

$ git add. $ git commit -m "Formular zur Erstellung von Gutscheinen im Dashboard"

Bald auslaufende Gutscheine

Eine weitere Sache möchten wir im Dashboard angezeigt werden: Coupons, die bald ablaufen, zum Beispiel solche, die diese Woche ablaufen.

Hinzufügen django.contrib.humanize zu INSTALLED_APPS um Datumsangaben in den Vorlagen auf eine benutzerfreundliche Weise anzuzeigen.

Lassen Sie uns die Ansicht so verbessern, dass die bald auslaufenden Coupons abgerufen und an den Vorlagenkontext übergeben werden:

from datetime import timedelta from django.contrib.auth.decorators import login_required from django.shortcuts import render, umleiten von django.core.urlresolvers import reverse_lazy von django.utils importieren timezone von .forms import CouponForm from .models import CouponForm aus = reverse_lazy ('login')) def Dashboard (Anforderung): expiring_coupons = Coupon.objects.filter (end__gte = timezone.now (), end__lte = timezone.now () + timedelta (days = 7)) if request.method = = 'POST': form = CouponForm (request.POST) if form.is_valid (): coupon = form.save (commit = False) coupon.owner = request.user coupon.save () gibt die Weiterleitung ("Dashboard") zurück : form = CouponForm () return render (Anfrage, 'dashboard.html', context = 'create_form': form, 'expiring_coupons': expiring_coupons)

Lassen Sie uns die Vorlage so aktualisieren, dass die auslaufenden Coupons tabellarisch angezeigt werden. Das Erstellungsformular und die Tabelle werden mit Hilfe des Bootstrap-Rastersystems in zwei separate Spalten eingefügt:

% erweitert 'base.html'% % load widget_tweaks% % load humanize% % block title% Dashboard % endblock% % block content% 

Instrumententafel

[Der Formularcode]
% if expiring_coupons% % für Coupon in expiring_coupons% % endfor%
Rabattcode Webseite Ablaufdatum
coupon.discount_code coupon.website coupon.end | naturalday
% else%
Keine Coupons, die bald auslaufen
% endif% % endblock%

Gut aussehen. Speichern Sie Ihren Fortschritt:

$ git add. $ git commit -m "Auslaufende Couponliste implementieren"

Katalogansicht

Lernen Sie jetzt einige weitere Django-Verknüpfungen, um eine Ansicht zu erstellen, in der die Liste der verfügbaren Gutscheine angezeigt wird. Wir reden über generische Ansichten. So erstellen Sie schnell eine Listenansicht:

# views.py #… aus django.views.generic.list importiere ListView aus django.db.models importiere Q-Klasse CouponListView (ListView): model = Coupon def get_queryset (self): Gib Coupon.objects.filter zurück (Q (end__gte = timezone.now ()) | Q (end__isnull = True)). order_by ('- end')

Binden Sie nun die Ansicht in Ihr URL-Schema:

# main / urls.py aus django.conf.urls importiere URL aus django.contrib.auth importiere Ansichten als auth_views aus django.views.generic.base importiere RedirectView aus .views import Dashboard, CouponListView urlpatterns = [url ('$ $' , RedirectView.as_view (url = 'login'), name = "index"), url (r '^ login / $'), auth_views.LoginView.as_view (), name = "login"), url (r '^ logout) / $ ', auth_views.LogoutView.as_view (), name = "logout"), URL (r' ^ Dashboard / $ ', Dashboard, name = "Dashboard"), URL (r' ^ catalog / $ ', CouponListView. as_view (template_name = 'catalogue.html'), name = "catalog"),]

Erstellen Sie die Vorlage catalogue.html:

% erweitert 'base.html'% % load humanize% % block title% Katalog % endblock% % block content% 

Katalog

% if object_list% % für Gutschein in object_list% % endfor%
Rabattcode Webseite Ablaufdatum
coupon.discount_code coupon.website coupon.end | naturalday
% else%
Noch keine Gutscheine Erstellen Sie hier Ihren ersten.
% endif% % endblock%

Da wir alles angeschlossen haben, gehen Sie zu http: // localhost: 8000 / catalog / um Ihren Gutscheinkatalog anzusehen.

Speichern Sie den Fortschritt:

$ git add. $ git commit -m "Katalogansicht erstellen"

Dies ist ziemlich nahe an einem MVP. Ich möchte Sie dazu ermutigen, einige Feinabstimmungen vorzunehmen, z. B. das Erstellen einer Navbar, das Anmelden / Abmelden / Registrieren von Schaltflächen usw. Das Wichtigste ist, dass Sie den Prozess des Prototypens verstehen und Ihr Produkt für die Nutzer sichtbar machen. Apropos, unser Produkt ist noch nicht online. Wir haben die neueste Version nicht auf Heroku übertragen. Lass uns das tun und dann das Telefon abnehmen und die Investoren anrufen.

Fazit

Wir haben eine einfache, aber praktische Anwendung geschaffen. Wir haben Funktionen schnell erstellt und online bereitgestellt, damit unsere potenziellen Kunden sie nutzen und uns Feedback geben können. Es ist besser, den Leuten zu zeigen, als nur über eine Idee zu reden. 

Hier einige Schlussfolgerungen, die wir ziehen können:

  • Die Auswahl der richtigen Tools kann den Entwicklungsprozess erheblich beschleunigen.
  • Die Werkzeuge für das Prototyping sind nicht immer die beste Wahl für ausgereiftere Projekte. Wenn Sie dies berücksichtigen, ist es besser, frühzeitig mehr agile Tools zu verwenden und sie zu durchlaufen, anstatt sich in den kleinsten Implementierungsdetails frühzeitig zu verlieren.
  • Die Nutzung eines PaaS bedeutet, dass die Anwendungen einige Designmuster berücksichtigen müssen. Normalerweise machen diese Muster Sinn und zwingen uns, noch besseren Code zu schreiben.
  • Django hat viele Abkürzungen, die uns das Leben erleichtern:
    • Django ORM hilft beim Datenbankzugriff. Sie müssen sich keine Gedanken darüber machen, ob Sie korrektes SQL schreiben und bei Syntaxfehlern besonders vorsichtig sind.
    • Migrationen helfen uns bei der Version und beim Durchlaufen des Datenbankschemas. Sie müssen nicht SQL schreiben, um Tabellen zu erstellen oder Spalten hinzuzufügen.
    • Django hat eine Plugin-freundliche Architektur. Wir können Apps installieren, mit denen wir unsere Ziele schneller erreichen können.
    • Generische Ansichten und Modellformulare können einige der häufigsten Verhaltensweisen enthalten: Auflisten von Modellen, Erstellen von Modellen, Authentifizierung, Umleitung usw..
  • Beim Starten ist es wichtig, schlank und schnell zu sein. Verschwenden Sie keine Zeit und geben Sie kein Geld aus.