Matt Seymour

Unlike other programming languages Javascript does not have a native range function. By range function I am talking about a function which given an integer will return an Array/List with sequential values.

For example in Python you can do the following:

> range(5)
< [0, 1, 2, 3, 4]

Or, if you want the numbers 1-5:

> range(1, 6)
< [1, 2, 3, 4, 5]

The good news is you can simulate a basic range function with the following if not slightly elongated code:

> Array.from(Array(5), (_, x) => x +1 )
< [1, 2, 3, 4, 5]

After updating my machine today I came across the following error:

error: There was a problem with the editor 'vi'

The issue appears to be a problem relating to the default editor git is using. The issue can be easily fixed by running the following command:

git config --global core.editor `which vim`

It is simple to launch sublime text from command line on OSX you simply need to symlink a file found within the Sublime Text installation directory to /usr/local/bin.

This can be done using the following command:

ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl /usr/local/bin/subl

Within your favourite OSX terminal / shell you can now use the command: subl to launch sublime text.

By default brew will give you access to the latest version of python via the brew install command. But what if you want to install a specific version?

The simplest option is to use pyenv it allows you to install python specific versions to your machine.

Usefully pyenv is available as a brew package:

brew install pyenv

Note: Read through the command line summary and caveats after installing. It will allow you to better configure your setup. For example I would rather make use of the "Homebrew directories rather than ~/.pyenv" to do this add the following line to your profile (.bashrc, .zshrc).

export PYENV_ROOT=/usr/local/var/pyenv

To enable auto complete also include:

if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi

Once installed you can now download and install the python specific versions you are looking for. To do this use the following commands:

pyenv install 3.4.4

If you are wanting to make this work with virtualenv you can set the python environment setting using the -p, --python flag.

virtualenv -p <path to python bin>

virtualenv -p /usr/local/var/pyenv/versions/3.4.4/bin/python
# or
virtualenv -p ~/pyenv/versions/3.4.4/bin/python

When trying to format json in vim you can use the following command which makes use of the python json.tool

:%!python -m json.tool

Here is an example of the command at work

1 {
2     "name": "my-project-name",
3   "version": "0.1.0",
4     "devDependencies": {
5             "grunt": "~0.4.5",
6                 "grunt-contrib-jshint": "~0.10.0",
7                 "grunt-contrib-watch":"~1.0.0"
8                           }
9                           }


:%!python -m json.tool



> Output
1 {
2     "devDependencies": {
3         "grunt": "~0.4.5",
4         "grunt-contrib-jshint": "~0.10.0",
5         "grunt-contrib-watch": "~1.0.0"
6     },
7     "name": "my-project-name",
8     "version": "0.1.0"
9 }

In bash and zsh you can use an in command shortcut to use the last parameter of the previous command as an argument for the next command.

For example say you view the contents of a file using cat:

cat /path/to/file/name.txt

Now you realise you want edit the file in some way. Instead of typing the command: vim /path/to/file/name.txt you can instead use:

vim !$

Or even the following example:

> cat /path/to/file/name.txt
> mv !$ /new/file/path.txt

Not only does this save you some valuable keystrokes, it is also quicker and less error prone.

By default Finder in OSX hides a lot of files from the user. This is useful if you are a standard user but when you need access to /usr, /var or /Library this is really annoying. To enable finder to show all enter the following command into terminal.

defaults write com.apple.finder AppleShowAllFiles TRUE

You will then either need to logout your profile or run the command:

sudo killall Finder

Last month I wrote the article 'How to convert a file path into a file url'. This month lets convert a file url into a python file path.

import urlparse, urllib

file_url = 'file:///Users/auser/a.file'
file_path = urllib.url2pathname(urlparse.urlparse(file_url).path)
> output: /Users/auser/a.file

The python code to convert a url path to a file:// url.

import urlparse, urllib
path = '/Users/myuser/a.file'

urlparse.urljoin(
  'file:', urllib.pathname2url(path)
)

> output:: file:///Users/myuser/a.file

As a backend developer I generally work with python, (some PHP) and C#. The front-end web development tools whilst alien to me are not something I get to spend a lot of time working on. So I thought I would try out writing my own grid system for CSS.

I introduce Griddy a(nother) micro CSS framework.

