Python web frameworkök
összehasonlítása
Django
összehasonlítása
Programozási paradigmák
Imperatív
Objektum orientált
Deklaratív
Clean Architecture
Előnyök
- Egyértelműen leírja a téma nyelvtanát,
ún. domain-jét (beléptető rendszerek)
minden mástól függetlenül
- Üzleti logika teljesen el van szeparálva,
könnyebb rajta módosítani
- Sokkal rugalmasabb lesz a kód
- UI bármikor kicserélhető
- Sokkal könnyebben tesztelhető automatikus tesztekkel
Hátrányok
- Hosszabb ideig tart megírni?
- Több kód?
Példa Entities
class Ticket(object):
def __init__(self, price, valid_until):
self.price = price
self.valid_until = valid_until
def is_valid(self):
return datetime.now() <= valid_until
class Zone(object):
def __init__(self, name):
self.name = name
self.persons = []
def __contains__(self, person):
return person in self.persons
def exit_person(self, person):
self.persons.index(person)
del self.persons[person_index]
class Person(object):
def __init__(self, name, age, ticket):
self.name = name
self.ticket = ticket
@property
def shortname(self):
return self.name[:10]
@property
def full_name(self):
return self.first_name + self.middle_name + self.last_name
def has_ticket(self):
return self.ticket is not None
Példa Use Cases
def enter_person(zone, person):
if person.has_ticket() and person.ticket.is_valid():
zone.persons.append(person)
def exit_person(zone, person):
if person in zone:
zone.exit_person(person)
if person.has_zsigmondy_kartya():
say_something_ridiculous()
def check_entry(zone, person):
return (person.age > 18 and
person.has_ticket() and
zone.max_persons > zone.persons)
Django
Főbb jellemzők
- Batteries included
- Big framework (86k LOC)
- Erősen objektum orientált szemléletű
- Komponensei nem szétválaszthatók
- Óriási community, sok pénz van mögötte
- Rock solid, stabil
- Brutális dokumentáció, minden egy helyen
- Rugalmatlan (pl. PostgreSQL-el érdemes használni)
Batteries
- konfiguráció
- URL routing
- Templating
- ORM
- Form kezelés
- admin felület
- i18n, l10n
- GeoDjango (PostgGIS)
- User authentikáció, authorizáció
Konfiguráció
settings.py, globális
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'officecontrol',
'HOST': '192.168.224.24',
'PASSWORD': 'jelszo',
}
}
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'anteus.ticketcontrol',
'anteus.parkcontrol',
)
LANGUAGE_CODE = 'hu-hu'
TIME_ZONE = 'Europe/Budapest'
USE_I18N = True
USE_L10N = True
USE_TZ = True
URL routing
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
regex --> függvény
URL routing
from django.conf.urls import url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^about/', TemplateView.as_view(template_name="about.html")),
]
regex --> Class Based View
Class Based View példa 2
class ImageDetailView(BreadCrumbMixin, generic.DetailView):
model = WebGroup
template_name = 'image.html'
context_object_name = 'web_group'
def get_context_data(self, **kwargs):
context = super(ImageDetailView, self).get_context_data(**kwargs)
context['image_ext'] = self.object.image.split('.')[-1].lower()
return context
regex --> Class Based View
from django.conf.urls import url
from myapp import views
urlpatterns = [
url(r'^termekkep/(?P<pk>.*)/(?P<slug>.*)/$', views.ImageDetailView.as_view()),
]
Templating
{% extends "base.html" %}
{% block title %}
{{ block.super }} - Bejelentkezés
{% endblock title %}
{% block content %}
<div class="row login">
<div class="row">
<div class="col-md-offset-2 col-md-6">
{% if form.errors %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger"> {{ error }} </div>
{% empty %}
<div class="col-md-offset-3 alert alert-danger">Hiba!</div>
{% endfor %}
{% elif user.is_authenticated %}
<div class="col-md-offset-3 alert alert-info"> Bejelentkezhet egy másik Felhasználónévvel. </div>
{% else %}
<div class="col-md-offset-3 alert alert-warning"> A megtekintéshez bejelentkezés szükséges! </div>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-2">
<form method="post" action="{% url 'login' %}" class="form-horizontal login" role="form">
{% csrf_token %}
{# Mivel az anchor nem kerül küldésre a szerver felé (RFC 1808) #}
{# JavaScripttel kinyerem az url-ből és hozzácsatolom a beküldött GET['next'] részhez. #}
<script type="text/javascript">
document.write("<input type=\"hidden\" name=\"next\" value=\"{{ request.GET.next }}" + window.location.hash + "\">");
</script>
{% include "form_fields/_input.html" with field=form.username type="text" %}
{% include "form_fields/_input.html" with field=form.password type="password" %}
<div class="form-group">
<div class="col-sm-offset-3 col-sm-5">
<div class="checkbox">
<label>
<input type="checkbox" name="remember_me"> Maradjak bejelentkezve
</label>
</div>
</div>
<div class="col-sm-4">
<button type="submit" class="btn btn-primary">Bejelentkezés</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock content %}
ORM
- Active Record pattern
- Támogatott adatbázisok:
MySQL, PostgreSQL, SQLite, Oracle - Mindenféle típust kezel
- Leginkább egyszerű CRUD műveletekre való,
de az utóbbi években sokat fejlődött - Automatikus migrációk
- Form generálás modellekből
ORM model példa
from django.db import models
class Menu(models.Model):
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
name = models.CharField(max_length=100, blank=True)
descr = models.TextField(blank=True)
fullname = models.CharField(max_length=100, blank=True)
ord = models.IntegerField(blank=True, null=True)
image = models.CharField(max_length=100, blank=True)
ord_tree = models.CharField(max_length=100, blank=True)
image_thumbnail = models.BinaryField(blank=True, null=True)
meta_keyword = models.TextField(blank=True)
meta_title = models.TextField(blank=True)
meta_descr = models.TextField(blank=True)
text_top = models.TextField(blank=True)
text_bottom = models.TextField(blank=True)
to_upload_image = models.NullBooleanField()
objects = WebMenuManager()
not_empty = NotEmptyWebMenuManager()
class Meta:
managed = False
db_table = 'web_menu'
verbose_name = 'Menü'
verbose_name_plural = 'Menük'
ordering = ['ord_tree']
Automatikus adatbázis migráció
- Migráció is a kód része
- teljesen automatikus
(kitalálja a változásokat) - bármelyik fejlesztő egyetlen paranccsal képest létrehozni a legutolsó adatbázis állapotot
Migráció példa
from django.db import models
class Ticket(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
from django.db import models
class Ticket(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
comment = models.TextField(blank=True)
Migráció demo
Modularitás:
appok
Teljesen elkülöníthető minden részük:
- template
- url
- modelek
- migrációk
- stb.
App létrehozás példa
$ manage.py startapp ticketcontrol
$ tree ticketcontrol [10:54:41]
ticketcontrol
├── __init__.py
├── admin.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
1 directory, 6 files
Admin felület
- Modellekből automatikusan generált
- Minden típust ismer
- Konfigurálható, Testre szabható
- Nem a felhasználónak való!
(kb. Config-nak felel meg) - Automatikus szűrők
- Bulk operations
Internationalization (i18n)
Preparing the software for localization. Usually done by developers.
Localization (l10n)
Writing the translations and local formats. Usually done by translators.
i18n és l10n
- szövegek többnyelvűsítése
- dátumok, számok formázása az adott ország konvencióinak megfelelően
- időzónák kezelés
- GNU gettext toolsettel (.po)
kód példa, template példa - lazy translation
(konkrét elérés vs hívás)
GeoDjango
geographic Web framework
User authentikáció
Global típusú, azaz fel lehet venni mindenféle jogosultságot és azt ellenőrizni
(row level szintű jogosultságkezelés nem lehetséges vele mint Pyramid-nál)
de vannak hozzá csomagok még rugalmasabb jogosultság kezelésre
Példa kód
Pyramid
Főbb jellemzők
- Some batteries
- Legrugalmasabb framework mind közül
- Közepes méretű (37k LOC)
(nem micro, de Djangonál jóval kisebb) - Hosszú múlt, nagyon jó minőségű kód
- Gyors
(bizonyos részei C-ben íródtak,
pl. nincs paraméter átadás overhead) - Kicsi, de nagyon aktív és tapasztalt community
Bővíthetőség
- Teljesen különálló részek
https://xiaonuogantan.wordpress.com/2011/12/24/pyramid-vs-django/
Hello world
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
return Response('Hello %(name)s!' % request.matchdict)
if __name__ == '__main__':
config = Configurator()
config.add_route('hello', '/hello/{name}')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
Flask
Főbb jellemzők
- Pluginezhető
- Microframework (2,5k LOC)
- Sok plugin, de ezek sokszor gyenge minőségűek,
vagy nincsenek karban tartva
Hello world
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
Python web frameworkök
By Kiss György
Python web frameworkök
- 225