Setting TinyMCE configs in Django settings.py

Working with the Django Filebrowser and TinyMCE I have just spent quite a while with an utterly frustrating problem.

I want to set all my my inserted image paths to absolute e.g. /media/uploads/someimge.jpg – in TinyMCE the way to do this is to set “convert_urls”: false

The relevant part of my settings.py file looked like this:

TINYMCE_DEFAULT_CONFIG = {
    'plugins': "table,spellchecker,paste,searchreplace",
    'theme': "advanced",
    'theme_advanced_toolbar_location' : "top",
    'theme_advanced_toolbar_align' : "left",
    'theme_advanced_statusbar_location' : "bottom",
    'theme_advanced_resizing' : "true",
    'convert_urls' : "false"
}

But nothing worked and my images were all being inserted as ../../../media/uploads/someimge.jpg

Eventually looking at the generated source of my page I realised that the problem was this was rendering “convert_urls”: “false” it should be rendering “convert_urls”: false

The solution is pretty obvious – but then they usually are:

TINYMCE_DEFAULT_CONFIG = {
    'plugins': "table,spellchecker,paste,searchreplace",
    'theme': "advanced",
    'theme_advanced_toolbar_location' : "top",
    'theme_advanced_toolbar_align' : "left",
    'theme_advanced_statusbar_location' : "bottom",
    'theme_advanced_resizing' : True,
    'convert_urls' : False
}

The reason it took me so long to figure out was that I tried to use ‘convert_urls’ : false – which just resulted in syntax error – coming from PHP I’m used to booleans being case insensitive – in Python they aren’t. It also explains why my ‘theme_advanced_resizing’ didn’t work either.

Flirting with Django – part 3 – setting plural model names in admin

This is probably a bit obvious to any experienced Django user, but it took me a bit of digging to find.

In Django when you create a model to use the automatic admin interface you have to add it to the admin.py file.

Here is an example which only includes a ‘news’ model:

1
2
3
4
5
6
7
8
 
from s2.portfolio.models import News
from django.contrib import admin
 
class NewsAdmin(admin.ModelAdmin):
    pass
 
admin.site.register(News)

The trouble is that it shows up in your Django admin interface as ‘Newss’ which is obviously a bit lame.

The answer is quite simple once you know how, you need to add ‘Meta’ information the model class (I believe this is an example of an ‘internal class’). The ‘Meta’ class contains information about each model such as the ordering with which records should be displayed in the admin etc. This is documented in the Django documentation here.

Example news model including the Meta information

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
class News(models.Model):
    title = models.CharField(max_length=200)
    summary = models.CharField(max_length=200)
    description = tinymce_models.HTMLField()
    slug = models.CharField(max_length=200)
    live = models.BooleanField(default=1)
    date = models.DateField()
 
    def __unicode__(self):
        return self.title
 
    class Meta:
        verbose_name_plural = 'News'

Like most things, easy when you know how!

Flirting with Django – part 2

Just a quick post. I’ve been on holiday and I’ve been quite busy with various other things like setting myself up as full blown freelancer (dedicated website powered by Django coming soon)(anybody need a website?) and tweaking my new business directory website, so i haven’t had a chance to do too much.

In my previous post I mentioned that the one thing that drove me utterly mad was the issue of serving static files from Django. I thought that I had got it licked. My god I was wrong. Everything was working fine or so I assumed by tying in the Django FileBrowser and Django TinyMCE started to cause me problems. In the end I was left with a situation where I could browse for an image (using FileBrowseField) and select it but when I saved the page on the next page the paths were scrambled somehow and the file browser would not open. (Clearly my own newbie fault but damn hard to sort – and caused by my attempts to sort the static files issue).

The TinyMCE plugin is great, don’t get me wrong installing TinyMCE is not hard but setting up the plugins can be a chore so this is a nice little package – particularly the way it integrates with the File Browser.

The FileBrowser plugin is also great, but may one day if I get good enough at Python and Django I will rewrite it. Personally I like to have all my uploads managed in a database (as anyone who has tried out my extension to the CakePHP MeioUpload behaviour will see). My feeling is that with the FileBrowser things could get messy pretty fast. Be nice to have everything in inline popups / modal dialogues rather than new windows (haven’t tried yet).

I did solve the static file issue but I had to create a brand new clean app to test it out (integrated with TinyMCE + FileBrowser). Key parts of settings.py as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = 'E:/xampp/htdocs/django/s2/media/'
 
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '/media/'
 
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/admin/'
 
FILEBROWSER_URL_WWW = '/'
 
TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    'E:/xampp/htdocs/django/s2/templates'
)
 
 
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    's2.shop',
    'sorl.thumbnail',
    'filebrowser',
    'tinymce',
)
 
TINYMCE_DEFAULT_CONFIG = {
    'plugins': "table,spellchecker,paste,searchreplace",
    'theme': "advanced",
    'theme_advanced_toolbar_location' : "top",
    'theme_advanced_toolbar_align' : "left",
    'theme_advanced_statusbar_location' : "bottom",
    'theme_advanced_resizing' : "true"
}
TINYMCE_SPELLCHECKER = True
TINYMCE_COMPRESSOR = True

It’s funny – I really don’t feel that the whole static file thing is explained anywhere clearly enough. Should be fun when I come to deploy it on a real server. The experience so far has really got me thinking about ‘Auto Magic’ – the way frameworks can do so too much. Here I am building something fairly complex and learning both Python and the framework at the same time – at the moment I feel there is too much magic, the framework is so powerful I am completely detached and it doesn’t really help me learn Python particularly (mostly as I am having to write so little). i am constantly amazed at how terse the language is; CakePHP has a lot of magic but I still have to type a fair bit; with Django I don’t feel I’m writing at all – it makes an interesting comparison to Java which really doesn’t seem to be at all concerned with saving poor programmers fingers.

Until next time…

Flirting with Django – part 1

Right now I’ve got a bit of time on my hands and I am slowly catching up with bits and pieces that I have been meaning to do for years. I have also decided to broaden my horizons and learn some Python and Java.

Why Python and Java? Well its simple really; I think Java would be really useful (in this part of the world), both career wise and in terms of being a better programmer; Python? – well my best friend raves about it all the time, its a bit different and Django seems so damn sexy (so far I am loving it).

Over the last couple of years I have dabbled with Django, run through the tutorials etc. but never quite had enough time to get to grips with it and Python at the same time. This time I have a specific project in mind and have decided to stick with it until I have something live and kicking on a web server out there in the big wide world.

(Un)fortunately I just blew my book budget on a pair of Java books – Sams Teach Yourself Java 6 in 21 Days (which is a superb book and I would recommend it to anyone learning Java) and Beginning JSP, JSF & Tomcat Web Development: From Novice to Professional (Beginning from Novice to Professional) (IMHO a bit mixed some of it is great, but chapters on HTML and Javascript are just filler), so in the absence of paper I have had to resort to the (excellent) online versions Django Book and Dive into Python. (Personally I’d take a real book over a screen any day – you can lie in sunshine in a hammock with your laptop and a beer, but you can’t see the screen and if you spill the beer it could be an expensive mistake)

My Setup

I’m developing on my laptop which runs Windows XP Professional. I already have an XAMPP webserver running on my laptop. I also have a copy of the Microsoft Power Toy – Open Command Window here, that lets you open a command prompt in any directory. I’m using Netbeans as an IDE, although I did start off with IDLE (the text editor that comes bundled with Python on Windows) but I got driven mad by all the windows.

The Django documentation runs through everything in detail and is a good place to start http://docs.djangoproject.com/en/dev/intro/install/#intro-install. Here is what I did:

  1. Download + Install Python
  2. Download + Install MySQL Python
  3. Download + Install Django + Set Paths in your windows environment variables
  4. Download + Install PIL (Python Imaging Library) so you can work with images

A few thoughts

Having worked mainly with ASP and PHP, the thing I have found most alien isn’t anything obvious like syntax differences it is the use of libraries . Of course they exist in PHP – think about things like PEAR – but for some reason they are not really a visible part of the language – PEAR is installed almost ubiquitously and in other cases people seem to just grab a library and dump directly into their application somewhere. Built in libraries (think GD or SPL) are just that built in and people don’t actually think about them. I think a lot of this is also a reflection of the nature of most PHP hosting which tends to be in cheap (and often shared) hosting environments where it is difficult to (if not impossible) to use non standard libraries, so people stick to the core.

To me therefore, it feels a little odd to have Django sitting in C:\Python25\Lib\site-packages and my application sitting E:\django\mysite

Getting started – create your project

Go to the directory you want to create your site in and then from the command prompt run:
django-admin.py startproject mysite.
This will create a project called mysite d within your current directory.

Create you app

Within a project you can have any number of applications – I’ve been thinking of an app as basically a plugin – a collection of related code. The idea is that you can take a number of apps and put them together inside a project and viola – a new site. An app might be a products database and shopping cart or it could be a blog or news system. But you can mix them all together and because of the unified Django admin interface they will all fit together perfectly. (The Django book explains it pretty clearly)

