Category: Django
Blog upgraded to Django 1.2.1
My personal blog site has been upgraded to Django 1.2.1. For me, upgrading was a simple matter of running:
sudo easy_install http://media.djangoproject.com/releases/1.2/Django-1.2.1.tar.gz
Everything else seems to work fine after that, except that I had to change an import statement for email_re:
-from django.forms.fields import email_re +from django.core.validators import email_re
The regular expression is used for validating comment sender email addresess.
Update:
Also had to add CSRF support according to these instructions to make my custom comment form work.
Djangolle NoSQL-tuki Google Summer of Codessa
Tämä on mainio uutinen: Alex Gaynor kehittää tänä vuonna Djangon NoSQL-tukea Google Summer of Code -projektina. Sama kaveri väänsi viime vuoden GSoCissa Djangolle multi-db-tuen, jolla Django-webbisaitteja voi skaalata lisäämällä useita rinnakkaisia SQL-tietokantoja jakamaan kuormitusta. Se on tulossa ihan tuotantokäyttöön Django 1.2:ssa lähiviikkoina.
Djangon NoSQL-tuki, tai siis virallisesti Django-nonrel, ei ole ihan yksinkertainen asia ratkaistavaksi. Sen ongelmista keskusteltiin hiljattain Django Dosen podcastissa. On päätettävä mitä NoSQL-tietokantoja tuetaan, ja siinä taas ratkaisee se, millaisia indeksointi- ja hakuominaisuuksia kustakin löytyy.
Useimmille NoSQL-kannoille on yhteistä lähinnä key-value-store-ajattelu ja se, että valuet eli tietokannan datakentät voivat sisältää monimurkaisia tietorakenteita, eivätkä vain tiettyjä ennalta määriteltyjä sarakkeita kuten SQL:ssä. Mutta sitten taas tiedon indeksointia ja hakemista käsitellään hyvinkin eri tavoin.
Toistaiseksi Django-nonrel näyttää keskittyneen Google App Engine -tukeen, mutta itse toivoisin sen tukevan jatkossa myös Cassandraa ja ehkäpä CouchDB:täkin.
Salasanojen replikoiminen Djangoon
Django tallentaa normaalisti salasanat SHA1-hasheina, joissa on mukana myös 5-merkkinen salt. Mutta jos salasanoja replikoi jostain toisesta systeemistä Djangoon, ne voi tallentaa myös MD5-hasheina tai ilman salttia. Tämä tarkoittaa, että melkein mistä tahansa tyypillisestä web-pohjaisesta käyttäjärekisteristä on suhteellisen helppoa replikoida käyttäjätunnukset ja salasanat Djangoon.
Djangon itse luoma salasanakenttä näyttää tietokannassa suurin piirtein tältä:
sha1$abcde$9f228544172d611cbfb5b8c7111f51aac0a166ba
Kentässä on siis peräkkäin algoritmi (sha1), salt (abcde) ja itse hashi (9f228544172d611cbfb5b8c7111f51aac0a166ba) dollarimerkeillä eroteltuna.
Jos oletetaan, että legacy-järjestelmässä on käytetty pelkkää MD5-hashia ilman saltteja, niin siellä tietokantakenttään on tallennettu luultavasti jotain tällaista:
5f4dcc3b5aa765d61d8327deb882cf99
Tämä voidaan replikoida suoraan Djangoon kirjoittamalla salasanakenttä tietokantaan tässä muodossa:
md5$$5f4dcc3b5aa765d61d8327deb882cf99
Vanha salasana toimii nyt normaalisti sisäänkirjautumiseen. Kun salasanaa sitten joskus vaihdetaan, se korvautuu uudella SHA1-hashilla, jossa on salt mukana.
PS. Papukaijamerkki kaikille hakkereille, jotka osaavat päätellä tuosta, mitä salasanaa käytin esimerkeissä. ;-)
Markdown-tuki Djangon kommenteissa
Otin käyttöön blogissani Djangon markdown-tuen kommenteille. Testailen tässä yhteydessä niiden toimivuutta.
Linkkien esikatselu Djangossa
Leikin hieman python-webkit2png:llä ja tein kotisivujeni Shared Links -osioon esikatselun. Niistä linkeistä, joille esikatselukuva on generoitu, pitäisi kyseisen kuvan tulla näkyviin, kun vie hiiren linkin päälle.
Python-webkit2png käyttää Qt-kirjastoa ja WebKit-moottoria esikatselukuvan renderöintiin. Omat asetukseni generoivat kuvia 800x600 pikselin kokoisella virtuaaliselaimella, jossa ei ole Flashia eikä JavaScriptiä. Sen jälkeen kuvat pienennetään kokoon 400x300, mikä tekee niistä tällä hetkellä hieman kökön näköisiä.
Djangossa tämä operaatio ajetaan cronissa management commandina. Se käy läpi ne linkit, joilla ei vielä ole esikatselukuvaa, ja tallentaa uudet kuvat kunkin linkin ImageField-kenttään. Joillekin linkeille tämä epäonnistuu, koska asetin renderöinnin maksimiajaksi 60 sekuntia, ja maailmalta löytyy edelleen kovin raskaita saitteja, jotka eivät siinä ajassa kerkeä latautua kokonaan.
SQL-kyselyiden eliminoiminen Djangosta
Django-sovellus on suhteellisen helppoa rakentaa siten, että se lataa kaiken tarvittavan välimuistista, eikä tee ollenkaan SQL-tietokantahakuja. Omien datamallien lisäksi on kuitenkin huomioitava muutama Djangon sisäänrakennettu komponentti, jotka yrittävät väkisin tehdä SQL-hakuja. Ne voi eliminoida seuraavasti.
1. Välimuistittava authentication backend
Jos käyttäjä on kirjautunut sisään, Django kutsuu jokaisella hakupyynnöllä authentication backendin get_user()-funktiota. Normaalisti tämä lataa käyttäjän tiedot SQL-tietokannasta. Tietokantahaun voi välttää toteuttamalla oman backendin, joka osaa pitää tiedot välimuistissa esimerkiksi omaa kustomoitua User-mallia käyttäen.
#auth_backends.py from django.contrib.auth.backends import ModelBackend from myapp.profile.models import User class MyBackend(ModelBackend): def get_user(self, user_id): try: return User.objects.get_by_id(user_id) # uses cache except User.DoesNotExist: return None
Oma backend otetaan käyttöön asettamalla settings.py:ssä muuttuja AUTHENTICATION_BACKENDS = ('myapp.auth_backends.MyBackend',).
2. Oman User-mallin get_and_delete_messages()
Django tekee jokaisella hakupyynnöllä kirjautuneille käyttäjille vielä toisenkin SQL-haun tarkistaakseen onko auth_messages-taulussa uusia viestejä. Jos viestejä ei kaipaa omassa sovelluksessa, on helpointa toteuttaa omaan User-malliin tyhjä get_and_delete_messages()-metodi:
#models.py from django.contrib.auth.models import User as DjangoUser class User(DjangoUser): def get_and_delete_messages(self): return []
3. Site.objects.current_site() monkey-patch
Mikäli käyttää Djangon multi-site-ominaisuutta, tarvitsee usein oletussaittia, joka saadaan metodilla Site.objects.current_site(). Django pitää saittia muistissa Pythonin VM:ssä, mutta jos käytössä on useita palvelinprosesseja, kukin niistä joutuu erikseen hakemaan saitin tiedot kannasta. Tämän voi eliminoida pienellä monkey-patchilla, joka tallentaa saitin oikeaan välimuistiin:
from django.contrib.sites.models import Site from django.conf import settings from django.core.cache import cache _original_get_current = Site._default_manager.__class__.get_current def _caching_get_current(self): site = cache.get('Site:' + str(settings.SITE_ID)) if site is None: site = _original_get_current(self) cache.set('Site:' + str(settings.SITE_ID), site) return site Site._default_manager.__class__.get_current = _caching_get_current
Näillä muutoksilla Django ei enää tee lainkaan SQL-hakuja, ja koko HTTP-hakupyyntö voidaan palvella suoraan välimuistista.
Uusien kommenttien sähköposti-ilmoitukset
Koodasin tähän Django-pohjaiseen blogisysteemiini tuen sähköposti-ilmoituksille uusista kommenteista. Testailen niitä tämän artikkelin kommenteissa.