ลองติดตั้ง django เพื่อใช้งานกับ apache2 บนเดเบียน
เที่ยวนี้ทำไปบันทึกไป จึงไม่มีกำหนดเสร็จครับ
งานของ admin เจ้าของเซิร์ฟเวอร์
เอา django มาก่อน
# aptitude install subversion
# svn co http://code.djangoproject.com/svn/django/trunk/
ติดตั้ง django สู่ระบบ
# cd trunk
# python setup.py install
ลบซอร์ส หากไม่ต้องการดูโค๊ดของ django
# cd ..
# rm -rf trunk
กันเหนียวให้ apache2 เปิดมอดูล env (ส่วนใหญ่จะเปิดมาอยู่แล้วมั้ง)
# a2enmod env
ติดตั้ง mod_python และเปิดให้ใช้งาน
# aptitude install libapache2-mod-python
# a2enmod mod_python
งานของเรา เจ้าของเว็บ
สมมุติว่า admin ติดตั้ง ให้ DocumentRoot ของ apache2 สำหรับโดเมน www.example.com อยู่ที่ไดเรกทอรี่ของเรา /home/user1/www
และเราจะให้หน้าของ django ไปอยู่ที่ http://www.example.com/dj
มาที่ไดเรกทอรี่ของเราก่อน
$ cd ~/www
เริ่มโปรเจคต์ใหม่ชื่อ dj
$ django-admin.py startproject dj
ไปที่ไดเรคทอรี่ dj และเตรียมการให้ apache2 โดยการสร้างไฟล์ .htaccess
$ cd dj
$ vi .htaccess
SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv SERVER_ADMIN webmaster@example.com SetEnv DJANGO_SETTINGS_MODULE dj.settings PythonDebug On PythonPath "['/home/user1'] + sys.path" RewriteEngine On RewriteBase /dj/
เสร็จแล้ว ดูที่หน้า www.example.com/dj ได้ดังนี้

เพิ่มเติม
สำหรับการทำงานให้เต็มรูปแบบ ต้องสร้างหน้า admin ด้วย
การที่จะทำให้หน้า admin ทำงานได้สมบูรณ์ ต้องสร้างลิงก์โยงจากทรัพยากรของซอร์สมาที่ไดเรกทอรี่รากของ apache2 ด้วย
สมมุติถ้าใช้ไพธอน 2.4 บนเดเบียน
$ cd ~/www
$ ln -sf /usr/lib/python2.4/site-packages/django/contrib/admin/media/ .
สร้างหน้า admin โดยการลบคอมเมนต์ในไฟล์ dj/urls.py
$ cd dj
$ vi urls.py
...
(r'^admin/', include('django.contrib.admin.urls')),
...แต่ถ้าหากเราจะให้เพจของ django อยู่ในหน้า www.example.com/dj เราต้องแก้ไฟล์ด้วย
...
(r'^dj/admin/', include('django.contrib.admin.urls')),
...
แต่...ก่อนจะใช้งานหน้า admin ได้ เราต้องสร้างฐานข้อมูลก่อน สมมุติว่าจะใช้กับ postgresql
สร้างฐานข้อมูลไว้รองรับ ตั้งชื่อว่า djdb
$ createdb djdb
Password: >>> --- USER1_PASSWORD
ปรับตั้งไฟล์ settings.py ให้ django รับรู้ฐานข้อมูลและให้เรียกใช้มอดูล admin
$ vi settings.py
...
DATABASE_ENGINE = 'postgresql'
DATABASE_NAME = 'djdb'
DATABASE_USER = 'user1'
DATABASE_PASSWORD = 'USER1_PASSWORD'
...
TIME_ZONE = 'Asia/Bangkok'
...
LANGUAGE_CODE = 'th'
...
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
)
สั่งปรับปรุงฐานข้อมูล
$ python manage.py syncdb
Creating table auth_message Creating table auth_group Creating table auth_user Creating table auth_permission Creating table django_content_type Creating table django_session Creating table django_site Creating table django_admin_log 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 'user1'): >>>--- ENTER E-mail address: >>>--- user1@example.com Password: >>>--- USER1_PASSWORD Password (again): >>>--- USER1_PASSWORD Superuser created successfully. Installing index for auth.Message model Installing index for auth.Permission model Installing index for admin.LogEntry model
เสร็จแล้ว ดูจาก URL:http://www.example.com/dj/admin จะได้ดังนี้