The idea behind Griddy was partly to be a learning exercise into CSS and responsive development but also to be something which I can use in various projects moving me away from Bootstrap. Whilst bootstrap has served me well and I make good use of it I find it is bloated for the functionality I require.

Current features of Griddy:

  • Mobile first
  • Responsive
  • Simple
  • Media breakpoints : 768px, 950px, 1200px

The source for Griddy can be found at https://github.com/mattseymour/griddy/.

Within linux it is possible to pause (freeze) and start processes.

Before you can pause a process you need to know the process ID (pid). This can be done using the ps command.

ps -A | grep <process_name>
# a process might not be obviously named

The output will be something like:

matt@wasdy : ~
   [1510|09:10:52] $  ps -A | grep chrome
    2777 ?        00:01:14 chrome
    2790 ?        00:00:00 chrome
    2811 ?        00:00:00 chrome
    2827 ?        00:00:59 chrome
    2835 ?        00:00:00 chrome
    2842 ?        00:00:02 chrome
    2862 ?        00:00:03 chrome
    2874 ?        00:00:00 chrome
    2890 ?        00:00:00 chrome

What we are interested in is the first number this is the process ID which we will use pause and start the process.

Pausing a process

In the command line run the following command:

sudo kill -STOP <pid>

At this point your application will appear to stop working. Well the process is paused... duh

Re-starting a process

In the command line run the following command:

sudo kill -CONT <pid>

Linux kernel 4 has been release and can be installed and upgraded. Whilst the Ubuntu repository is still currently on version < 3.19. Kernel 4 does have a number of useful and features and bug fixes.

To install and upgrade your current kernel version you first need to download the deb packages from kernel.ubuntu.com. To install a new kernel version you will need to download 3 packages.

  • linux-headers-4.*_all.deb
  • linux-headers-4.*_{i386|amd64}.deb
  • linux-image-4.*_{i386|amd64}.deb

Downloads can be found in the kernel.ubuntu.com main steam site.

When choosing your download I recommend not downloading anything which is an RC (release candidate) unless you need to for a specific reason (like bug fixes). The latest kernel releases will be towards the bottom of the page.

Once you have downloaded your three files as stated above proceed to install them using:

sudo dpkg -i ~<path-to-deb>
# install in the order stated above

Once installed you will need to update grub to use the newest installed version of the kernel. This is done by running:

sudo update-grub

Now, restart your machine and in terminal type uname -r your kernel version should now be updated.

Notes: Kernel version 3.19 has a bug which means juniper VPN will not work. If you are running this kernel version you will need to upgrade to a newer kernel version to resolve this issue. If you are running 15.04 you can upgrade to Linux kernel 4.

Juniper VPN kindly do not offer a 64bit deb package for Ubuntu users. This means you need to find a way to install and run the VPN on your own. With Ubuntu 15.04 being relatively new at the time of writing this may be a little more difficult than it needs to be for some users.

Hopefully this installation guide will get you up and running with little fuss.

First I started by installing openjdk and the icedtea plugin and xterm:

sudo apt-get install openjdk-7-jdk icedtea-7-plugin xterm

Followed by installing the 32bit version of the openjdk 7.

sudo apt-get install openjdk-7-jre:i386

Once installed you should check that update-alternatives is sym-linked in /usr/sbin/ this can be done by running the command:

ln -s /usr/bin/update-alternatives /usr/sbin/

Update the java version being used by update-alternatives to be java-7-openjdk-amd64/jre/bin/java:

sudo update-alternatives --config java
# select the option which is the recently downloaded java-7-openjdk-amd64/jre/bin/java

At this point if you try to run the juniper network tool you may get an error saying 32bit library files are missing. You will need to install the following packages so these errors do not appear.

sudo apt-get install libstdc++6:i386 lib32z1 lib32ncurses5 lib32bz2-1.0 libxext6:i386 libxrender1:i386 libxtst6:i386 libxi6:i386 libbz2-1.0:i386

Now restart firefox and log into the juniper vpn. You should now be able to access and install the VPN client software.

When installing pycurl via pip a number of errors can occur during the build process. The most likely cause of this is missing dependencies which are required to build the package. The good news is this can be easily fixed by installing the missing libraries and retrying the install.

Example error raised by pip when installing pycurl:

In file included from src/docstrings.c:4:0:
src/pycurl.h:145:31: fatal error: openssl/crypto.h: No such file or directory
 #   include <openssl/crypto.h>
                               ^
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

