« The role of designers in the Django community | Large Problems in Django, Mostly Solved: Delayed Execution »
Django itself has shipped with a "semi-private" introspection API, _meta, for a long time. I have created a drop-dead simple wrapper on top of this.
The value of introspection keeps growing on me as I realize how it makes making truly reusable applications possible. It is an interesting intersection of duck-typing and interfaces. Basically, you can create functionality that will work with any Django model, as long as it has the correct values on them.
However, I present this as a very useful proof of concept, and I think a lot can be done with these ideas to improve on them. I recommend you just pull down the code and play with it. The ideas are very simple, but the power it gives you is vast.
The code is on Github with a very simple test suite showing usage.
The API is very simple. You pass in a instance of a Django model, and you can get off the values that you care about.
from django_inspect import base
intro = base.Inspecter(comment)
self.assertEqual(intro.content.field, 'comment')
self.assertEqual(intro.content.value, 'First here, too!')
This example is using a Django comment, as you can see. When you get a comment object, you want to see what the actual "content" of it is. Normally, this requires special casing in your code, or somewhere else. However, here we see it's just intro.content.value, to get the value, or .field to get the name of the content field.
The idea is that you have pluggable "parsers" that have names, which then map to fields on the model. By default, the name of the parser is checked, and any mappings you have passed in. Then it will go ahead and execute any custom logic that is associated with that parser.
So for this example, the "content parser" knows about comments, so it knows to check for the "comment" field for it's main content. This lets this mapping of content to fields to live inside the parser, and lets the user of the Inspecter to just say "I want the content".
Again, it's just easier if you read the code, it's really pretty simple.
Django Inspect also has the concept of mapping models to fields. So you can create a simple dictionary and pass it into your Introspection class, and it will map those keys to the corresponding fields. An example is worth a thousand words:
DEFAULT_MAPPINGS = {
'comments.comment': {
'content': 'comment',
'pub_date': 'submit_date',
}
}
I call this the "Mingus use case". For example, if Mingus wanted to be able to introspect any of it's reusable apps for what it's "pub_date" or "content" fields were, it could ship with a mapping for all of the reusable app models, and then you would be able to write generic code that would work across all of those apps.
This is partially inspired by South's support for app migration directories
Say I am using Nathan Borror's Fantastic Basic Blog. It has it's Blog Post model defined as such:
class Post(models.Model):
STATUS_CHOICES = (
(1, _('Draft')),
(2, _('Public')),
)
title = models.CharField(_('title'), max_length=200)
slug = models.SlugField(_('slug'), unique_for_date='publish')
author = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(_('body'), )
tease = models.TextField(_('tease'), blank=True, help_text=_('Concise text suggested. Does not appear in RSS feed.'))
status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=2)
allow_comments = models.BooleanField(_('allow comments'), default=True)
publish = models.DateTimeField(_('publish'), default=datetime.datetime.now)
created = models.DateTimeField(_('created'), auto_now_add=True)
modified = models.DateTimeField(_('modified'), auto_now=True)
categories = models.ManyToManyField(Category, blank=True)
tags = TagField()
objects = PublicManager()
When I go ahead and create an inspecter class for this, I will be able to define what fields I want to map onto what. So for example, here the 'content' field of the blog post is actually called "body". I could create a simple mapping for this model, or I could modify the default parser to make the "content" field look for "body" models.
BLOG_MAPPING = {
'blog.post': {
'content': 'body',
'pub_date': 'publish',
}
}
from django_inspect import base
ins = base.Inspecter(post, BLOG_MAPPING)
Now the following fields should have the following values:
ins.content.field: 'body'
ins.content.value: <Whatever my blog post is about>
ins.pub_date.field: 'publish'
ins.pub_date.value: <When my blog post was published>
There are a lot of interesting API niceities that could be added in on top of this code. I want to keep it really simple, however there is room for improvement. A couple that I have thought of:
The whole idea of releasing this is to get feedback on what the actual API should look like. I think it's pretty awesome currently for the simple case, but for more advanced use, it's going to need to grow some features.
The whole idea behind this is that if your code is named or modeled sanely, it should "Just Work". However, if you have a crazy data model, or have to depend on wonky third party apps outside your control, it is incredibly simple to map and introspect those models as well.
The other powerful idea is the application of semantics to models. I can query your model for the "content" or "tease" field, and be able to define exactly what that is. This lets me build interfaces and applications that "know" more about their data, even when that data is unknown at the time of writing.
This gives the application developer the power to write truly generic applications that will work with any suitable model. At least I hope so :). I have some other ideas that fall out from the implications of this introspection code that I will be talking about at Pycon, and probably doing a lightning talk. So feel free to find me and I probably won't shut up about it.
Posted at 11:48 a.m. on February 14, 2010
Comments: 8
Tags: django , inspect , introspection , proofofconcept
Should reusable apps have templates?
Announcing Django Crawler and django-test-utils
Django stands for Awesome
Welcome to the home of Eric Holscher on the web. I talk about software development, mostly in the realm of Django. I am interested in the real time web, testing, mobile apps, and other things.
Why Read the Docs matters
2 weeks, 1 day ago (Comments: 7)
Read the Docs Update
10 months ago (Comments: 2)
Using Reviewboard with Git
1 year ago (Comments: 0)
Read the Docs Updates
1 year ago (Comments: 1)
Handling Django Settings Files
1 year ago (Comments: 12)
Required Reading
1 year, 2 months ago (Comments: 0)
Using Haystack to index non-database content
1 year, 2 months ago (Comments: 4)
Correct commands to check out and update VCS repos
1 year, 2 months ago (Comments: 0)
Site upgrades
1 year, 2 months ago (Comments: 0)
Building a Django App Server with Chef: Part 4
1 year, 2 months ago (Comments: 1)
Setting up Django and mod_wsgi
Building a Django App Server with Chef: Part 1
Screencast: Django Command Extensions
Big list of Django tips (and some python tips too)
Handling Django Settings Files
Lessons Learned From The Dash: Easy Django Deployment
Large Problems in Django, Mostly Solved: Delayed Execution
Building a Django App Server with Chef: Part 2