อ้างอิง
คราวนี้ทำบล๊อกจาก Falling Bullets - Blog - WordPress Clone in 27 Seconds (Part 1 of 40)
โดย
http://www.example.com/djhttp://dj.example.com เป็นต้น)/dj ไปก่อน/home/user1/wwwuser1 รหัสผ่านคือ USER1_PASSWORD มีสิทธิ์ในการสร้างฐานข้อมูล/home/user1/www/djสร้างแอพลิเคชั่นชื่อ blog ในไดเรคทอรี่ dj จากครั้งก่อน
$ cd ~/www/dj
$ python manage.py startapp blog
สร้างตารางฐานข้อมูลด้วย models.py ให้มี 2 ตาราง คือเก็บแท็ก และเก็บเนื้อเรื่อง
$ vi blog/models.py
from django.db import models
class Tag(models.Model):
name = models.CharField(maxlength=50, core=True)
slug = models.SlugField(prepopulate_from=("name",))
class Admin:
pass
def __str__(self):
return self.name
def get_absolute_url(self):
return "/dj/blog/tags/%s/" % (self.slug)
class Entry(models.Model):
title = models.CharField(maxlength=200)
slug = models.SlugField(
unique_for_date='pub_date',
prepopulate_from=('title',),
help_text='Automatically built from the title.'
)
summary = models.TextField(help_text="One paragraph. Don't add <p> tag.")
body = models.TextField()
pub_date = models.DateTimeField()
tags = models.ManyToManyField(Tag, filter_interface=models.HORIZONTAL)
class Meta:
ordering = ('-pub_date',)
get_latest_by = 'pub_date'
class Admin:
list_display = ('pub_date', 'title')
search_fields = ['title', 'summary', 'body']
def __str__(self):
return self.title
def get_absolute_url(self):
return "/dj/blog/%s/%s/" % (self.pub_date.strftime("%Y/%b/%d").lower(), self.slug)
แก้ไข urls.py ให้สามารถเรียกไดเรกทอรี่เลียนแบบ Wordpress หรือเรียกแบบปกติ
$ vi urls.py
from django.conf.urls.defaults import *
from dj.blog.models import Entry
blog_dict = {
'queryset': Entry.objects.all(),
'date_field': 'pub_date',
}
urlpatterns = patterns('',
# Example:
# (r'^dj/', include('dj.foo.urls')),
# Uncomment this for admin:
(r'^dj/admin/', include('django.contrib.admin.urls')),
(r'^dj/report/$', 'dj.todo.views.status_report'),
(r'^dj/blog/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'django.views.generic.date_based.object_detail', dict(blog_dict, slug_field='slug')),
(r'^dj/blog/?$', 'django.views.generic.date_based.archive_index', blog_dict),
)
รัน syncdb ครั้งนึง เพื่อสร้างและปรับปรุงตาราง
$ python manage.py syncdb
title = models.CharField(maxlength=250, unique=True) title = models.CharField(maxlength=250)
ต่อไปเป็นเรื่องอินเทอร์เฟสแสดงหน้าตา
(เที่ยวนี้แปลกไปนิดนึง เพราะเขาเรียกแสดงผลผ่านฟังก์ชั่นมาตรฐานของ django โดยไม่ได้ใช้ views ของเรา เลยต้องวางไดเรกทอรี่ไว้เป็นมาตรฐาน คือเอา templates ไว้ที่ root ของโครงการ)
แก้ไข settings.py ให้มาใช้ template ของเรา รวมทั้งบอกให้เปิดมอดูล blog ที่เราเพิ่งสร้างขึ้น
$ vi settings.py
...
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.
'/home/user1/www/dj/todo/templates',
'/home/user1/www/dj/templates',
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'dj.todo',
'dj.blog',
)
สร้างเทมเพลตโดยการสร้างไดเรกทอรี่ชื่อ templates ไว้ที่ root ของโครงการ
ในไดเรกทอรี่ templates จะมีไฟล์ base.html เอาไว้ดูหน้าหลักซึ่งเป็นพวกเมนูต่าง ๆ
และสร้างไดเรกทอรี่ย่อยชื่อ templates/blog อีกที จะมีไฟล์ entry_archive.html ไว้ดูหัวข้อบล๊อก และ entry_detail.html ไว้ดูรายละเอียดของแต่ละรายการ
$ mkdir -p templates/blog
$ vi templates/base.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>My Site - {% block title %}{% endblock %}</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="header">
<h1><a href="/">My Interweb Tubes Blog</a></h1>
<h2>It's not a truck!</h2>
<ul id="nav">
<li><a href="/dj/">Home</a></li>
<li><a href="/dj/blog/">Blog</a></li>
<li><a href="#">Photos</a></li>
<li><a href="/dj/links/">Links</a></li>
<li><a href="/dj/portfolio/">Work</a></li>
<li><a href="/dj/colophon/">Colophon</a></li>
</ul>
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
$ vi templates/blog/entry_archive.html
{% extends "base.html" %}
{% block title %}Latest Blog Entries{% endblock %}
{% block content %}
<h1>Latest Blog Entries</h1>
<ol id="object-list">
{% for object in latest %}
<li>
<h2><a href="{{ object.get_absolute_url }}">{{ object.title|escape }}</a></h2>
<p class="post-date">{{ object.pub_date|date:"F j, Y" }}</p>
<p class="summary">{{ object.summary }}</p>
</li>
{% endfor %}
</ol>
{% endblock %}
$ vi templates/blog/entry_detail.html
{% extends "base.html" %}
{% block title %}Blog - {{ object.title|escape }}{% endblock %}
{% block content %}
<h1>{{ object.title|escape }}</h1>
<dl>
<dt>Posted On:</dt>
<dd>{{ object.pub_date|date:"F j, Y" }}</dd>
<dt>Tags:</dt>
<dd>
{% for tag in object.tags.all %}
<a href="{{ tag.get_absolute_url }}">{{ tag.name }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</dd>
</dl>
{{ object.body }}
{% endblock %}
เรียกปรับปรุงตารางอีกครั้ง
python manage.py syncdb
title = models.CharField(maxlength=250, unique=True) title = models.CharField(maxlength=250) name = models.CharField(maxlength=50, core=True) title = models.CharField(maxlength=200) Creating table blog_entry Creating table blog_tag Installing index for blog.Entry model Installing index for blog.Tag model
เสร็จแล้ว เรียกผ่าน URL:http://www.example.com/dj/blog ได้ดังนี้

จากครั้งก่อน django: ใช้กับ apache2 บนเดเบียน (มีการปรับปรุงให้เนื้อหาสมบูรณ์ขึ้นในหน้าเก่าด้วย)
ตอนนี้เราจะมาสร้างแอพลิเคชั่นชื่อ "to do" จาก sitepoint.com - Django Djumpstart: Build a To-do List in 30 Minutes
โดย
http://www.example.com/djhttp://dj.example.com เป็นต้น)/dj ไปก่อน/home/user1/wwwuser1 รหัสผ่านคือ USER1_PASSWORD มีสิทธิ์ในการสร้างฐานข้อมูล/home/user1/www/djเริ่มเลย
สร้างแอพลิเคชั่นชื่อ "to do" เอาไว้สำหรับดูว่าจะทำงานอะไรบ้าง
$ cd ~/www/dj
$ python manage.py startapp todo
สร้างฐานข้อมูลผ่านโปรแกรมชื่อ todo/models.py
โดยเราจะสร้างเป็น 2 ตาราง โดยแต่ละตารางจะเป็นคลาสใน model.py
คือคลาส List สำหรับดูหัวข้อ และคลาส Item สำหรับเก็บรายละเอียดของข้อมูลของงานที่จะทำ
$ vi todo/models.py
...
#TABLE List
class List(models.Model):
title = models.CharField(maxlength=250, unique=True)
def __str__(self):
return self.title
class Meta:
ordering = ['title']
class Admin:
pass
#TABLE Item
import datetime
PRIORITY_CHOICES = (
(1, 'Low'),
(2, 'Normal'),
(3, 'High'),
)
class Item(models.Model):
title = models.CharField(maxlength=250)
created_date = models.DateTimeField(default=datetime.datetime.now)
priority = models.IntegerField(choices=PRIORITY_CHOICES, default=2)
completed = models.BooleanField(default=False)
todo_list = models.ForeignKey(List)
def __str__(self):
return self.title
class Meta:
ordering = ['-priority', 'title']
class Admin:
pass
ถึงตอนนี้ต้องมีฐานข้อมูลอยู่แล้ว หากยังไม่ได้สร้างฐานข้อมูล ให้ย้อนไปดูคราวก่อน
ปรับตั้งให้ django รับรู้ถึงการเพิ่มตาราง ผ่านไฟล์ settings.py
$ vi settings.py
...
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'dj.todo',
)
สั่งสร้างตาราง/ปรับปรุงฐานข้อมูล
$ python manage.py syncdb
title = models.CharField(maxlength=250, unique=True) title = models.CharField(maxlength=250) Creating table todo_item Creating table todo_list Installing index for todo.Item model
ต่อไปเป็นการสร้างอินเทอร์เฟสผ่านไฟล์ชื่อ todo/views.py
ในไฟล์นี้เราจะสร้างฟังก์ชั่นในการแสดงรายงานสถานะของงานชื่อว่า status_report
$ vi todo/views.py
...
from django.shortcuts import render_to_response
from dj.todo.models import List
def status_report(request):
todo_listing = []
for todo_list in List.objects.all():
todo_dict = {}
todo_dict['list_object'] = todo_list
todo_dict['item_count'] = todo_list.item_set.count()
todo_dict['items_complete'] = todo_list.item_set.filter(completed=True).count()
todo_dict['percent_complete'] = int(float(todo_dict['items_complete']) / todo_dict['item_count'] * 100)
todo_listing.append(todo_dict)
return render_to_response('status_report.html', { 'todo_listing': todo_listing })เอาตารางมาใช้จากคลาส List ใน todo/models.py
ไฟล์ views.py นี้เป็นฟังก์ชั่นการทำงานล้วน ๆ ซึ่งเราจะต้องสร้างเทมเพลตในการแสดงผลอีกทีหนึ่ง
ในการสร้างเทมเพลต เราจะสร้างไดเรคทอรี่ย่อยชื่อ templates ไว้ใน todo เพื่อเอาไว้บรรจุไฟล์เทมเพลต คือไฟล์ HTML ในที่นี้ตั้งชื่อว่า status_report.html
$ mkdir todo/templates
$ vi todo/templates/status_report.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>To-do List Status Report</title>
</head>
<body>
<h1>To-do list status report</h1>
{% for list_dict in todo_listing %}
<h2>{{ list_dict.list_object.title }}</h2>
<ul>
<li>Number of items: {{ list_dict.item_count }}</li>
<li>Number completed: {{ list_dict.items_complete }} ({{ list_dict.percent_complete }}%)</li>
</ul>
{% endfor %}
</body>
</html>สังเกตุว่าคำสั่งจะอยู่ในบล๊อก {% COMMAND %} และตัวแปรจะอยู่ในบล๊อก {{ VARIABLE }} โดยตัวแปรที่ใช้ ใช้เสมือนเราอยู่ภายในมอดูล todo.views.status_report ซึ่งเราต้องกลับไปบอก django ในไฟล์ urls.py
ต้องกลับไปบอก django ว่าโครงการของเรามีเทมเพลตด้วย และเทมเพลตเราอยู่ที่ไหน ผ่าน settings.py
$ vi settings.py
...
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.
'/home/user1/www/dj/todo/templates',
)
และกำหนดให้ apache2 มาเรียกใช้ todo เมื่อเข้า URL:/dj/report/ ผ่าน urls.py
$ vi urls.py
...
urlpatterns = patterns('',
# Example:
# (r'^dj/', include('dj.foo.urls')),
# Uncomment this for admin:
(r'^dj/admin/', include('django.contrib.admin.urls')),
(r'^dj/report/$', 'dj.todo.views.status_report'),
)
ตอนนี้ดูได้แล้ว ผ่าน URL:http://www.example.com/dj/report