Solution

Within Ubuntu install sudo apt-get install libssl-dev libcurl4-openssl-dev python-dev. Then re-run the pip install pycurl command to install the package without error.

Linux kernel 4 has been release and can be installed and upgraded. Whilst the Ubuntu repository is still currently on version < 3.19. Kernel 4 does have a number of useful and features and bug fixes.

To install and upgrade your current kernel version you first need to download the deb packages from kernel.ubuntu.com. To install a new kernel version you will need to download 3 packages.

  • linux-headers-4.*_all.deb
  • linux-headers-4.*_{i386|amd64}.deb
  • linux-image-4.*_{i386|amd64}.deb

Downloads can be found in the kernel.ubuntu.com main steam site.

When choosing your download I recommend not downloading anything which is an RC (release candidate) unless you need to for a specific reason (like bug fixes). The latest kernel releases will be towards the bottom of the page.

Once you have downloaded your three files as stated above proceed to install them using:

sudo dpkg -i ~<path-to-deb>
# install in the order stated above

Once installed you will need to update grub to use the newest installed version of the kernel. This is done by running:

sudo update-grub

Now, restart your machine and in terminal type uname -r your kernel version should now be updated.

So last week I was lucky enough to find a weekend (21st-22nd March 2015) where I could afford the time to go up to London and participate in Django Sprint London. It was a one and a half day event focused on meeting fellow Django community members as well as being able to contribute further to the Django community. The event took place in the well equipped offices of Potato.

The event was split into two parts. Day one (evening meetup) was a chance for community members to meet, chat, and learn from some talks; as well as have a few beverages. Talks were given by:

Luke Benstead on Djangae Google Slide

Baptiste Mispelon on Contributing to Django in a Nutshell

Marc Tamlyn on Whats new in Django 1.8

Day 2: Let the sprints begin

Sunday morning was when the sprinting started. Arriving at the offices of Potato in London at 9am I was greeted with the smell of coffee and pastries. Upon setting up it was time to get down to business. To start the day off I picked a couple of easy picking tickets from Djangos current list of issues (Django uses trac for issue monitoring). Upon completing these tickets I then moved my attention to some more challenging tickets before lunch.

The afternoon was spent looking into support issues for the djangoproject.com website. Whilst contributing to the django framework is something I had done multiple times in the past, actually contributing to the project website was something I had previously overlooked. I would recommend others contributing to this project as it is something which can be overlooked by the community.

The end of the day for me was at 4:30, overall the day was a great learning and sharing experience. It was great to be able to put names to faces and meet new Django-ers from across Europe.

Whilst upgrading between Gitlab 6.x to 7.7 an error occurs because of a missing database migration.

After successfully running:

gitlab-rake db:migrate

I opened the webserver logs to see 500 errors from from the /projects/ url.

