30 lis 2008

blip, curses i dynamiczna podmiana kodu w pythonie

W związku z poniedziałkiem zacząłem się zastanawiać, czy nie lepiej poszukać konsolowej metody na blipanie. Coby blipa odpalić pod konsolą w domu, połączenie via ssh, coby mi nikt w pakiety nie zaglądał.
Ponieważ ^leafnode powiedział, że napisać klienta blipa w curses to dwie godziny, a za mną od dawna chodziło poprawienie mojej innej cursesowej aplikacyjki (tej), aka zobaczenie co w curses możnaby nowego poznać, zakasałem rękawy i napisałem coś.
Owo coś miało bugi, nie umiało czytać polskich literek w obiekcie curses.textpad.Textbox, więc trzeba było coś poprawić. Skończyło się na zajrzeniu do źródełem modułów curses.textpad i curses.ascii i dynamicznej podmianie dwóch funkcji w moim kodzie. A oto co zrobiłem:

wyświetlanie polskich liter w Textboksie


Textbox korzysta z funkcji zdefiniowanych w module curses.ascii żeby rozpoznać, co za znak mu wklepaliśmy. Wyświetlane są znaki, dla których funkcja isprint(c) zwraca True. A jak to sprawdza?

def isprint(c): return _ctoi(c) >= 32 and _ctoi(c) <= 126

Bóóó.
Polskie literki, jako nienależące do podstawowych znaków ascii nie nadały się do tego.
Zapytałem o radę na stackoverflow.com. Zgodnie z sugestią tam w moim kodzie zdefiniowałem funkcję:

def isprint(ch):
try:
x = unicodedata.category(chr(ch).decode('iso-8859-2'))[0] in 'LNPS'
if x or (curses.ascii._ctoi(ch) >= 32 and curses.ascii._ctoi(ch) <= 126):
return True
except:
pass
return False
curses.ascii.isprint = isprint # WOW!!

Ostatnia linijka dynamicznie podmienia fukcję zdefiniowaną zupełnie gdzie indziej na moją. Dzięki czemu, bez ingerencji w źródło oryginalnego modułu (bo naprawdę nie wiem co moje rozwiązanie może popsuć na dłuższą metę) możemy modyfikować zachowanie tegoż.
Teraz już wpisywanie polskich literek zaczęło działać.

odczyt z pola Textbox


mnie trochę zaskoczył. W trakcie wołana jest fukcja curses.ascii.ascii, która w oryginale wygląda tak:

def ascii(c):
if type(c) == type(""):
return chr(_ctoi(c) & 0x7f)
else:
return _ctoi(c) & 0x7f

W jej wyniku moje wpisane w pole tekstowe 'ą' było zwracane jako '1'.
Bóó again.
No ale wystarczyło znów dokonać podmiany w moim kodzie na coś prostszego:

def asci(ch):
if type(ch) == type(""):
return chr(curses.ascii._ctoi(ch))
else:
return curses.ascii._ctoi(ch)
curses.ascii.ascii = asci

...i naprawdę nie wiem co w ten sposób popsułem, ale wolę nie myśleć. W każdym razie teraz 'ą' jest zwracane jako 'ą'.

I tym samym

blipCurses pozwala wysyłać polskie literki:)


To tytułem ogłoszenia.
Tutaj można pobrać blipcursesa i nawet zobaczyć screena!

Enjoy it as I do.

27 lis 2008

[pomysł] nie-ma-mnie.pl

