Django, CakePHP and CodeIgniter, part 3: Models, data, relationships and foreign keys

I have written this post to annotate something I have been studying – which is how do I use Django, CakePHP and CodeIgniter to create database tables for my web application. This approach, especially the comparative aspect, has made it possible for me to understand a few new things about Object-relational mappers (the active record pattern) which let us get data from dbs as if they were objects. I noticed that something that is simple with a JOIN query to get data from two tables related through a Foreign Key, that is knowing all the comments for a post and which post a comment is related to, is not that immediate with objects. I even got to chat about it with Larry E. Masters (PhpNut), the author of CakePHP (I am very thankful for his help, patience and attention). I will also explain the clever technique with objects that Django (written in Python) uses to get around this, and the CodeIgniter Active Record pattern approach.

This post can’t be a tutorial on frameworks and databases. I am not an expert, I am just learning. Please correct me if I get something wrong! And the issue is so complex. you could write a book about it. But I will still start the post with a theoretical overview about what a model is as far as mapping real world problems into something computational, what a model is in the model-view-controller pattern, how databases fit into the picture, and so on. I mean, I will take it very slowly, from the beginning. But you can still jump to any chapter that interests you particularly (I have added anchors).

So, if you want to, click “Continue reading”.

P.S. Check out my new CodeIgniter themed blog post about Objects in frameworks – those who get the work done . Object interaction, creating custom classes/libraries, extending the CodeIgniter super object. Study/work notes, basically.

INDEX:

WORLD, COMPUTER, MODEL, VIEW, CONTROLLER
MODELS, WITH OR WITHOUT DATABASES
ACTIVE RECORD OR OBJECT RELATIONAL MAPPING PATTERN
DJANGO DB MAGIC
DJANGO RELATIONSHIPS
BACKWARDS RELATIONSHIPS – FROM PARENT TO CHILD AND BACK
QUERYING DJANGO’S DBS
CAKEPHP – BOTH MODELS NEED TO BE TOLD
CODEIGNITER’S ACTIVERECORD APPROACH

WORLD, COMPUTER, MODEL, VIEW, CONTROLLER

Computation is what we do when we “take a description of a problem and map it into something computational”, as we’ve learned from MIT’s Open Course Ware (see previous post). When we do this we create models. Like we can put something in words, we can also put it into models, algorithms and code – code a computer can understand and run.

The word model might remind you of various things, including the Model-View-Controller software pattern. This is because computer programs running software versions of models often interact with the outside world, and one way of doing it is described with that pattern. We could say that the Controller looks at the outside input and “knows” what to do with it, with or without getting the Model involved, and then uses the View to output the results.

MODELS, WITH OR WITHOUT DATABASES

But let’s concentrate on the model for now. It may look like the model is the part that connects to the database. That could be one of the things that the model does, but is only a part of a bigger picture. Plus, even if model does need data, it doesn’t need to be taken from a database, it can be scraped off the web, gotten from XML, a digital telescope, motion detector, any input through Arduino, etc. A model can create its little map of a real world problem, and then map a data source into it.

But let’s stick with the databases for now, because most often that’s what we’ll be using. Relational databases are a nice way to represent a real life situation – we are imagining the world like an organized system of stuff and relationships between stuff. For example, if you need to store users and their books, different users may share same books and books may be added. So you have a table with users, a table with books, and then create relationships between them. That’s why relational tables are more then just rows and columns. Either way, a JOIN query can let you see the complete picture. JOIN is when you tell the query too look at more then one table and consider their relationships, say when looking for all users who have read a certain book. Look up normalization (Wikipedia, Stack Overflow).

ACTIVE RECORD OR OBJECT RELATIONAL MAPPING PATTERN

Traditionally, web developers had to create DB tables and write SQL queries by hand (hand being the one typing the code that generates the query). With frameworks like Django, CakePHP and CodeIgniter, there is another approach. They use Object-relational mapping (ORM, see Wikipedia). Since programmers tend to keep data and behaviors in objects anyway, this technique maps the database into objects, so that data in there can be accessed like it was in any other object. You don’t need a framework to do that, BTW. You can just use a library. I am a bit confused by the terminology, because some use the name Active record pattern for this technology (Ruby ActiveRecord library is just one of many implementations). But the idea is clear and simple. Now let’s see how do our frameworks make this work.

DJANGO DB MAGIC

Django makes for a pretty painless and fun use of databases. Even though too much auto-magic  may not be seen as a good thing by everyone. When you install Django, you just edit a settings.py file and choose your database. First time you try Django, you don’t necessarily need a web server or a particular database, you can just use the development server shipped with Django and a SQLite db. The tables you want to be created will be simply described in the models.py file (each app has one – a Django application is structured into a project that contain apps).

For example, you could have a blog, which needs authors, posts and comments. The example that can be found in the Django official tutorial is that of an app for polls. Polls need choices. So the model.py file will contain this:

from django.db import models

class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField(‘date published’)

class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
votes = models.IntegerField()

That’s all. You don’t need to actually create tables by hand. Obviously, in order to describe the tables you want inside models.py, you need to have an idea of how databases operate. If you save models.py (make sure your app is added to the apps list in settings.py) and then run the command

python manage.py sql polls

you will see  which SQL queries will be used to create your tables. If you run

python manage.py syncdb