ActionView::Template::Error (PG::Error: ERROR:  column projects.imported does not exist

It looks as though whilst the migrations successfully complete they miss this one crucial migration.

Solution: Open your database connection and run the command.

ALTER TABLE projects ADD COLUMN "imported" BOOLEAN DEFAULT FALSE NOT NULL;
/usr/bin/env: node: No such file or directory

The above error can occur when running nodejs on Ubuntu. The cause of the error is simply that node cannot be found on your system PATH. The reason for this error is that within the Ubuntu software repository there is another application called node which can use /usr/bin/node which is not nodejs. To resolve this nodejs instead use the binary name nodejs and not node like some would rather it.

What this means is that some node modules reference the wrong node when in Ubuntu.

So the solution:

To resolve this issue you can simply symlink /usr/bin/nodejs to /usr/bin/node. This will mean both node and nodejs are available on the system path.

Open a terminal and using sudo enter:

sudo ln -s /usr/bin/nodejs /usr/bin/node

In some cases people have been finding ruby web applications in development very slow to respond (upwards of 3-7 seconds). The issue seems to be caused by the introduction of a new webrick configuration option DoNotReverseLookup which has a default value of nil (false). By simply changing the value of this (overriding the global default) webrick will not perform a reverse DNS lookup for each request substantially speeding up each page request.

Solution:

Change the default value of the webrick configuration option DoNotReverseLookup to true.

Old:

:DoNotReverseLookup => nil,

New:

:DoNotReverseLookup => true,

There is no built in git dry run option which is a shame as it is a feature I would use all the time. But there is a way to simulate this without polluting the git history.

Performing a git merge with no commit or no fast-forward will merge the two code bases together. This will allow you to examine, test, and undo the merge if required.

git merge --no-commit --no-ff <branch-name>

If you need to undo the commit you can use:

git merge --abort

This will return git to its state before the merge occurred.

If you are wanting to create a copy of a file from a specific git commit you can do so by using the following git command:

git show 32206111:my-app/indirectory/file-to-copy.py >> my-app/indirectory/copy.py

The first part of this command shows the content of a particular file for a specified commit. The second part of the command writes the content of the first part of the command to the specified file.

The Django send_mail function is a really simply way to be able to send an email via Django. It requires setting only a few parameters and Django settings in order to be able to send emails from your application.

A common question asked when using Django send_mail is how do I set the reply-to email header.


tldr; Use the EmailMessage class set the header (named argument) to {'Reply-To':'reply-to@example.com'}


What is Reply-To?

Reply-To serves as a way to respond to an email but to a different email address than an email was originally from. For example an email may be sent from a server (server@example.com) but the reply-to address maybe to an admin (admin@example.com); this will mean if you choose to reply to the message from server@example.com you will be sending an email to admin@example.com.

Whats the use of this?

Setting an email Reply-To means your Django web application can send emails from a valid email account. But all responses will be going to another valid email account. This comes in useful for things like contact forms using email.

So how do I set Reply-To in Django?

The easiest solutions is to make use of the class EmailMessage.


from django.core.mail import EmailMessage
email = EmailMessage('This is the subject', 'This is the body of your email', 'from@example.com',
        ['to@example.com',], headers = {'Reply-To': 'another@example.com'})
# send() sends the email
email.send()

If you run a virtual environment (virtualenv / virtualenvwrapper) at some point you will want to upgrade your python version. As it stands there is no built in way of doing this so the steps below are required to upgrade.

1. Freeze your current virtual environment pip freeze > requirements.txt

2. Remove your existing virtual environment


# if using virtualenvwrapper
rmvirtualenv <environment name>
# virtualenv
rm -r /path/to/virtual/environment

3. Create your new virtual environment


# virtualenvwrapper
mkvirtualenv -p /path/to/python/version <environment name>
# virtualenv
virtualenv -p /path/to/python/version <environment name>

4. Load new virtual environment


# virtualenvwrapper
workon <environment name>
# virtualenv
source /path/to/virtual/environment

5. Install the pip dependencies from requirements.txt


pip install -r /path/to/requirements/file

You have been working hard building your app. Now has come the time to deploy your application to production but there is one question you have which wsgi server shall I use? Your two real options for Django are Gunicorn or uWSGI. Both integrate easily with Django and you can get them up and running (as a beginner within an hour).

But which one should you choose?

tldr; Either Gunicorn or uWSGI correctly configured will give you more than adequate performance for your website. Go with the wsgi server you think is best suited for you.

Okay first things first...

I will not be comparing the performance of Gunicorn and uWSGI. There are a number of reasons, primarily being there are a large number of posts talking about performance. Simply put either wsgi server will give you more than enough performance if configured correctly.

Introducing uWSGI uWSGI is a high performance, powerful wsgi server. It has a massive number of configuration options (personally I think too many) to allow you to tailor your server to your needs. Though a large number of the options you will never need to use. uWSGI works well with nginx as nginx talks uwsgi by default. A basic wsgi server can be setup easily but to tailor the server for your system will take time as you figure out all the configuration options.

Introducing Gunicorn

Gunicorn is a simple, performant, and easy to setup and configure. Gunicorn may not be as performant as uWSGI (depending on your source ~10-15% down on max requests per second), but it is still fast the standard user would have no idea of the performance difference. What Gunicorn loses in performance it gains in simplicity and ease of use; Gunicorn has a fraction of the options than uWSGI. A Gunicorn wsgi server can be set up and running in less than 10 minutes.

So which one is better?

uWSGI is highly configurable (maybe too much so), whereas Gunicorn is simpler. Both have more than enough performance to run any website at scale. You have to remember that in most web applications the datastore and API calls will be the performance bottleneck.

The question you need to ask yourself is this: Is the extra time spent configuring uWSGI beneficial to your application, or would the time saved using Gunicorn. The Gunicorn settings file can easily be made to work with uWSGI; so one option is to start by using Gunicorn and if the situation requires it make the move to uWSGI.

My personal preference is towards the Gunicorn wsgi server. Whilst offering excellent performance, it is simple to configure, well documented and can be used whilst developing my Django applications locally. When used with supervisord it provides a stable well rounded system.

Earlier this month I released python-envvars, a python library which can read the contents of a .env file adding the key->values into pythons os.environ dictionary. The idea behind envvars is to make it easier to add environment variables into a python web application (django, flask etc).

By storing configuration settings within environment variables it allows your application to be easily moved from server to server without having to alter the code base of your application. Using .env files as to the host systems environment variables means you simply have to upload the .env file not messing around with the host system setup. The .env files can be stored in you secure files location keeping credentials safe.

A .env file looks something like:

SECRET_KEY=AbCdEfG
DEBUG=False
SOME_VARIABLE=1348904

The envvars package is available on pypi and can be installed using:

pip install envvars

To load the contents of the .env file into your application you simply call.

import envvars
import os

envvars.load('/path/to/file/.env')

print os.environ['SECRET_KEY']
> AbCdEfG

Envvars also has a get method which will get a value from os.environ. environ.get('KEY') has the added ability to return the value as its python type. For instance:

import envvars
import os

envvars.load('/path/to/file/.env')

print envvars.get('DEBUG')
> False # type boolean

print envvars.get('SOME_VARIABLE')
> 1348904 # type int

# if the .env value of SOME_VARIABLE was "1348904"
# Then the return value of envvars.get('SOME_VARIABLE') will be type str

Ways to use environment variables in Django.

  1. Store settings in environment variables

By storing settings in environment variables you can freely store your project on machines without the extra precautions relating to sensitive information.

Storing items like your SECRET_KEY, and database passwords within the environment variables mean they can be set on a per-environment basis.

Example


SECRET_KEY = os.environ.get('PROJECT_SECRET_KEY')

Storing environment variables:

My single biggest annoyance with environment variables are setting them when provisioning or running a server in production. My personal solution is to use envvars a small package I created for handling environment variables when running applications as different users.

As a developer I regularly try to attend hack days. They offer a chance to meet other developers, people and companies in your community; work on something interesting and potentially win some great prizes.

Here is a basic kit list for successful hacking:

Laptop

Most importantly you need your laptop. Make sure it is loaded with everything you might need prior to attending the event. Not only does it save time, but it also saves you the agony of trying to download and install software on an internet connection which could be worse than rubbish.

3G/ 4G phone

It seems to be that even the best organised hack days cant seem to keep the internet up and running. If the internet is important for your project make sure you can tether your phone and computer. It will keep you running whilst those around you are struggling to get things working.

Ethernet cable

At many hack days the organisers will offer a cabled network option. Be prepared take a length of ethernet cable. If you think the wireless is going to go down or be unreliable get your ethernet cable connected before others get there.

Software

Before your leave home ensure you have all the software installed and configured on your laptop. Also ensure your have downloaded any documentation you may need.

Small pillow

At a hackathon there is a good chance you will end up like this at some point.

A small pillow is a nice to have and highly practical at most hackathons. There is the chance you will be sitting down for hours working on a project a pillow allows you to keep comfortable as well as offer a place to rest your head if you need to 10 minute nap.

Hardware

If you are doing a hardware hack then hopefully it speaks for its self you need to take some hardware with you. For hardware hacks its recommended to take slightly more hardware than you need to ensure you have what it needs to complete your hack.

List of Ideas

At most hackathons I try to go along with at least 5 ideas for projects. Having a hack list helps you started coding sooner and allows you to form a team easier. It is also nice to share ideas with other developers who might be struggling to come up with ideas.

As you may or may not know Django is an awesome framework for web development. Its complete, simple to code, and well documented. But as with every thing there are a few things that just plain frustrate and annoy me about working with it that I would like to see worked on and improved.

1. Django communities reaction to MySql

2. Deployment

Probably my single biggest problem with django is the ease of deployment.

3. The need for a better initial project layout

I think most people would agree that the first thing they do when starting a django project is completely change the layout of the default project structure. Django by default creates applications in the project root directory.


# default project
| My project dir
    | Project folder
        | settings.py
        | wsgi.py
        | urls.py

Newly created applications will be created by default in the My Project dir. Whilst there is no problem with this when you are starting out and your project is small over time it does lead to a project structure which can be difficult to manage.

A more sensible initial project structure would be one which allows for better management from the initial creation of the project.


# improved project strucute
| My Project dir
    | apps
    | libs
    | settings
        | common.py
        | local.py
    | wsgi.py
    | urls.py

With this basic structure all apps are stored in an apps folder separating them from third party libraries. The settings files in one directory again allows for cleaner project layout and easier project management as your project grows over time.

4. Django website (this has now been fixed.)

I love the Django web framework I make use of it all the time. It is my goto web framework when I need to get something done quickly, or need something which I know will be expanded on over time.

For those of you not familiar Django is a python web framework which allows for the rapid development of web applications. Its core functionality is complete and can be easily extended. In the case the functionality you are looking for is not there you can rest assure someone has already built something that will help you achieve your end goals.

In particular I love these 5 things about Django. (If you are not yet a Django user I would highly recommend trying it out, I am sure you will love it too).

The Django admin

I cannot even begin to think how much time the Django admin has saved me over the years. If you have ever built the admin side of a web application you will know how mind numbingly boring it is. Just imagine that in a few lines of code you could have a fully functional administration panel for your application. Django gives you this ability as a built in option.

The Django admin works by creating the CRUD functionality of all your models used within your application.

Essentially it turns:

class Post(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    text = models.TextField()
    timestamp = models.DateField()
    categories = models.ManyToManyField('Category')
    published = models.BooleanField(default=False)

Into:

Thought that was nice? It also gives you user management, user groups and change history by default.

Regex urls

As a developer you want to make your web application easy to develop, easy to use and pretty. A powerful feature within django is the ability to make powerful regex URLs that are pretty for the end user.

Within Django you specify your regex URL and bind a view function to this. As a result you can create easily readable URLs which can be mapped to various views and applications within your django project.


urlpatterns = patterns('',
        url(r'^$', 'myapp.views.home', name='home'),
        url(r'^contact/us/$', 'myapp.views.contact_us', name='contact_us'),
)

Here you will easily be able to see which urls we have available within our web application and which function is called as a result.

The named parameter name can also be used within the templating language to reverse generate the url.

For example:

<a href="{% url 'contact_us' %}">Contact</a>

Will generate the following code within the template:

<a href="/contact/us/">Contact</a>

What this does mean is that if the URL changes then all template urls will automatically be changed as a result.

Database migrations in core Django

Database migrations are a new feature in the Django core.

Migrations are Django’s way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema. They’re designed to be mostly automatic, but you’ll need to know when to make migrations, when to run them, and the common problems you might run into. https://docs.djangoproject.com/en/1.7/topics/migrations/

Migrations also have the added bonus of being able to revert the database change (though this does not undo any data manipulation which may have occurred). See Migrations in the Django documentation for more details.

You have NoSql options

By default Django makes use of a SQL based back-end supporting Postgres, Mysql, SQLite, Oracle and more. But what if you want a NoSQL option? Django can be used with NoSQL back-ends providing you options to work with MongoDB, Riak, and other NoSQL data-stores. The Django framework is very modular in its design and because of this different data back-ends can be used. I have used MongoEngine in several projects in the past and believe this is one of the better NoSQL data-store options to use with Django. The option of being able to use NoSQL means you as a developer can have a loosely attached schema which can change without the need for migrations.

Django community

An important factor when working with any technology is the community behind it. The community behind a technology are going to help you when you need help or advice.

The Django community is great for some many reasons.

  • Developer are willing to give their time freely to help other developers.
  • Sharing of code, just looking at http://djangopackages.com will list over 2000 packages available for download.
  • Continuous development of the Django project.
  • Superb documentation of Django core.

In conclusion:

I am a massive fan of Django and whilst I have only listed a couple of reasons why I love Django there are many more. If you have thought about using Django I would strongly recommend trying out the simple tutorials found on the Django project website.

If you are a Django use, tweet me on twitter and tell me your favourite thing about Django.

Cool urls dont change http://www.w3.org/Provider/Style/URI.html

Hello people of the internet this is my blog.

print `hello world