nie-ma-mnie.pl

  1. Osochozi?
    prosta idea - jak np wyjezdzamy na urlop / zaszywamy sie pod stertą liści i nie mamy ochoty sprawdzać i odpowiadac na kretyńskie maile - ustawiamy autoresponder że nas nie ma. Do autorespondera wrzucamy linka "żeby skontaktowac sie ze mna naprawde pilnie, kliknij ".
    Ten link prowadzi do strony z formularzem kontaktowy, gdzie gosc wpisuje kto on i co chce (maks np 100 znakow) i klika "wyślij". Ta wiadomość trafia do nas via sms i już decydujemy co robić dalej (bo może to byc wiadomosć naprawde pilna, ktorej nie chcielbysmy przegapic).
  2. Jak?
    Uzytkownik sie rejestruje, podaje w szczególności imie, numer telefonu oraz podaje godziny w jakich chce dostawac smsy (jako zakres, whatever). Dostaje link do swojego formularza kontaktowego, na przyklad /kontakt/kender.
  3. I co dalej?
    Jak ktos kliknie w linka, dostaje formularz (pewnie zabezpieczony jakims captcha i z limitem ilosci wysylanych wiadomosci per cookie per dzień). Chodzi o to, żeby wysyłający wiadomosc nie musial się rejestrować ani nic.
    Wysyłane wiadomości trzeba logować naturalnie. I ostrzec o tym (ale nie czytać po godzinach, bo nie wypada).
  4. Co potrzeba?
    serwer, który potrafi wysyłać smsy, trochę kodowania, trochę dizajnu i jakiś pomysł na monetyzację tego. Część z tych "zasobów" mam, części nie...
  5. Jest analogiczny serwis zagramaniczny, awayfind.com, pewnie bardziej zaawansowany niż to co opisałem. To tutaj to tylko podstawowa funkcjonalność, na start. Moim zdaniem są ludzie, którzy byliby tym zainteresowani.
Co o tym sądzicie?

23 lis 2008

Acer Aspire One i debian

Od jakiegoś czasu jestem szczęśliwym posiadaczem netbooka Acer Aspire One. Ten model dość mi pasuje – waga około kilograma, 9-calowy wyświetlacz (działający w rozdzielczości 1024x600) i dość wygodna klawiatura (wydaje się, że większa niż w EeePC Asusa).

1. Acer Aspire One