ตอนนี้ยังไม่มีอะไร เพราะเรายังไม่ได้ใส่อะไรเข้าไป
ถึงตอนนี้เราสามารถใส่เนื้อหาใหม่เข้าไปได้ ผ่านทางหน้า admin
โดยต้องเพิ่ม List ก่อน ทาง URL:http://www.example.com/dj/admin/todo/list/add
ตามด้วย Item ทาง URL:http://www.example.com/dj/admin/todo/item/add
พอเข้าหน้า report ใหม่ ก็จะเห็นรายการตามต้องการ
รายการเพิ่มเติมสำหรับ django รุ่น svn (ระหว่าง 0.96-)
$ sudo aptitude install python-docutils$ sudo vi /usr/lib/python2.4/site-packages/django/contrib/admin/media/css/global.css
body { margin:0; padding:0; font-size:84%; font-family:"Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; color:#333; background:#fff; }
/* LINKS */
a:link, a:visited { color: #5b80b2; text-decoration:none; }
a:hover { color: #036; }
a img { border:none; }
/* GLOBAL DEFAULTS */
p, ol, ul, dl { margin:.2em 0 .8em 0; }
p { padding:0; line-height:140%; }
h1,h2,h3,h4,h5 { font-weight:bold; }
h1 { font-size:1.4em; color:#666; padding:0 6px 0 0; margin:0 0 .2em 0; }
h2 { font-size:1.3em; margin:1em 0 .5em 0; }
h2.subhead { font-weight:normal;margin-top:0; }
h3 { font-size:1.2em; margin:.8em 0 .3em 0; color:#666; font-weight:bold; }
h4 { font-size:1.1em; margin:1em 0 .8em 0; padding-bottom:3px; }
h5 { font-size:1em; margin:1.5em 0 .5em 0; color:#666; text-transform:uppercase; letter-spacing:1px; }
ul li { list-style-type:square; padding:1px 0; }
ul.plainlist { margin-left:0 !important; }
ul.plainlist li { list-style-type:none; }
li ul { margin-bottom:0; }
li, dt, dd { font-size:.9em; line-height:1.2em; }
dt { font-weight:bold; margin-top:4px; }
dd { margin-left:0; }
form { margin:0; padding:0; }
fieldset { margin:0; padding:0; }
blockquote { font-size:.9em; color:#777; margin-left:2px; padding-left:10px; border-left:5px solid #ddd; }
code, pre { font-family:"Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; background:inherit; color:#666; font-size:.9em; }
pre.literal-block { margin:10px; background:#eee; padding:6px 8px; }
code strong { color:#930; }
hr { clear:both; color:#eee; background-color:#eee; height:1px; border:none; margin:0; padding:0; font-size:1px; line-height:1px; }
/* TEXT STYLES & MODIFIERS */
.small { font-size:.9em; }
.tiny { font-size:.8em; }
p.tiny { margin-top:-2px; }
.mini { font-size:.7em; }
p.mini { margin-top:-3px; }
.help, p.help { font-size:.8em !important; color:#999; }
p img, h1 img, h2 img, h3 img, h4 img, td img { vertical-align:middle; }
.quiet, a.quiet:link, a.quiet:visited { color:#999 !important;font-weight:normal !important; }
.quiet strong { font-weight:bold !important; }
.float-right { float:right; }
.float-left { float:left; }
.clear { clear:both; }
.align-left { text-align:left; }
.align-right { text-align:right; }
.example { margin:10px 0; padding:5px 10px; background:#efefef; }
.nowrap { white-space:nowrap; }
/* TABLES */
table { border-collapse:collapse; border-color:#ccc; }
td, th { font-size:.9em; line-height:1.2em; border-bottom:1px solid #eee; vertical-align:top; padding:5px; font-family:"Lucida Grande", Verdana, Arial, sans-serif; }
th { text-align:left; font-size:1em; font-weight:bold; }
thead th,
tfoot td { color:#666; padding:2px 5px; font-size:.9em; background:#e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; border-left:1px solid #ddd; border-bottom:1px solid #ddd; }
tfoot td { border-bottom:none; border-top:1px solid #ddd; }
thead th:first-child,
tfoot td:first-child { border-left:none !important; }
thead th.optional { font-weight:normal !important; }
fieldset table { border-right:1px solid #eee; }
tr.row-label td { font-size:.7em; padding-top:2px; padding-bottom:0; border-bottom:none; color:#666; margin-top:-1px; }
tr.alt { background:#f6f6f6; }
.row1 { background:#EDF3FE; }
.row2 { background:white; }
/* SORTABLE TABLES */
thead th a:link, thead th a:visited { color:#666; display:block; }
table thead th.sorted { background-position:bottom left !important; }
table thead th.sorted a { padding-right:13px; }
table thead th.ascending a { background:url(../img/admin/arrow-down.gif) right .4em no-repeat; }
table thead th.descending a { background:url(../img/admin/arrow-up.gif) right .4em no-repeat; }
/* ORDERABLE TABLES */
table.orderable tbody tr td:hover { cursor:move; }
table.orderable tbody tr td:hover { cursor:move; }
table.orderable tbody tr td:first-child { padding-left:14px; background-image:url(../img/admin/nav-bg-grabber.gif); background-repeat:repeat-y; }
table.orderable-initalized .order-cell, body>tr>td.order-cell { display:none; }
/* FORM DEFAULTS */
input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:.9em; }
textarea { vertical-align:top !important; }
input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; }
/* FORM BUTTONS */
input[type=submit], input[type=button], .submit-row input { background:white url(../img/admin/nav-bg.gif) bottom repeat-x; padding:3px; color:black; border:1px solid #bbb; border-color:#ddd #aaa #aaa #ddd; }
input[type=submit]:active, input[type=button]:active { background-image:url(../img/admin/nav-bg-reverse.gif); background-position:top; }
input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2; background:#7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x; font-weight:bold; color:white; }
input[type=submit].default:active { background-image:url(../img/admin/default-bg-reverse.gif); background-position:top; }
/* MODULES */
.module { border:1px solid #ccc; margin-bottom:5px; background:white; }
.module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; }
.module blockquote { margin-left:12px; }
.module ul, .module ol { margin-left:1.5em; }
.module h3 { margin-top:.6em; }
.module h2, .module caption { margin:0; padding:2px 5px 3px 5px; font-size:.9em; text-align:left; font-weight:bold; background:#7CA0C7 url(../img/admin/default-bg.gif) top left repeat-x; color:white; }
.module table { border-collapse: collapse; }
/* MESSAGES & ERRORS */
ul.messagelist { padding:0 0 5px 0; margin:0; }
ul.messagelist li { font-size:1em; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border-bottom:1px solid #ddd; color:#666; background:#ffc url(../img/admin/icon_success.gif) 5px .3em no-repeat; }
.errornote { font-size:1em !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:red;background:#ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; }
ul.errorlist { margin:0 !important; padding:0 !important; }
.errorlist li { font-size:1em !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:white; background:red url(../img/admin/icon_alert.gif) 5px .3em no-repeat; }
td ul.errorlist { margin:0 !important; padding:0 !important; }
td ul.errorlist li { margin:0 !important; }
.error { background:#ffc; }
.error input, .error select { border:1px solid red; }
div.system-message { background: #ffc; margin: 10px; padding: 6px 8px; font-size: .8em; }
div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; color:red; background:#ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; }
.description { font-size:1em; padding:5px 0 0 12px; }
/* BREADCRUMBS */
div.breadcrumbs { background:white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; padding:2px 8px 3px 8px; font-size:.9em; color:#999; border-top:1px solid white; border-bottom:1px solid #ccc; text-align:left; }
/* ACTION ICONS */
.addlink { padding-left:12px; background:url(../img/admin/icon_addlink.gif) 0 .2em no-repeat; }
.changelink { padding-left:12px; background:url(../img/admin/icon_changelink.gif) 0 .2em no-repeat; }
.deletelink { padding-left:12px; background:url(../img/admin/icon_deletelink.gif) 0 .25em no-repeat; }
a.deletelink:link, a.deletelink:visited { color:#CC3434; }
a.deletelink:hover { color:#993333; }
/* OBJECT TOOLS */
.object-tools { font-size:.8em; font-weight:bold; font-family:Arial,Helvetica,sans-serif; padding-left:0; float:right; position:relative; margin-top:-2.4em; margin-bottom:-2em; }
.form-row .object-tools { margin-top:5px; margin-bottom:5px; float:none; height:2em; padding-left:3.5em; }
.object-tools li { display:block; float:left; background:url(../img/admin/tool-left.gif) 0 0 no-repeat; padding:0 0 0 8px; margin-left:2px; height:16px; }
.object-tools li:hover { background:url(../img/admin/tool-left_over.gif) 0 0 no-repeat; }
.object-tools a:link, .object-tools a:visited { display:block; float:left; color:white; padding:.1em 14px .1em 8px; height:14px; background:#999 url(../img/admin/tool-right.gif) 100% 0 no-repeat; }
.object-tools a:hover, .object-tools li:hover a { background:#5b80b2 url(../img/admin/tool-right_over.gif) 100% 0 no-repeat; }
.object-tools a.viewsitelink, .object-tools a.golink { background:#999 url(../img/admin/tooltag-arrowright.gif) top right no-repeat; padding-right:28px; }
.object-tools a.viewsitelink:hover, .object-tools a.golink:hover { background:#5b80b2 url(../img/admin/tooltag-arrowright_over.gif) top right no-repeat; }
.object-tools a.viewsitelink:hover, .object-tools a.golink:hover { background:#5b80b2 url(../img/admin/tooltag-arrowright_over.gif) top right no-repeat; }
.object-tools a.addlink { background:#999 url(../img/admin/tooltag-add.gif) top right no-repeat; padding-right:28px; }
.object-tools a.addlink:hover { background:#5b80b2 url(../img/admin/tooltag-add_over.gif) top right no-repeat; }
/* OBJECT HISTORY */
table#change-history { width:100%; }
table#change-history tbody th { width:16em; }
คราวหน้า ถ้าจะปรับเปลี่ยนเพิ่มเติม เพียงเปลี่ยนเฉพาะบรรทัดแรกจาก 84% ไปเป็นตัวเลขอื่นก็ปรับเฉพาะตัวนี้ตัวเดียว
เมื่อแปลงแล้วได้ภาพดังนี้
