postgresql django 搭建博客

2011年12月16日 发表评论 阅读评论

一个国外站点上看到的,使用postgresql django 搭建博客。看着写的不错,就摘了下来:

In part 1, we installed PostgreSQL on the VPS. In this part, it’s time to get the database server up and configured. First, though, now that we have something to lose on the server, backups are now enabled at Slicehost. $5/month is cheap insurance. This also means we can take a snapshot of the slice, which we’ll do at the end of each major checkpoint, so we can roll back to it if something gets screwed up. (As they say in videogaming, “Hope you saved.”)

Since we built PostgreSQL from the tarball, rather than using an RPM, we didn’t get some of the conveniences that the RPM provides, like creating the user that the server will run as. So let’s do that!

[xof@blog ~]$ sudo /usr/sbin/adduser postgres
[xof@blog ~]$ sudo passwd postgres
Changing password for user postgres.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
Logging in as our shiny new user, we add the PostgreSQL binaries to our $PATH in the .bash_profile:

Well, no time like the present… let’s create a cluster:

[postgres@blog ~]$ initdb db
We want the locale and encoding to be UTF8, and that happens to be the default:

The database cluster will be initialized with locale en_US.UTF-8.
The default database encoding has accordingly been set to UTF8.
The default text search configuration will be set to "english".
Nota bene that the default authentication is “trust”:

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the -A option the
next time you run initdb.
That’s fine for now (we’ll change it later). As a smoke test, let’s start up the server and make sure all is well:

[postgres@blog ~]$ pg_ctl -D ~postgres/db -l logfile start
We’re just writing the log to a file ‘logfile’ in the postgres user’s home director, which is not particularly sophisticated log file management. (That’s also something we’ll fix later.)

So, did it work?

[postgres@blog ~]$ psql postgres
psql (8.4.1)
Type "help" for help.

Looks good!

Now, before we start creating new databases, let’s set up a couple of useful defaults.

[postgres@blog ~]$ psql template1
psql (8.4.1)
Type "help" for help.

We’ll be using PL/pgSQL functions in the future, so let’s add that language to template1. The template1 database is the template from which new databases are created, so changes here will be propagated to all new databses we create in the future.

template1=# CREATE LANGUAGE plpgsql;
We can also add the UUID-OSSP functions:

template1=# i /usr/local/pgsql/share/contrib/uuid-ossp.sql
Great. PostgreSQL has a ton more configuration options, of course, but this will get us started.

One of the other things that you don’t get when you build PostgreSQL from a tarball is an automatic init.d script so that PostgreSQL starts on system boot. Fortunately, the source tarball comes packaged with a suitable startup script:

[xof@blog ~]$ cd builds/postgresql-8.4.1/contrib/start-scripts
[xof@blog start-scripts]$ sudo cp linux /etc/rc.d/init.d/postgresql
[xof@blog start-scripts]$ sudo chmod +x /etc/rc.d/init.d/postgresql
The standard script doesn’t have the right location for the database directory, so we have to edit the appropriate line:

# Data directory
and use chkconfig to add the appropriate symlinks:

[xof@blog start-scripts]$ sudo /sbin/chkconfig --add postgresql
(We went back to the xof account because the postgres account isn’t a member of wheel, and can’t use sudo, which is just the way it should be.)

So, did that work? Let’s find out!

[xof@blog ~]$ sudo reboot
(wait wait wait.) Back up!

[postgres@blog ~]$ psql postgres
psql (8.4.1)
Type "help" for help.

Great. Note that the server logs are now being written to the default for the init.d file, which is $PGDATA/serverlogs rather than ~/logfile as before.

Next, in part 3, we’ll install Python 2.6, Apache, mod_wsgi and psycopg2.

In part 2 of this series, we got PostgreSQL up and running. In this part, we’ll install the remaining components to get Django up and running under Apache: Apache itself, Python 2.6, psycopg2, and mod_wsgi. So far, we’ve just accepted the default configuration parameters that initdb provided. Those will get us up and running, and setting the various PostgreSQL config parameters is worth at least one post all to itself. (In the meantime, see Josh Berkus’ talk “The Mighty GUCS”.)

Installing Apache couldn’t be easier:

[xof@blog ~]$ sudo yum install httpd httpd-devel
(We need httpd-devel to build mod_wsgi, the module we’ll use to get at Python programs from Apache.)

 Python and Centos: A Brief Diversion
The good news about Python on Centos is that it comes pre-installed. (It has to be; yum, among other tools, is written in Python.) The bad news is that the version that it comes with is …

[xof@blog ~]$ python -V
Python 2.4.3
… not exactly current. The most recent version of Python on the 2.x line as of this writing is 2.6.3. The very bad news is that you cannot just upgrade the base system Python install to 2.6; it breaks some of the system tools.

Fortunately, a solution exists: Doing a parallel installation of Python. I’m deeply indebted to this posting from Perplexed Labs for guidance on the process.

On with it: Installing Python 2.6
Since the RPMs for Centos are all Python 2.4, we need to install Python 2.6 from source. So, we grab the tarball, download it, and install it.

[xof@blog ~]$ cd builds
[xof@blog builds]$ wget
[xof@blog builds]$ tar xvfz Python-2.6.3.tgz
[xof@blog builds]$ cd Python-2.6.3
Note the --prefix option to put the 2.6 install in a different location.

[xof@blog Python-2.6.3]$ ./configure --prefix=/opt/python2.6 --with-threads --enable-shared
[xof@blog Python-2.6.3]$ make
[xof@blog Python-2.6.3]$ sudo make install
Add a symbolic link to put Python 2.6 in our path:

[xof@blog Python-2.6.3]$ sudo ln -s /opt/python2.6/bin/python /usr/bin/python2.6
Add the shared libraries to ldconfig and to /usr/lib64:

[xof@blog Python-2.6.3]$ sudo sh
sh-3.2# cat >> /etc/
sh-3.2# /sbin/ldconfig
sh-3.2# exit
[xof@blog Python-2.6.3]$ cd /usr/lib64
[xof@blog Python-2.6.3]$ sudo ln -s /opt/python2.6/lib/
[xof@blog Python-2.6.3]$ sudo ln -s
How does it look?

[xof@blog Python-2.6.3]$ python2.6
Python 2.6.3 (r263:75183, Oct 17 2009, 18:29:55)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Great. Onwards.

Installing setuptools
It’s very handy to have the Python package setuptools, so let’s download that and install it from the appropriate Python egg:

[xof@blog Python-2.6.3]$ cd ..
[xof@blog builds]$ wget
[xof@blog builds]$ sudo sh setuptools-0.6c9-py2.6.egg --prefix=/opt/python2.6
Installing psycopg2
And now we can install psycopg2. First, I have to say that the documentation on pretty much any aspect of psycopg2 is not exactly everything one can ask for; reading the INSTALL file in the tarball is your friend…

[xof@blog builds]$ wget
[xof@blog builds]$ tar xvfz psycopg2-2.0.13.tar.gz
[xof@blog builds]$ cd psycopg2-2.0.13
One of the files in the tarball is setup.cfg; this contains a setting we need to fix. We point pg_config to the right location for the binary.

# "pg_config" is the preferred method to locate PostgreSQL headers and
# libraries needed to build psycopg2. If pg_config is not in the path or
# is installed under a different name uncomment the following option and
# set it to the pg_config full path.
And away we go!

[xof@blog psycopg2-2.0.13]$ python2.6 build
[xof@blog psycopg2-2.0.13]$ sudo python2.6 install
So, did that work?

[xof@blog psycopg2-2.0.13]$ python2.6
Python 2.6.3 (r263:75183, Oct 17 2009, 18:29:55)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import psycopg2
>>> conn = psycopg2.connect("dbname='template1' user='postgres' host='localhost'")
>>> cur = conn.cursor()
>>> cur.execute("""SELECT datname from pg_database""")
>>> rows = cur.fetchall()
>>> print rows
[('template1',), ('template0',), ('postgres',)]
Installing mod_wsgi
mod_wsgi is an Apache module serving up Python programs. It’s generally considered a superior candidate to mod_python.