Co dostajemy „w środku”? Procesor Atom 1.6GHz. W zależności od opcji 512MB lub 1GB RAMu. Kartę ethernet 100Mbit, WiFi, 3 porty USB, 2 czytniki kart (jeden używany jako „storage extension”), wyjście VGA do monitora oraz wyjście na miktofon i słuchawki. Poza tym – wbudowany głośnik, mikrofon i kamerkę.
Dysk twardy – znów, zależnie od wybranej opcji, 8GB SSD lub tradycyjny dysk, rzędu 120GB.
W porównaniu z Eee PC 901 brakuje mu Bluetootha. Jestem w stanie to strawić, choć nie próbowałem korzystać z telefonu jako modemu – wówczas pewnie by się przydał BT.
Ja mam wersję z 512MB ramu (wersja 1GB jest sporo droższa – zaś do AAO możemy dołożyć kość pamięci 1GB, rozszerzając pamięć do maksymalnej wielkości – 1,5G. Kość kosztuje obecnie ~50 zł, założenie wymaga jedynie śrubokrętu i rozkręcenia laptopa – można zobaczyć, jak wygląda proces zakładania baterii np. tutaj: http://pl.youtube.com/watch?v=-EfzckyZMTk).
Dysk – SSD. Szybszy niż tradycyjny, poza tym odchodzi sporo elementów ruchomych, co stanowi dużą zaletę przy komputerze, którego główną cechą jest przenośność.
Z tego powodu w opisywanych tu działaniach skupię się przede wszystkim na tym, co ja robiłem z moim modelem.

2. System, z którym przyszedł


AAO sprzedawany jest w dwóch wersjach, z preinstalowanym Win XP i preinstalowanym Linuksem. Mój był ten drugi.
Ogólnie – śmieszny system. Widać, że zrobiony tak, żeby maksymalnie uprościć korzystanie z komputera osobom nieobeznanym z czymkolwiek innym niż Windows. Główny ekran to 4 „bloki”, w których pogrupowane są najczęściej (zdaniem twórców) używane aplikacje – przeglądarka, klient poczty, Office, gry, aplikacje do łączenia się z siecią...
Ja jednak postanowiłem, korzystając z całej masy HOWTOs dostępnej w sieci, zainstalować na nim Debiana.

3. Instalacja Debiana


Prosta sprawa – potrzebujemy pendrive'a lub karty pamięci i czytnika, albo napędu CD na usb – czegokolwiek, z czego można będzie zbootować nasz komputer. Na ten napęd, zgodnie z instrukcjami na stronie wiki.debian.org - http://wiki.debian.org/DebianAcerOne – wrzucamy boot.img.gz i obraz iso „płytki” instalacyjnej netinst – ważne, żeby oba były stworzone dla tej samej wersji kernela.
Proces instalacji powinien przebiegać jak zawsze. Postarajmy się tylko o kabelek ethernetowy, jako że obecna wersja testing nie widzi na etapie instalacji wifi...
W moim przypadku instalacja nie zakończyła się sukcesem – wyskakiwały jakieś błędy (nie zrobiłem fotki, niestety) na etapie instalacji pakietów. Na szczęście wyjście z instalatora, chroot /target pod konsolą i instalacja tam czego potrzeba (przede wszystkim – aptitude install grub i konfiguracja gruba tak, żeby komputer uruchomił się z dysku) pomogło. Po restarcie i zainstalowaniu reszty systemu musiałem tylko podmienić /sbin/start-stop-daemon – na jego miejsce wrzucić wersję /sbin/start-stop-daemon.REAL. Ten pierwszy jest takim oszukańczym na czas instalacji.
Zaraz potem warto zainstalować dalsze pakiety, zresztą w większości wymienione na http://wiki.debian.org/DebianAcerOne. W szeczególności przyda się moduł madwifi do jądra, dający nam dostęp do wifi. Ja zainstalowałem go przez module-assistanta, jak opisali na powyższej stronie.

4. Tweaks


System, zaraz po zainstalowaniu, choć działa, może dzialać lepiej. To co ja chciałem osiągnąć to:
zmniejszenie obciążenia dysku SSD
Ogólnie chcę uzyskać mniejsze obciążenie zapisem dysku SSD (mimo, że według tego artykułu mój dysk powinien wytrzymać minimum 8 lat). W tym celu zrobiłem kilka rzeczy:
  • do linijki kernel w pliku konfiguracyjnym gruba (/boot/grub/menu.lst) dopisalem elevator=noop
  • do opcji montowania dysku w /etc/fstab dodałem noatime,nodiratime
  • partycje /var/log, /var/tmp i /tmp są montowane jako ramdyski (linijki w /etc/fstab: tmpfs /tmp tmpfs defaults 0 0)
    • miejsce, gdzie trafiają pakiety przy instalacji też wrzucam na ramdisk, ale już nie osobny. po prostu zrobiłem symlinka /var/cache/apt/archives -> /tmp (komendą rm -r /var/cache/apt/archives/ ; mkdir -p /tmp/partial/ ; ln -s /tmp/ /var/cache/apt/archives/). Że mi zaśmiecają /tmp? co z tego? (nawet jeśli będzie używany swap, nie powinno to zwiększyć ilości zapisów na dysku).
    • żeby wszystko działało jak należy, do pliku /etc/rc.local dopisałem tworzenie katalogów na tym ramdyskach (/var/log/apt, /var/log/gdm, /var/log/news, /tmp/partial)

      Zawartość mojego pliku /etc/rc.local po zmianach wygląda mniej więcej tak:

      if [ ! -d /var/log/apt ]
      then
        mkdir -p /var/log/apt
      fi
      if [ ! -d /var/log/gdm ]
      then
        mkdir -p /var/log/gdm
      fi
      if [ ! -d /tmp/partial ]
      then
        mkdir -p /tmp/partial
      fi



  • /var/run i /var/lock to też RAMDISKI - w pliku /etc/default/rcS ustawiam RAMRUN=yes i RAMLOCK=yes

konfiguracja X-ów

Jest kilka spraw, którymi należy się zająć: ustawienie odpowiedniej wielkości czcionek dla wyświetlacza, modyfikacja działania touchpada i ogólne poprawienie działania Xów.
  • z domyślnymi ustawieniami czcionki w niektórych programach będą wielkie. Naprawdę wielkie, prawie takie jak Wszechświat. Aby to naprawić, wystarczy do /etc/X11/xorg.conf dopisać:


    • w sekcji Device linię Option "NoDDC"
    • w sekcji Monitor - DisplaySize 195 113


  • dodatkowe opcje dla touchpada




    • musimy powiedzieć xorg, żeby używały sterownika Synaptics. Poniżej cała moja sekcja InputDevice dla myszki:


      Section "InputDevice"
      Identifier "Synaptics Touchpad"
      Option "SHMConfig" "on"
      Driver "synaptics"
      Option "SendCoreEvents" "true"
      Option "Device" "/dev/psaux"
      Option "Protocol" "auto-dev"
      Option "HorizScrollDelta" "0
      EndSection


    • syndaemon pozwala na zablokowanie działania touchpada gdy klawiatura jest używana. Powinno to zmniejszyć ilość przypadkowych kliknięć / przesunięć kursora myszy gdy piszemy. a więc: aptitude install syndaemon. Następnie musimy odpalić syndeamona w naszym skrypcie startowym X-ów, na przykład: syndaemon -d -i 0.8 -k.


  • aby poprawić wydajność karty graficznej w X-ach wystarczy dodać do sekcji Device pliku /etc/X11/xorg.conf następujące linie:


    Driver "intel"
    Option "AccelMethod" "exa"
    Option "MigrationHeuristic" "greedy"


dźwięk

Aby mieć sensowny dźwięk, trzeba zainstalować alsę (pakiety alsa-base i alsa-utils się przydadzą). Następnie do pliku /etc/modprobe.d/alsa-base dodać linijkę options snd-hda-intel model=acer. Niestety, nie udało mi się sprawić, żeby dźwięk działał po suspendzie. Jeśli ktoś wie, jak do tego dojść, proszę o info. (Niektórzy radzą, żeby używać model=toshiba, wówczas może nie działać wbudowany mikrofon, ale być może dźwięk po obudzeniu owszem - u mnie po obudzeniu dźwięk był, ale tak cichy, że i tak musiałem rebootować).

dobrze działający, wygodny na nietypowym ekranie Firefox

Ekran ma rozdzielczość 1024x600, więc ilość punktów w poziomie jest prawie dwa razy większa niż w pionie. Bardzo szeroka panorama. Wobec tego w Firefoksie chciałem usunąć jak najwięcej rzeczy zajmujących miejsce w pionie. Udało mi się dojść do takiego stanu:

  • Zwinięcie całego menu do małego przycisku, pod którym są wszystkie opcje to zaleta addonu Tiny Menu: https://addons.mozilla.org/en-US/firefox/addon/1455. Następnie, przy użyciu menu customizacji przeniosłem wszystkie potrzebne ikony (back, forward i home – zamiast stop używam Esc, zamiast reload – ctrl+r), pasek adresu i wyszukiwania na pasek menu, oraz ukryłem Navigation Toolbar.
  • Są addony umieszczające zakładki po boku ekranu – celem oszczędzenia miejsca z jeszcze jednego paska – ale to już by była przesada. Chyba straciłbym więcej miejsca w efekcie niż zyskał (tym bardziej, że większość stron tworzona jest na określoną szerokość, nie wysokość okna).
  • Jest też addon autoHideStatusbar - pozwala ukrywać Status Bar (to to coś na dole okna) poza sytuacjami, gdy jest potrzebny (np. najeżdżamy na linka i chcielibyśmy wiedzieć, dokąd nas zaprowadzi). Niestety, mam z tym addonem problem przy przenoszeniu okienka FF na inny pulpit - statusbar zostaje na starym. Być może to wina mojego winmanagera, whatever... Ten dodatek jest w fazie eksperymentalnej, będę monitorować jego status.
Jeśli jesteśmy już przy Firefoksie – warto się wysilić i przenieść cache przeglądarki do katalogu na ramdysku - jeśli nie chcemy z niego korzystać między bootami. Pozwoli to bardziej zmniejszyć obciążenie dysku SSD. Aby to zrobić, należy otworzyć stronę about:config i dodać zmienną typu String o nazwie browser.cache.disk.parent_directory, o wartości wskazującej na katalog, w którym umieszczony będzie cache (w moim przypadku - /tmp/firefox).

dodatkowe klawisze

Po pierwsze: klawiatura Aspire One daje nam trochę dodatkowych klawiszy. Jako, że nie używam go z zewnętrznymi monitorami, nie bawiłem się w konfiguracje klawisza Fn+F5. Przyciemnianie/pojaśnianie wyświetlacza (Fn+left/right) działa bez żadnej dodatkowej konfiguracji. Interesowała mnie przede wszystkim kontrola nad dźwiękiem z klawiatury (Fn+F8 włącza/wyłącza dźwięk, Fn+up/down pogłaśnia i przycisza).
Dodatkową "sztuczką" związaną z klawiaturą było użycie kombinacji klawiszy Shift+Menu jako symulacji kliknięcia środkowym klawiszem. Jakoś nie wychodziło mi to dobrze z touchpada.
Zainstalowałem: xmodmap i xbindkeys. Mój plik .Xmodmaprc wygląda tak:

keycode 160 = XF86AudioMute
keycode 174 = XF86AudioLowerVolume
keycode 176 = XF86AudioRaiseVolume
keycode 223 = XF86Standby
Plik .xbindkeysrc:
"middleclick"
Shift + Menu
"amixer set Master toggle"
m:0x0 + c:160
"amixer set Master 2dB+ unmute"
m:0x0 + c:176
"amixer set Master 2dB- unmute"
m:0x0 + c:174
"sudo pm-suspend"
XF86Standby
middleclick jest skryptem symulującym środkowe kliknięcie myszy (u mnie w /usr/local/bin/middleclick):
#!/bin/sh
xevent -b 2 2
Wykorzystuję program xevent (niestety, niedostępny w Debianie jako pakiet, skompilowałem ze źródeł - xevent).

19 lis 2008

Policyjny psychol w kolorowych gatkach?

Rzadko zdarza się, żebym zachwycał się filmem ze względu na obsadę[1]. Zazwyczaj musi być dużo strzelania, jakieś cycki, najlepiej nerd na koniec filmu zdobywający super-laskę, durny wątek romantyczny który wyciska mi łzy jak najlepsza cebula...

[caption id="attachment_71" align="alignleft" width="274" caption="najbardziej dziewczęca rola w ostatnich latach?"]najbardziej dziewczęca rola w ostatnich latach?[/caption]

Ten rok zafundował mi dwa filmy, w których obsada wgniotła w fotel. Pierwszym z nich jest Mamma Mia, z rewelacyjną rolą i głosem Meryl Streep oraz świetnie dobraną Amandą Seyfried (znana między innymi z sukowatej roli w pierwszym sezonie Veroniki Mars - tutaj świetnie gra rolę 20-latki, wchodzącej w życie, w przeddzień ślubu, która stara się odnaleźć samą siebie; tak dziewczęco zagranej roli nie widziałem od dawna).

[caption id="attachment_68" align="alignright" width="320" caption="De Niro, Pacino i randomalna laska"]De Niro, Pacino i randomalna laska[/caption]

Drugi film jest całkiem inny - Righteous Kill. Gra tu para aktorów, którą bardzo lubię - Robert De Niro i Al Pacino. Nie pamiętam ich razem w żadnym filmie od The Heat z roku 1995, ale może coś mnie ominęło...

Obaj panowie mają już swoje lata, w filmie nie doświadczymy więc bardzo dużo typowej akcji. Jest to raczej dramat psychologiczny o policjantach. Policjantach, którzy, jak to stróże prawa, związani procedurami, prawem i przekupnymi, bezradnymi sądami, nie mogą nic zrobić. Ale, there's a new sheriff in town, ktoś zaczyna wykańczać najgorsze szumowiny w mieście, zostawiając (a jakże bez tego) rymowany nekrolog na miejscu zbrodni. Oczywiście, żeby było ciekawiej, śledztwo w sprawie tych morderst przypada naszym dwóm bohaterom - jednocześnie zaś jeden z nich opowiada o kolejnych swoich zbrodniach (bo, jakby się ktoś nie domyślił, to to jego sprawka, o czym zresztą wiemy od początku).

W kolejnych scenach możemy obserwować kolejne ofiary. Oraz, następujące wraz z nimi psychiczne napięcie mordercy - pogłębiające się, gdy ktoś sugeruje, że mordercą jest najprawdopodobniej policjant. Takie podwójne życie musi jednak być trudne, tym bardziej, że w domu czeka młoda (no, młoda jak na warunki panów De Niro i Pacino) dziewczyna, która wszak nie jest wprowadzona w sprawę.

Ogólnie to ofiary mordercy przedstawione są na tyle negatywnie, że jego samego nie da się nie lubić. Poza tym, przecież walczy on o to, żeby nam było na ulicach bezpiecznie, nie? Cel uświęca środki, o czym powie nam każdy superbohater ze stajni Marvela.

[caption id="attachment_69" align="alignleft" width="320" caption="Robert De Niro"]2008-11-19-195337_1024x600_scrot_s[/caption]

Pewien zgrzyt następuje, gdy pętla na szyi mordercy zaczyna się zaciskać, a on sam lekko traci nad sobą panowanie. Co z tego wyniknie - nie powiem, nie chcę spojlerować...

Zakończenie filmu nie jest może najlepszym w historii kina, ale na pewno utrzymuje poziom.

Na przykładzie tego filmu widać, co to znaczy klasa aktorska i ogromne doświadczenie. Sorry, ale pojedynczy grymas na twarzy De Niro znaczy więcej niż cała niesłychana kariera aktorska różnych Cichopek i innych polskich (i nie tylko) gwiazd występujących w serialach, nawet najlepszych. Tak naprawdę film pozbawiony tej dwójki aktorów raczej nie wart byłby polecenia - za to z nimi zdecydowanie zasługuje na to, żeby się nim ponapawać.

I, być może, nawet zastanowić, co może zrobić superhero, żeby ciągle był bohaterem w kolorowych portkach a nie mrocznym psychopatą.

[1] No dobra, było trochę tego. Ale zazwyczaj obsada, ze względu na którą coś oglądałem, miała duże cycki.

6 lis 2008

blipFiltr - zmiany

Bardzo miłe było wspomnienie o blipFiltrze we wpisie na bliplogu. Zanotowałem nawet trochę odwiedzin, i dostałem kilka wiadomości feedbackowych;)