Comments
1 Panos Laganakos says...
Very nice idea, this opens up so many possibilities!
Grabbing the code from github right about now :)
Posted at 9:01 p.m. on February 14, 2010
2 kevin says...
Very cool Eric.
Conceptually this remind me of some of the ideas behind Django-Proxy (which Mingus actually uses for content-type aggregation). That solutions uses a subclass ProxyMeta to define field mappings as well and then signals handle the introspections to align everything for aggregation.
I'll have to spent more time taking a peek but your solution may be a bit more decoupled since there's no subclass required, which is nice. I've been meaning to blog about Django-Proxy so maybe that's something I should sit down and do.
Posted at 9:20 p.m. on February 14, 2010
3 Kevin says...
edit: I meant inner class, not subclass above. brain fart, excuse me.
Posted at 9:29 p.m. on February 14, 2010
4 Drew says...
Interesting... I've been contemplating the problem of "structured" emitters for Piston. For example, emitting RSS, iCal, etc... where field mapping is necessary to shape the output. This would appear to have practical application there.
Posted at 5:39 p.m. on February 22, 2010
5 florian says...
I read your blog frequentl and I have to admit it's really interzsting ! :)
Posted at 12:32 p.m. on April 3, 2010
6 anerfinna says...
<a href="http://videoexclg11.vidiLife.com">GILLIAN ANDERSON NUDE</a> http://videoexclg11.vidiLife.com - GILLIAN ANDERSON NUDE <a href=http://videoexclg11.vidiLife.com>GILLIAN ANDERSON NUDE</a> http://videoexclg11.vidiLife.com - GILLIAN ANDERSON NUDE <a href="http://videoexclg12.vidiLife.com">ALI LARTER NUDE</a> http://videoexclg12.vidiLife.com - ALI LARTER NUDE <a href=http://videoexclg12.vidiLife.com>ALI LARTER NUDE</a> http://videoexclg12.vidiLife.com - ALI LARTER NUDE <a href="http://videoexclg13.vidiLife.com">BRITNEY SPEARS DESNUDA</a> http://videoexclg13.vidiLife.com - BRITNEY SPEARS DESNUDA <a href=http://videoexclg13.vidiLife.com>BRITNEY SPEARS DESNUDA</a> http://videoexclg13.vidiLife.com - BRITNEY SPEARS DESNUDA <a href="http://videoexclg14.vidiLife.com">FILIPINA CELEBRITIES</a> http://videoexclg14.vidiLife.com - FILIPINA CELEBRITIES <a href=http://videoexclg14.vidiLife.com>FILIPINA CELEBRITIES</a> http://videoexclg14.vidiLife.com - FILIPINA CELEBRITIES <a href="http://videoexclg15.vidiLife.com">FREE CELEBRITY SEX VIDEOS</a> http://videoexclg15.vidiLife.com - FREE CELEBRITY SEX VIDEOS <a href=http://videoexclg15.vidiLife.com>FREE CELEBRITY SEX VIDEOS</a> http://videoexclg15.vidiLife.com - FREE CELEBRITY SEX VIDEOS
Posted at 6:15 a.m. on April 27, 2010
7 rand says...
comment here
Posted at 4:40 a.m. on July 10, 2010
8 autoversicherung says...
last week our group held a similar discussion on this topic and you illustrate something we have not covered yet, thanks.
Posted at 11:14 a.m. on October 28, 2010