What’s the difference between a project and an app? An app is a Web application that does something — e.g., a weblog system, a database of public records or a simple poll app. A project is a collection of configuration and apps for a particular Web site. A project can contain multiple apps. An app can be in multiple projects.

To create an app Go to the directory you want to create your app in and then from the command prompt run:
django-admin.py startapp shop.
(This would create an app called shop within the mysite project)

Create your model

I usually have a pretty accurate database schema down in my notebook before I start any project and although you can import an existing schema and get Django to build the models, the preferred way seems to be to write your models and then get Django to create any necessary database tables based on your models. The latter method is certainly more useful from a learning point of view.

The basic workflow to create your models and synchronise them with the database is very simple indeed:

  1. Edit the models.py file within your app
  2. Generate the SQL for your shop app models with:
    manage.py sql shop.
  3. Create your database tables with:
    manage.py syncdb.

How easy is that?

The one thing to watch out for is that once a table has been created running syncdb will not update the database structure for that table – you either need to do this manually or use find a schema migration tool to use (something I haven’t tried yet)

Templates and Views

Once you’ve got a model or two in place, you probably want to do something with it. So you need to write a view. If you are coming from another MVC system, a Django View is basically equivalent to the Controller. I just followed the Django tutorial and played around from there. I didn’t make any earth shattering discoveries that weren’t in the book.

Django uses templateing engines to produce its output – commonly some HTML (but it could be anything, or even empty for AJAX) mixed in with placeholder tags and filters. When you view the page the place holders are replaced with data from the Model by way of the View. The template system seems to be deliberately sparse, but well thought out. If you need more functionality. you cna extend it by defining your own tags and filters or swap in an alternate template system.

You will need to specify the directory that your templates live in settings.py. e.g.

TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'E:/django/mysite/templates'
)

If you just want to use Django admin as is you don’t have to do a thing, but if you want to customise it you can override and of the default admin templates just by creating new ones and placing them in a directory called admin inside your templates directory. Again very straight forward.

The one thing that I got stuck on for a short while is that Django doesn’t provide any default templates for your the public facing parts of your application. I don’t think it is that clear on this and I felt a while thinking I was doing something wrong before I realised I actually needed to just make them.

My simple base.html template looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="http://static.mysite.com/css/reset.css" type="text/css" />
<link rel="stylesheet" href="http://static.mysite.com/css/base.css" type="text/css" />
{% block meta %}{% endblock %}
</head>
<body>
<div id="container">
 
	<div id="header">
		{% block header %}{% endblock %}
	</div>
	<div id="content">
		{% block content %}{% endblock %}
		<div class="push"></div>
	</div>
	<div id="footer">
		{% block footer %}{% endblock %}
	</div>
</div>
</body>
</html>

The important thing here is are the placeholder tags e.g. {% block header %}{% endblock %}
In this case this is a placeholder for another template fragment called header so you can extend your templates ad infinitum.

Which brings me on to the only part of my Django experience so far that wasn’t great, it was the hair-pullingly frustrating experience of setting up to serve static files…

Serving Static Files

Django doesn’t like to serve static files (think css, js etc.). Even though I’m just developing on my laptop at the moment, I thought that it would be a good idea to try and mimic a production setup as closely as possible, and reading around the sensible thing to do was just serve all my static files from a sub domain. I’ve also got a copy of XAMPP running on my machine so I set up a subdomain in that to serve static files and experienced a total nightmare. I’m not quite sure why I had so much trouble, but I did, and I would imagine that this is the step where a lot of other people give up. Of course I got it working in the end (or else I probably wouldn’t be writing this, or at least not in a wow Django is so so cool kind of way…)

In the end I did get it working and it is possible that it is slightly weird. My actual Django project directory is within my XAMPP directory structure (because this is where I store all my code), but it is not served by the XAMPP Apache server (yet) – instead it is served using the python server: python manage.py runserver on http://127.0.0.1:8000/

So for the moment my static files are within the Django project (in the static directory) and can be accessed at: http://static.simbiotica.co.uk – in my settings.py has the following settings:


# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = './static/'

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
#MEDIA_URL = 'http://static.simbiotica.co.uk'
MEDIA_URL = '/static/'

Update 19th July 2009

It turns out I was wrong! Thought it was all working, but when I started to dig deeper it wasn’t. Close though I think. For development have gone back to a more conventional setup in my latest post.

Django Files

The story so far…

So far my Django experience has been very positive and I can’t wait to get my first site done. I’ve successfully plugged in the Django Filebrowser into my admin system too. I think the thing I like most is wonderful terseness – you can achive so much writing so little, and from my currently extremely limited Python experience I’m really enjoying the language too.