Ogólnie plan jest taki, aby stworzyć z tego potworka aplikację, która będzie miała sens :) Dlatego staram się, w ramach wolnego czasu, dodawać conieco, tudzież poprawiać to, co już jest. A co zostało dodane?

co nowego?


Na początek - trochę poprawiłem wyświetlanie strony z wiadomościami i statusami. Można tam "z palca" wpisać teraz nazwę użytkownika, z którym chcemy śledzić konwersację. Poza tym oczywiście, na liście wiadomości, można kliknąć jego nick, uzyskując to samo. Jak komu wygodnie.

Poza tym - wyświetlanie ładnych (DGCC) tooltipów z obrazkami posłanymi na blipa - można obejrzeć taki obrazek przeskalowany w dół (mam nadzieję;p) po najechaniu myszką na linka.

Kolejną zmianą jest więcej regexpów - dzięki czemu mamy klikalne linki tam, gdzie coś wygląda jak link.

Sposób ściągania statusów i wiadomości też się trochę zmienił - jeśli w takim updacie jest link do innego statusu/wiadomości blipowej, zostanie ona też scache'owana. Na stronie z wiadomościami wyświetli się natomiast ona w tooltipie nad linkiem do tej wiadomości w blipie.

Oraz, last but not least, oczywiście... zawsze zazdrościłem dużym chłopcom (serwisom) tych ich "ponad 11 milionów użytkowników..." i innych bla bla. Ponieważ blipfiltr nie ma użytkowników jako takich (nie ma logowania, i nie będzie...), jedyne czym mogę się pochwalić to zawartość cache'a :) Więc jest ona wyświetlana na głównej stronie (ilość wiadomości, nie cała zawartość...).