[xof@blog builds]$ wget
[xof@blog builds]$ tar xvfz mod_wsgi-2.6.tar.gz
[xof@blog builds]$ cd mod_wsgi-2.6
[xof@blog mod_wsgi-2.6]$ ./configure --with-python=/opt/python2.6/bin/python
[xof@blog mod_wsgi-2.6]$ make
[xof@blog mod_wsgi-2.6]$ sudo make install
To be paranoid, we should check two things. One: Did it link against the correct Python shared library?

xof@blog mod_wsgi-2.6]$ ldd /usr/lib64/httpd/modules/ =>  (0x00007fffcbbfe000) => /opt/python2.6/lib/ (0x00007f9ac3553000) => /lib64/ (0x00007f9ac332c000) => /lib64/ (0x00007f9ac3128000) => /lib64/ (0x00007f9ac2f25000) => /lib64/ (0x00007f9ac2ca1000) => /lib64/ (0x00007f9ac294b000)
    /lib64/ (0x000000323e400000)
Looks good. Second, how big is the shared library it created?

xof@blog mod_wsgi-2.6]$ ls -l /usr/lib64/httpd/modules/
-rwxr-xr-x 1 root root 339625 Oct 17 23:02 /usr/lib64/httpd/modules/
We’re looking for a size in the 332 kilobyte or smaller range, to confirm that it linked against the Python library as a shared, not static, library; for a discussion of this issue, see the “Lack of Shared Library” heading in the installation instructions.

In the next part, we’ll configure Apache, install Django, and bring up a test application.


In the previous installment of this series (in which we’re migrating this blog from WordPress to Django and PostgreSQL), we installed Apache, Python 2.6, psycopg and mod_wsgi on the server. A note about the pace: I’m taking this very slowly, spelling out each and every setp. I realize that those of you with more Centos experience (which is probably pretty much everyone) or Django experience are probably tapping your feet and thinking, “Come on, get a move on here!” To those, I beg your indulgence. When reading about a topic I am unfamiliar with, I appreciate a high level of detail, so I don’t hit a weird error message only to be told, “Oh, right, you have to install an old version of x. I skipped that step.”

Installing Django

We have choices here: We can install Django directly from the current Subversion repository, or from an official release. We also have the choice of installing Django as local to a particular user, or global for the whole system. For this install, we’ll do an official release (1.1.1 is current), and install it for the whole system.

