Simple, powerful, clean. Just works.
Saturday, May 28, 2011
PyHole - simple REST API client
Every time you need to connect to some rest api you hack urllib and hardcode some url to hit. Not any more, check out PyHole.
Tuesday, April 26, 2011
Hiring
PRACA
Programista Python / django
Co robimy? Ciekawe projekty związane z aplikacjami internetowymi, które wymagają nieszablonowego podejścia.
Kogo szukamy? Studentów, którzy chcą rozwijać swoje umiejętności w technologiach internetowych (python, django, html 4 i 5, css 3, JavaScript, jQuery, SQL, mysql, postgres).
Co oferujemy? Dogodne godziny pracy dla studiowania, miłą atmosferę i duży nacisk na rozwój przez naukę od doświadczonego zespołu.
Saturday, April 2, 2011
Flat but clever menuing for django
While creating a website you may need a menu at some point. Maybe even more than one. Django does not have any menuing system, so after searching for ready menu app I still was not satisfied of what I found. All of stuff that I've found were neither complicated or had some strange architecture (e. g. based on ORM).
So I wrote it by myself with such assumptions:
Definition of the template tag is the only thing that is important in the menus app:
In menus.py put following code:
Now add new app to your settings.py to INSTALLED_APPS.
Create in your project root dir (the same where you keep settings.py) file called menu.py.
menu.py
That's all folks. Now you can use your menu in the template. If this is main menu, it is wise to use it in top level template that you will extend from.
As you can see, your menu will be generated from the data structure that is returned after calling appropriate menu name from menu.py. This allows you to even create dynamic menus if needed.
The format of structure is a list of tuples. Each tuple contain three values:
Avoiding hardcoding
Nested menu
In my case nested menu is when you want to have a main menu at the same time with additional menu (e. g. for logged user). One of items from main menu may be selected as an ancestor item for logged "sub" menu.
You can easily create the second menu, only remember to make URLs in prefix style. For example:
When you try to display both menus the item "Your Account" in menu_main will still be active for all "logged" pages because regex will still match for this urls (there is no $ sign at the end of regex). And you can have your nested menu_logged with some different items to display.
Notice that every other action made from view2 and view3 will also select Action 2/Action 3 in menu_logged. That's because we use URL prefixing for organizing the URL namespace of django project. Even if that additional actions does not have their menu items - with url prefixing you can assign them to the particular menu item.
So I wrote it by myself with such assumptions:
- I do really need only flat menus - but still I can use several flat menus to emulate nested menus.
- Menuing should work in every view without putting any arbitrary @decoration or python code to view function code.
- Menu should be able to draw items in the way that template designer wants it to have, no hardcoding of CSS classes for "selected" items.
- No database hits for getting menu - this is obvious, menu does not change at all, why to hit database for it?
- Finally the clever thing - the fact that any item of menu is selected should be evaluated from current URL of view request.
So the first thing to do is to create reusable django app.
~$ ./manage.py createapp menus
Definition of the template tag is the only thing that is important in the menus app:
./menus/ ./menus/templatetags/ ./menus/templatetags/__init__.py ./menus/templatetags/menus.py
In menus.py put following code:
from django.template import Library, Node, TemplateSyntaxError import re register = Library() def match_path(match, path): if re.search(match, path): return 'selected' else: return '' class MenusNode(Node): def __init__(self, model, varname): self.varname = varname self.model = model self.project_menus = __import__('menu') def render(self, context): menu_list = getattr(self.project_menus, self.model)() menu_list = map(lambda x: {'name': x['name'], 'url':x['url'], 'selected': match_path(x['match'], context['request'].path)} , menu_list) context[self.varname] = menu_list return '' def get_menu(parser, token): bits = token.contents.split() if len(bits) != 4 or bits[2] != 'as' : raise TemplateSyntaxError, "bad syntax: get_menu menu_name as menu_variable for url" return MenusNode(bits[1], bits[3]) get_menu = register.tag(get_menu)
Now add new app to your settings.py to INSTALLED_APPS.
Create in your project root dir (the same where you keep settings.py) file called menu.py.
menu.py
from django.core.urlresolvers import reverse def menu_main(): return [ { 'name' : 'Home', 'url' : '/', 'match' : r'^/$', }, { 'name' : 'Pricing', 'url' : '/pricing/', 'match' : r'^/pricing/', }, { 'name' : 'Blog', 'url' : '/blog/', 'match' : r'^/blog/', }, { 'name' : 'Contact', 'url' : '/contact/', 'match' : r'^/contact/', }, { 'name' : 'Sign-in', 'url' : reverse('accounts.views.signin'), 'match' : r'^' + reverse('django.contrib.auth.views.login'), }, { 'name' : 'Your account', 'url' : reverse('accounts.views.accont'), 'match' : r'^/logged/', }, ]
That's all folks. Now you can use your menu in the template. If this is main menu, it is wise to use it in top level template that you will extend from.
{% load menus %} <html> ... <body> ... <div id="menu"> <ul> {% get_menu menu_main as menu_main %} {% for menu_item in menu_main %} <li><a href="{{menu_item.url}}" class="{{menu_item.selected}}">{{menu_item.name}}</a></li> {% endfor %} </ul> </div> ... </body> </html>
As you can see, your menu will be generated from the data structure that is returned after calling appropriate menu name from menu.py. This allows you to even create dynamic menus if needed.
The format of structure is a list of tuples. Each tuple contain three values:
- Display name for menu.
- URL address that the menu item should direct to after clicking.
- Regex to match against current URL in order to determine if particular item should be marked as "selected". This simple approach gives you many possibilites to activate menu items on different set of URLs by making alternations in regex.
Avoiding hardcoding
- If you don't want to hardcode regular expressions into menu.py, just change them to r'^' + reverse(...). This will create a regular expression from the link you are pointing to (what is usually good idea).
- If you don't want to hardcode class="selected" just change it to class="{% if menu_item.selected %}my_fancy_selected_class {% endif %}".
Nested menu
In my case nested menu is when you want to have a main menu at the same time with additional menu (e. g. for logged user). One of items from main menu may be selected as an ancestor item for logged "sub" menu.
You can easily create the second menu, only remember to make URLs in prefix style. For example:
http://mydomain.tld/pricing http://mydomain.tld/blog http://mydomain.tld/contact http://mydomain.tld/logged/view1 http://mydomain.tld/logged/view2 http://mydomain.tld/logged/view2/add/new/item http://mydomain.tld/logged/view3 http://mydomain.tld/logged/view3/some/other/action
When you try to display both menus the item "Your Account" in menu_main will still be active for all "logged" pages because regex will still match for this urls (there is no $ sign at the end of regex). And you can have your nested menu_logged with some different items to display.
def menu_logged(): return [ { 'name' : 'Action 1', 'url' : reverse('myapp.logged.view1'), 'match' : r'^' + reverse('myapp.logged.view1'), }, { 'name' : 'Action 2', 'url' : reverse('myapp.logged.view2'), 'match' : r'^' + reverse('myapp.logged.view2'), }, { 'name' : 'Action 3', 'url' : reverse('myapp.logged.view3'), 'match' : r'^' + reverse('myapp.logged.view3'), }, ]
Notice that every other action made from view2 and view3 will also select Action 2/Action 3 in menu_logged. That's because we use URL prefixing for organizing the URL namespace of django project. Even if that additional actions does not have their menu items - with url prefixing you can assign them to the particular menu item.
Functional python programming in April Fools
This is not djangish stuff but still tooks me a while of hacking.
I wanted to make an April Fools Day joke on my dear students and mess up their names on student records.
All I had need to do is to export Google Spreadsheet as CSV, read first column with "surname firstname" format. Then split surnames from firstnames, sort the firstnames list and join them again.
So I make a simple python script:
I looked at this and thought - what a long python code. This is so simple task, shouldn't be written in so sparse way. Also omitting the two first lines looks awful. This should be done with slicing.
After while of hacking I've end up with this:
But this became a typical one-liner that is completely unreadable after one week. I felt that I need to make some indentation to this code anyway to make it readable:
So functional programming is fun, but the problem is you need to read code inside-out, not bottom-down and that is sometimes difficult. I am wondering if there will be someday a programming language that will support functional programing with bottom-down oriented syntax.
I wanted to make an April Fools Day joke on my dear students and mess up their names on student records.
All I had need to do is to export Google Spreadsheet as CSV, read first column with "surname firstname" format. Then split surnames from firstnames, sort the firstnames list and join them again.
Aaby Joe Daby Ann Zaby Ianto
Aaby Ann Daby Ian Zaby Joe
So I make a simple python script:
import csv reader = csv.reader(open('notes.csv', 'rb'), delimiter=',', quotechar='"') i = 0 surnames=[] firstnames=[] for row in reader: if i > 2: surnames.append( row[0].decode('utf-8').split(' ')[0] ) firstnames.append( row[0].decode('utf-8').split(' ')[1] ) i+=1 firstnames.sort() newnames = map(lambda x: x[0] + ' ' +x[1], zip(surnames, firstnames)) print newnames
I looked at this and thought - what a long python code. This is so simple task, shouldn't be written in so sparse way. Also omitting the two first lines looks awful. This should be done with slicing.
After while of hacking I've end up with this:
import csv print map(lambda x: "%s %s" % (x[0], x[1]), reduce(lambda x, y: zip(x, sorted(y)), zip(* map(lambda x : x.split(' '), [row[0] for row in csv.reader(open('a.csv'))][3:]))))
But this became a typical one-liner that is completely unreadable after one week. I felt that I need to make some indentation to this code anyway to make it readable:
import csv print map ( lambda x: "%s %s" % (x[0] , x[1]), reduce ( lambda x,y: zip(x, sorted(y)), zip (* map( lambda x: x.split(' '), [row[0] for row in csv.reader(open('notes.csv'))][3:]) ) ) )
So functional programming is fun, but the problem is you need to read code inside-out, not bottom-down and that is sometimes difficult. I am wondering if there will be someday a programming language that will support functional programing with bottom-down oriented syntax.
Polymorphism in django models
Django models are very powerful ORM, but they do not play nice with any kind of polymorphism out of the box. The problem cames when you want to add a model that have some generic properties set, but it can differ in implementations of some methods (because of theirs type/specialization).
Lets consider follwoing example:
I would like to store different types of Animals here: a dog, a cat, a cow. All I am interested with is theirs name, so I don't want to make a separate models for them. Also I would like to make querysets regardless of a kind of an animal - just from all of the animals I have.
Let's do some metaclass magic python programming.
Drop all from the database for previous example and create new models. Then try this:
Background notes:
Lets consider follwoing example:
class Animal(models.Model): name = models.CharField(max_length=15) def __unicode__(self): return self.name def make_sound(self): print "Some sound"
I would like to store different types of Animals here: a dog, a cat, a cow. All I am interested with is theirs name, so I don't want to make a separate models for them. Also I would like to make querysets regardless of a kind of an animal - just from all of the animals I have.
>>> cat = Animal(name="Cattie").save() >>> dog = Animal(name="Doggie").save() >>> cow = Animal(name="Cowwie").save() >>> Animal.objects.all() [<Animal: Cattie>, <Animal: Doggie>, <Animal: Cowwie>] >>> for a in Animal.objects.all(): ... a.make_sound() ... Some sound Some sound Some sound
Let's do some metaclass magic python programming.
class InheritanceMetaclass(ModelBase): def __call__(cls, *args, **kwargs): obj = super(InheritanceMetaclass, cls).__call__(*args, **kwargs) obj.__class__ = obj._get_class() return obj class Animal(models.Model): __metaclass__ = InheritanceMetaclass TYPES=( ('AnimalDog', 'Dog'), ('AnimalCat', 'Cat'), ('AnimalCow', 'Cow')) name = models.CharField(max_length=15) type = models.CharField(max_length=15, choices=TYPES) def __unicode__(self): return self.name def make_sound(self): print "Some sound" def _get_class(self): if not self.type: return self.__class__ else: return getattr(sys.modules[self.__module__], self.type) class AnimalDog(Animal): def make_sound(self): print "Hauu!" class Meta: proxy = True class AnimalCat(Animal): def make_sound(self): print "Meow!" class Meta: proxy = True class AnimalCow(Animal): def make_sound(self): print "Mooo!" class Meta: proxy = True
Drop all from the database for previous example and create new models. Then try this:
>>> Animal(name='Cattie', type='AnimalCat').save() >>> Animal(name='Doggie', type='AnimalDog').save() >>> Animal(name='Cowwie', type='AnimalCow').save() >>> Animal.objects.all() [<AnimalCat: Cattie>, <AnimalDog: Doggie>, <AnimalCow: Cowwie>] >>> for a in Animal.objects.all(): ... a.make_sound() ... Meow! Hauu! Mooo!
Background notes:
- because we create proxy models, there is only one database table for the Animal,
- every time you query for Animal object you get an object casted to appropriate class (not the Animal), but in this same time this will work flawless with django, because of duck typing. AnimalDog will behave exactly the same as parent Animal class in case of using it in django admin and so on,
- we store in the attribute Animal.type a name of django class model name,
- we can easily extend our Animal types by adding new values to Animal.TYPES,
- if you need real model inheritance (e.g. add custom model fields depending on a model type) use django model inheritance - this is not described here case,
- you can also store type as Integer field, but then it needs some further hacking in _get_class() method, see also how to avoid hardcoding with Perfect choice.
Friday, April 1, 2011
Perfect choice
Have you ever wondered how to deal with django choices without hardcoding numeric values into code?
Well, I was wondering too, found some solutions on the Web but after all need some rewriting to came up with this:
This is a little customization of this snippet: http://djangosnippets.org/snippets/1647/
How does it work with models? Nice and easy:
Now you can use it like that:
No more hardcoding values. No more!
Well, I was wondering too, found some solutions on the Web but after all need some rewriting to came up with this:
class Enumeration(object): """ A small helper class for more readable enumerations, and compatible with Django's choice convention. You may just pass the instance of this class as the choices argument of model/form fields. Example: MY_ENUM = Enumeration([ (100, 'MY_NAME', 'My verbose name'), (200, 'MY_AGE', 'My verbose age'), ]) assert MY_ENUM.MY_AGE == 100 assert MY_ENUM[1] == (200, 'My verbose age') """ def __init__(self, enum_list): self.enum_list_full=enum_list self.enum_list = [(item[0], item[2]) for item in enum_list] self.enum_dict = {} self.enum_display = {} for item in enum_list: self.enum_dict[item[1]] = item[0] self.enum_display[item[0]] = item[2] def __contains__(self, v): return (v in self.enum_list) def __len__(self): return len(self.enum_list) def __getitem__(self, v): if isinstance(v, basestring): return self.enum_dict[v] elif isinstance(v, int): return self.enum_list[v] def __getattr__(self, name): return self.enum_dict[name] def __iter__(self): return self.enum_list.__iter__() def __repr__(self): return 'Enum(%s)' % self.enum_list_full.__repr__() def get_display_name(self, v): return self.enum_display[v]
This is a little customization of this snippet: http://djangosnippets.org/snippets/1647/
How does it work with models? Nice and easy:
class SoomeModel(models.Model): OPTIONS=Enumeration([ (1, OPTION_A, u'This is option A'), (2, OPTION_B, u'This is option B'), (3, OPTION_C, u'This is option C'), ]) option = models.IntegerField(choices=OPTIONS)
Now you can use it like that:
>> SomeModel.OPTIONS.OPTION_A .. 1 >> SomeModel.OPTIONS['OPTION_B'] .. 2 >> SomeModel.OPTIONS[1] .. (2, 'This is option B') >> SomeModel.OPTIONS.get_display_name(2) .. "This is option B" >> SomeModel.OPTIONS.get_display_name(SomeModel.OPTIONS_A) .. "This is option A"
No more hardcoding values. No more!
Kick off
Yeap - it is April fools. Lovely time to start blogging :-)
Subscribe to:
Posts (Atom)