co w przyszłości?


O ile będzie jakaś przyszłość... aka ktoś będzie zaglądał (a mam nadzieję, że będzie) zamierzam pomyśleć nad dalszymi funkcjami:

  • linki do "powiązanych updatów" - czyli takich, które są cytowane w tej wiadomości / same ją cytują

  • śledzenie odpowiedzi - czasem ktoś coś pisze w statusie, ktoś mu odpowiada DM-ką (direct message) - what a mess!. Chciałbym móc to śledzić jakoś inteligentnie.

  • wyszukiwanie w wiadomościach (czy jest sens full-text search?)

  • stronicowanie. chyba się może przydać...

  • wygląd! To, jak teraz blipfiltr wygląda, jest efektem tego, co pisał Jeff Atwood na blogu stackoverflow.com - Trust me, you do not want to see the “programmer” design we had before this. Tjaaa...

  • Ktoś umie zrobić jakieś logo? :) Oczywiście, pro publico bono :)

3 lis 2008

denormalizować

Zapewne to, co napiszę tutaj będzie trywialne - ale może ktoś z tego skorzysta...

Jakoś niedawno bawiłem się w walidację formularzy w django - a chwilę później ^alex zetknął się z takim problemem i zapytał na blipie. Miałem to na świeżo, więc nawet dostałem ++ do lansu (tutaj).