[xof@blog ~]$ cd builds [xof@blog builds]$ wget [xof@blog builds]$ tar xvfz Django-1.1.1.tar.gz [xof@blog builds]$ cd Django-1.1.1 [xof@blog Django-1.1.1]$ sudo python2.6 install [xof@blog Django-1.1.1]$ python2.6 Python 2.6.3 (r263:75183, Oct 17 2009, 18:29:55) [GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import django >>> 

Where is the project going to live?

Before we configure Apache and mod_wsgi to serve up our new Django project, we should decide where the project is going to live. I like to keep my builds and maintenance account separate from the user that contains the actual stuff being served up by the web server… so let’s create a new user just to hold the project:

[xof@blog ~]$ sudo /usr/sbin/adduser thebuild [xof@blog ~]$ sudo passwd thebuild [xof@blog ~]$ sudo /usr/sbin/usermod -a -G apache thebuild 

Note: Depending on the permissions your installation sets on /home directories by default, you may need to adjust them so that mod_wsgi can get at the files it needs.

Set up the Django project

Logging in as the project user, first, we’ll make sure that we get the right Python installation by adding an alias to our .bash_profile:

alias python='/usr/bin/python2.6' 

Just checking!

[thebuild@blog ~]$ which python alias python='/usr/bin/python2.6' /usr/bin/python2.6 

And we can now create the project:

[thebuild@blog ~]$ cd [thebuild@blog]$ python /opt/python2.6/lib/python2.6/site-packages/django/bin/ startproject thebuild 

We also need to create a directory for any Python eggs that our application might download (this is, by the way, a “feature” of Python that I really do not care for).

[thebuild@blog]$ mkdir .python-eggs [thebuild@blog]$ chmod 770 .python-eggs 

Now, we need to create a .wsgi file. The .wsgi file is the glue that connects the mod_wsgi module in Apache to our particular application. The Django project itself doesn’t (and shouldn’t) live under the webroot of the web server, but the .wsgi file does:

[thebuild@blog]$ cd ~/ [thebuild@blog ~]$ mkdir apache [thebuild@blog ~]$ cd apache [thebuild@blog apache]$ cat >>django.wsgi #!/opt/python2.6/bin/python import os, sys sys.path.append('/home/thebuild/') os.environ['DJANGO_SETTINGS_MODULE'] = 'thebuild.settings' os.environ['PYTHON_EGG_CACHE'] = '/home/thebuild/' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler() [thebuild@blog apache]$ 

Next, let’s create the media and admin-media directories, and move the admin media over from the source distribution:

[thebuild@blog apache]$ mkdir admin-media [thebuild@blog apache]$ mkdir media [thebuild@blog apache]$ cd admin-media [thebuild@blog admin-media]$ cp -R /opt/python2.6/lib/python2.6/site-packages/django/contrib/admin/media/* . 

Creating a User in PostgreSQL for the Blog

Right now, the only user in the PostgreSQL cluster is the default superuser; that’s not a great choice for the user that Django will use to connect to the database.

It’s also not idea to allow the Django user to create objects in the public schema, but it needs to be able to create objects in some schema if we’re going to use the cool Django model mechanism for table and field creation.

First, let’s create a database for the site:

[postgres@blog ~]$ createdb thebuild [postgres@blog ~]$ psql thebuild psql (8.4.1) Type "help" for help. thebuild=# CREATE USER django ENCRYPTED PASSWORD 'password'; CREATE ROLE 

Then, let’s create a schema just to hold objects related to the site:


And set an appropriate search path:

thebuild=# ALTER ROLE django SET search_path TO thebuild, public; ALTER ROLE 

… and revoke CREATE on the public schema from the user:

thebuild=# REVOKE CREATE ON SCHEMA public FROM django; REVOKE 

This means that, by default, anything that the django user creates will go into the schema thebuild, while it still has access to the schema public. However, it won’t be able to create new objects in public.

(Note that we still have rather a barn door open here: We haven’t done anything with pg_hba.conf to require passwords or other security to log in.)

Django Settings

We’ll need to update the file to match all of the various changes we made. So far, we’ve changed:

DATABASE_ENGINE = 'postgresql_psycopg2' DATABASE_NAME = 'thebuild' DATABASE_USER = 'django' DATABASE_PASSWORD = 'password' TIME_ZONE = 'America/Los_Angeles' MEDIA_ROOT = '/home/thebuild/' MEDIA_URL = '' ADMIN_MEDIA_PREFIX = '/admin-media/' INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', ) 

Note that we’ve turned on the admin site by adding django.contrib.admin to installed apps. Now, we can do a syncdb to create the databases the installed apps require:

thebuild@blog thebuild]$ python syncdb Creating table django_admin_log Creating table auth_permission Creating table auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (Leave blank to use 'thebuild'): admin E-mail address: Password: Password (again): Superuser created successfully. Installing index for admin.LogEntry model Installing index for auth.Permission model Installing index for auth.Message model [thebuild@blog thebuild]$ 

Configure Apache

Apache can be tweaked endlessly, of course, but we’re going to do the minimum required to get the server up and ticking. Assuming we’ve done the basics (ServerName, etc.), we add the module info for mod_wsgi:

LoadModule wsgi_module modules/ AddHandler wsgi-script .wsgi 

Now, we need to point to the .wsgi file we created above. Moving over to /etc/httpd/conf.d, we can create a file thebuild.conf to contain the virtual host:

<IfModule mod_alias.c> Alias /media /home/thebuild/ Alias /admin-media /home/thebuild/ </IfModule> <IfModule mod_wsgi.c> WSGIScriptAlias / /home/thebuild/ WSGIDaemonProcess thebuild processes=5 threads=6 display-name=%{GROUP} WSGIProcessGroup thebuild WSGIApplicationGroup %{GLOBAL} WSGISocketPrefix run/wsgi </IfModule> 

… restart Apache …

[xof@blog conf]$ sudo /etc/init.d/httpd graceful 

… and did it work?


Exciting! Now, time to start actually designing our blog application.


You can donate through PayPal.
My paypal id:
Paypal page:

分类: http/html/web 标签:
  1. 本文目前尚无任何评论.