Wygodny storage z użyciem memcache w Django

Autor: nme · środa, 12 Maj, 2010 · Brak komentarzy ·

Czasami zachodzi konieczność napisania na szybko aplikacji w Django która standardowo coś tam trzyma w bazie danych, coś przetwarza i wyświetla. Jeśli aplikacja ma być prosta, a w bazie mają być trzymane proste struktury danych, to czy napewno musimy tyle czasu poświęcać na dopracowanie modeli? Jasne, że nie.

Poniższy kod oferuje nam możliwość trzymania dowolnych danych w postaci klucz-wartość w bazie danych. Dodatkowo — owe dane mogą mieć dowolną postać — może być to tekst, tablica asocjacyjna czy wartość typu Boolean.

Ponadto — biblioteczka ta opiera się o opisaną w poprzednim wpisie obsługę memcache'u w Django — co sprawia, że do póki nie zmienimy wartości danych, a ich obecność w cache'u nie zdąży wygasnąć — nie będziemy w ogóle obciążać naszej bazy danych. Osobiście wykorzystuję ten kod do trzymania ustawień aplikacji. Niektóre ustawienia są typu boolean, inne to stringi, jeszcze inne — tabele. Rozwiązanie sprawdza się świetnie.

Właściwy kod

Modele — models.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2009 nme.pl
# Dual licensed under MIT and GPL.
from django.db import models
class Vars (models.Model):
    key = models.CharField(max_length=50)
    value = models.TextField()

Proste prawda? Nie zapomnijcie wydać komendy django-admin syncdb która utworzy odpowiednią tabelę w bazie. Teraz czas na właściwą bibliotekę — vars.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2009 nme.pl
# Dual licensed under MIT and GPL.
""" Simple variables (key-value) handling with memcache """
import pickle,base64
import memcache,models
from settings import conf
class __Vars:
    def get (self,key,default=None):
        """ get Vars variable value """
        if memcache.enabled:
            value = memcache.get('va-%s' % key)
            if value != None:
                return pickle.loads(base64.b64decode(str(value)))
        settings = models.Vars.objects.filter(key=key)
        if settings:
            value = settings[0].value
            if value:
                return pickle.loads(base64.b64decode(str(value)))
            else:
                return default
        else:
            return default
    def __getitem__ (self,msg):
        return self.get(key)
    def set (self,key,value):
        """ set Vars variable value """
        value = base64.b64encode(pickle.dumps(value))
        if memcache.enabled:
            memcache.set('va-%s' % key,value)
        settings = models.Vars.objects.filter(key=key)
        if settings:
            setting = settings[0]
            setting.value = value
            setting.save()
        else:
            models.Vars(key=key,value=value).save()
    def has_key (self,key):
        """ return True or False if Vars variable exists """
        settings = models.Vars.objects.filter(key=key)
        if settings:
            return True
        else:
            return False
    def delete (self,key):
        """ deletes given key from Vars and memcache """
        if memcache.enabled:
            memcache.delete('va-%s' % key)
        settings = models.Vars.objects.filter(key=key)
        for i in settings:
            i.delete()
variables = __Vars()

Przykładowe użycie

Zastosowanie biblioteki z poziomu django-admin shell:

In [1]: from vars import variables

In [2]: if not variables.has_key('test'):
   ...:     variables.set('test','tekst')
   ...:
   ...:     

In [3]: print variables.get('test')
tekst

In [4]: variables.set('test',{'asd':1,'data':['struct','ure']})

In [5]: variables.get('test')['data'][1]
Out[5]: 'ure'

In [6]: variables.delete('test')

In [7]: variables.get('test')

In [8]: variables.has_key('test')
Out[8]: False

Jak to działa?

Składowanie dowolnego typu danych w rekordzie bazy zrealizowane jest w oparciu o dwie standardowe biblioteki pythonowe — pickle i base64. Pierwsza z nich oferuje zakodowanie dowolnej struktury danych do stringa, druga natomiast — zastosowanie notacji base64 — przez co zabezpieczamy się przed ewentualnymi problemami z obsługą znaków z którymi nasz bazodanowy backend mógłby mieć ewentualnie problemy. Innymi słowy — rozwiązanie przedstawione powyżej gwarantuje nam pełną przenośność danych.

Zachęcam gorąco do korzystania :)

Zostaw komentarz