Dziś znów, podczas pisania swojego nowego cudeńka (o którym tutaj, mam nadzieję, więcej wkrótce napiszę) zetknąłem się z problemem w modelu, który sprowadził się do tego - normalizować czy denormalizować bazę?

Nad problemem normalizacja czy nie zastanawiał się też Jeff Atwood na swoim blogu.

Sytuacja jest taka: dwie tabele, jedna z nich zawiera dane transakcji - nazwijmy ją tabelą A. Druga - tabela B, połączona z tabelką A przez ForeignKey.

Mamy więc many B - one A.



Teraz, chcę wybrać te obiekty A, które mają jeden (lub zero) powiązanych B.

Po kilku próbach zrobienia tego przez normalne filtrowanie, zapytałem na stackoverflow. Jedna z odpowiedzi sugeruje użycie składni .extra obiektu QuerySet. Wolałem tego uniknąć...

Druga - każe się zastanowić nad denormalizacją bazy - i dodaniem do modelu A dodatkowego elemrntu, albo wskazującego na ilość linkujących do niego B, albo zawierających po prostu boolowską zmienną mówiącą czy jest zero lub jeden takich B, że b.a_id = a.id.

No i mamy denormalizację. Podręcznikowy przykład, przy którym należy sobie zadać pytanie o dwie sprawy:

  • wydajność - czy aktualizacja obiektów jest częsta? Czy narzut związany z dodatkowym parametrem i każdorazowym jego przeliczaniem rekompensuje trochę szybsze wykonanie zapytania wyświetlającego nasze dane? Jest to więc pytanie o to, która z operacji wykonywana jest częściej.

  • zachowanie spójności bazy - jeśli skasuję obiekt b, wskazujący na obiekt a, muszę mieć pewność, że licznik a zmieni się odpowiednio. Podobnie - przy dodawaniu nowego obiektu.


Pierwszy przypadek jest bardzo zależny od tego, gdzie i w jakich okolicznościach używane jest to zapytanie, od obciążenia serwera i, jestem pewien, może być różny dla różnych silników bazodanowych. Dlatego najprostszą analizą jest zapytanie - czy wyświetlanie jest częstsze niż aktualizacja? W moim przypadku jest. score.

Druga sprawa jest na szczęście dość dobrze obsługiwana przez modele w Django.

Po chwili poszukiwań znalazłem sporo materiałów na temat możliwości dawanych przez nadpisanie domyślnej funkcji models.Model.save() dostarczonej przez django. Jedną z lepszych jest wyszukane przez Google (i już niestety nieistniejące poza światem cache'a googla) Django Signals vs. Custom Save()-Method.

W moim wypadku to przesądza. Zrobię składny, szybszy model, co z tego, że nieznormalizowany?