the tables will be created. That is, the database will be synchronized to the models (for all the installed apps, even the default ones that can be removed).

DJANGO RELATIONSHIPS

Relationships in relational databases can be one to many (or many to one) using ForeignKey, many to many using ManyToManyField, or one to one using OneToOneField. It’s easy.

BACKWARDS RELATIONSHIPS – FROM PARENT TO CHILD AND BACK

I can’t fit all the different aspects of this argument into a single post. But there is an interesting aspect to underline –  backwards relationships.

When there is a relationship like the one between the polls and the choices tables, the choices table is the child table, and the polls table is the parent table. It is easy, with JOIN queries, to find out both which children does the parent have, and which parent does the child have. It’s not as simple with the frameworks which access the databases through the objects that databases are mapped into. In this case, it appears that the child would know it’s parents, but that the parent wouldn’t know about its children.

Frameworks solve this in different way. Sometimes you have to declare the relationship in both the child and the parent part of the model, as we will see later. Django makes it easy. Here is the explanation from the Django 1.2 online documentation.

How are the backward relationships possible?

Other object-relational mappers require you to define relationships on both sides. The Django developers believe this is a violation of the DRY (Don’t Repeat Yourself) principle, so Django only requires you to define the relationship on one end.

But how is this possible, given that a model class doesn’t know which other model classes are related to it until those other model classes are loaded?

The answer lies in the INSTALLED_APPS setting. The first time any model is loaded, Django iterates over every model in INSTALLED_APPS and creates the backward relationships in memory as needed. Essentially, one of the functions of INSTALLED_APPS is to tell Django the entire model domain.”

QUERYING DJANGO’S DBS

Django has an interactive shell, which is like the normal Python interactive shell (very useful itself), but with the right environment. So, as the tutorial shows, you can use this shell to practice accessing the data in the db. For instance, you get all the polls with “Poll.objects.all()”, a particular poll with something like “Poll.objects.filter(id=1)” or “Poll.objects.filter(question__startswith=’What’)”. As the tutorial explains:

“# Choice objects have API access to their related Poll objects.
>>> c.poll
<Poll: What’s up?>

# And vice versa: Poll objects get access to Choice objects.
>>> p.choice_set.all()”

CAKEPHP – BOTH MODELS NEED TO BE TOLD

With CakePHP there is a little bit less automagic to table creation – you create a table yourself. By hand.

CakePHP relationship types are: hasOne for one-to-one, hasMany for one-to-many, belogsTo for many-to-one and hasAndBelongsToMany for many to many. One to many and many to one are separated, to have them both work you need to use both. This particularity is probably necessary because CakePHP doesn’t do all that fancy object lookup stuff that Django does, so it is tricky for an object to know that another object is related to it.

I asked about this on the CakePHP IRC channel and was thrilled to get a response from Larry E. Masters (PhpNut), the author of the framework, who explained the reasons. For instance, he wrote that “some things are better left alone when trying to do a lot of ‘magic'”, and that for auto-detection one should look into the bake application. Plus “defining the associations allows better handling of legacy tables, ability to disable them easier and other things”. And PHP 4 also limited his design choices at the time, and he doesn’t exclude maybe in the future implementing new interesting things. Any user can, however also try “overriding the __constructor() in your AppModel to bypass the way cake handles it and rewrite your own association code…” but “you would need to look @ the other methods called from within the constructor too”. I might decide to attempt that some day, who knows 🙂

Bake is an application for easily and automatically generating CakePHP code, with a simple dialog interface.

CODEIGNITER’S ACTIVERECORD APPROACH

CodeIgniter’s approach is even less automagical so it’s even easier to grasp if you already know simple relational databases basics. Not only do you create your own tables, but the way of querying them is more similar to just using the usual SQL queries then the CakePHP and Django approach, where you were getting data out of objects like they were any other kind of objects and not at all database tables. Learn more about this from the CodeIgniter ActiveRecord online documentation.

0) No More Static Web Sites (learning from mistakes #1)
1) part 1 : downloading – planting the framework tree
2) part 2: how does the server talk to the framework?
3) Django, CakePHP and Codeigniter, part 3: Models, data, relationships and foreign keys
4) Django, CakePHP and CodeIgniter, part 4: the Model-View-Controller or Model-Template-View interactions
5) Objects in frameworks – those who get the work done – CodeIgniter notes

Advertisements

About apprenticecoder

My blog is about me learning to program, and trying to narrate it in interesting ways. I love to learn and to learn through creativity. For example I like computers, but even more I like to see what computers can do for people. That's why I find web programming and scripting especially exciting. I was born in Split, Croatia, went to college in Bologna, Italy and now live in Milan. I like reading, especially non-fiction (lately). I'd like to read more poetry. I find architecture inspiring. Museums as well. Some more then others. Interfaces. Lifestyle magazines with interesting points of view. Semantic web. Strolls in nature. The sea.
This entry was posted in frameworks, tutorials and tagged , , , . Bookmark the permalink.

2 Responses to Django, CakePHP and CodeIgniter, part 3: Models, data, relationships and foreign keys

  1. blagi says:

    Hi!
    Looks like we both using same or similar tools. I’m a web programer for a month and using/learning PHP, CodeIgniter, Javascript, Ajax, Jquery, … Learning a MySql too. Haven’t enogh time for a moment but these links looks promising.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s