I strongly recommend you bypass this article for the much clearer, up to date Mezzanine Tutorial Take 2.
I had a couple things in mind when I started this work:
cat >mypatchfile <<EOF \$$me EOF
Oh, and credit where credit due: Ross Laird's "First Steps" series on Mezzanine got me started. Thanks Ross! By comparison to Ross's conversational writeup, this article takes a bang-bang approach.
#names and passwords for the script
name="me" # name for scm setup email="me@domain.tld" # email for scm setup pguser_password="pgdbpw" # postgres db user password project_name="rodmtech" # name of project dbuser=$project_name # project database name dbname=$project_name # project database user dbpass=$project_name # project database password
for TAB in heredocs, see
http://stackoverflow.com/questions/3731513/how-do-you-type-a-tab-in-a-bash-here-document
T=$(echo -e '\t')
#system stuff, requiring sudo or su
Make sure your system is up to date...essential on a new install
sudo apt-get update sudo apt-get --yes upgrade
Check for 2.7 or better python
python -c 'import sys; print("ruh roh" if sys.version_info < (2, 7) else "scooby dooby doo")'
Setup industory standard scm tools (if you haven't already)
sudo apt-get --yes install mercurial git subversion
Just in case not already installed
sudo apt-get --yes install openssh-server curl
Install things needed for python package building, pip, virtualenv, virtualenvwrapper, fabric
sudo apt-get --yes install build-essential python-setuptools python-dev python-software-properties sudo easy_install pip # no pip package in ubuntu < 10, be sure with easy_install sudo pip install --upgrade virtualenv virtualenvwrapper sudo pip install --upgrade 'fabric>=1.0'
Install, setup postgresql for dbms, give postgres dbuser a passwored for localhost login
sudo apt-get --yes install postgresql postgresql-client libpq5 sudo -u postgres psql template1 <<EOF ALTER USER postgres WITH ENCRYPTED PASSWORD '$pguser_password'; EOF
Allow postgres password based logins locally
sudo -u postgres patch -p0 -b <<EOF --- /etc/postgresql/9.1/main/pg_hba.conf.orig${T}2013-01-21 17:38:53.213169701 -0800 +++ /etc/postgresql/9.1/main/pg_hba.conf${T}2013-01-21 17:39:18.873170239 -0800 @@ -87,7 +87,7 @@ # TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only -local all all peer +local all all md5 # IPv4 local connections: host all all 127.0.0.1/32 md5 # IPv6 local connections: EOF service postgresql restart
Install jpeg, png, freetype support, so Pillow (aka PIL) has jpg & png support
sudo apt-get install --yes libjpeg-dev zlib1g-dev libfreetype6-dev
# Create the database we'll use sudo -u postgres psql <<EOF DROP DATABASE IF EXISTS $dbname; DROP USER IF EXISTS $dbuser; CREATE USER $dbuser WITH ENCRYPTED PASSWORD '$dbpass'; ALTER USER $dbuser CREATEDB; CREATE DATABASE $dbname WITH OWNER $dbuser ENCODING = 'UTF8' LC_CTYPE = 'en_US.UTF-8' LC_COLLATE = 'en_US.UTF-8' TEMPLATE template0; EOF
# id self for git, hg echo " [ui] username = $name <$email> verbose = True " >> $HOME/.hgrc git config --global user.name "$name" git config --global user.email "$email"Setup virtualenvwrapper
mkdir ~/pyves cat >~/.virtualenvrc <<EOF export WORKON_HOME="$HOME/pyves" export PROJECT_HOME="$HOME/pyves" source /usr/local/bin/virtualenvwrapper.sh EOF source ~/.virtualenvrc
setup virtualenvwrapper at login
cat >>~/.bashrc <<EOF source $HOME/.virtualenvrc EOF
#setup the site
Create a virtualenv
mkvirtualenv $project_name cdvirtualenv
Get mezzanine and friends
pip install mezzanine south django-compressor Pillow psycopg2
Create a mezzanine project
mezzanine-project $project_name cd $project_name pwd >../.project # so virtualenvwrapper "cdproject" alaias works hg init hg add . hg commit -m 'genesis'
Setup postgres db for dev work.
Note: Give db user createdb for unittest db create, not reco'd for production
Update local_settings.py with project db setup.
cat >local_settings.py <<EOF
DEBUG = True
DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql_psycopg2", "NAME": "$dbname", "USER": "$dbuser", "PASSWORD": "$dbpass", "HOST": "localhost", "PORT": "", } } EOF
Before we can load the initial data fixture, django backend for psycopg2
has an undeployed bug. See django ticket 12728
mkdir requirements/patches cat >requirements/patches/django.ticket-12728.patch <<EOF --- lib/python2.7/site-packages/django.orig/db/backends/init.py${T}2012-12-18 00:44:27.000000000 -0800 +++ lib/python2.7/site-packages/django/db/backends/init.py${T}2012-12-18 01:17:51.276110288 -0800 @@ -973,7 +973,7 @@ # If this is an m2m using an intermediate table, # we don't need to reset the sequence. if f.rel.through is None: - sequence_list.append({'table': f.m2m_db_table(), 'column': None}) + sequence_list.append({'table': f.m2m_db_table(), 'column': f.m2m_reverse_name()})
return sequence_listdiff -u -r django.orig/db/backends/postgresql_psycopg2/operations.py django/db/backends/postgresql_psycopg2/operations.py --- lib/python2.7/site-packages/django.orig/db/backends/postgresql_psycopg2/operations.py${T}2012-12-18 00:44:27.000000000 -0800 +++ lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/operations.py${T}2012-12-18 01:19:19.120545886 -0800 @@ -133,12 +133,13 @@ break # Only one AutoField is allowed per model, so don't bother continuing. for f in model._meta.many_to_many: if not f.rel.through: + pk_column = f.m2m_reverse_name() output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ (style.SQL_KEYWORD('SELECT'), style.SQL_TABLE(qn(f.m2m_db_table())), - style.SQL_FIELD('id'), - style.SQL_FIELD(qn('id')), - style.SQL_FIELD(qn('id')), + style.SQL_FIELD(pk_column), + style.SQL_FIELD(qn(pk_column)), + style.SQL_FIELD(qn(pk_column)), style.SQL_KEYWORD('IS NOT'), style.SQL_KEYWORD('FROM'), style.SQL_TABLE(qn(f.m2m_db_table())))) EOF cat requirements/patches/django.ticket-12728.patch | (cdsitepackages && patch -r - -N -b -p3) hg add requirements/patches hg commit -m 'postgresql django backend has a bug, patch for django ticket 12728, save patch for future deploys'
Create the schema, add some site pages and give it a test
python manage.py createdb --noinput --nodata mkdir fixtures curl -L https://bitbucket.org/rmorison/rodmtech/raw/tip/static/misc/rodmtech_net_initdata.tgz | tar xvzf - hg add fixtures python manage.py loaddata fixtures/rodmtech_net_init.json
Make the home page an editable page in the page tree (see urls.py)
Page can be created via /admin or a fixture, as above
patch -p0 <<EOF --- urls.py.orig${T}2012-12-30 22:05:04.000000000 -0800 +++ urls.py${T}2012-12-30 23:50:01.649895137 -0800 @@ -27,7 +27,7 @@ # one homepage pattern, so if you use a different one, comment this # one out.
# HOMEPAGE AS AN EDITABLE PAGE IN THE PAGE TREE # --------------------------------------------- @@ -45,7 +45,7 @@ # "/.html" - so for this case, the template "pages/index.html" can # be used.
url("^$", "mezzanine.pages.views.page", {"slug": "/"}, name="home"),
# HOMEPAGE FOR A BLOG-ONLY SITE # ----------------------------- EOF hg commit -m 'initial site data and / mapped to CMS page'
# mod settings.py for site name, static, etc. patch -p0 <<EOF --- settings.py.orig${T}2013-02-12 22:25:23.246056760 -0800 +++ settings.py${T}2013-02-12 22:26:47.098472562 -0800 @@ -35,11 +35,11 @@ # menus a page should appear in. Note that if a menu template is used # that doesn't appear in this setting, all pages will appear in it.-# PAGE_MENU_TEMPLATES = ( -# (1, "Top navigation bar", "pages/menus/dropdown.html"), +PAGE_MENU_TEMPLATES = ( + (1, "Top navigation bar", "pages/menus/dropdown.html"), # (2, "Left-hand tree", "pages/menus/tree.html"), # (3, "Footer", "pages/menus/footer.html"), -# ) +)
# A sequence of fields that will be injected into Mezzanine's (or any # library's) models. Each item in the sequence is a four item sequence. @@ -98,7 +98,7 @@ # timezone as the operating system. # If running in a Windows environment this must be set to the same as your # system time zone. -TIME_ZONE = None +TIME_ZONE = "America/Los_Angeles"
# If you set this to True, Django will use timezone-aware datetimes. USE_TZ = True @@ -116,6 +116,9 @@ SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SITE_ID = 1 +SITE_TITLE = "rodmtech" +SITE_TAGLINE = "docs & thoughts" + EOF
start customizing: pull mezzanine.base templates, setup a static css/js/img
python manage.py collecttemplates mezzanine.core hg add templates hg commit -m 'mezzanine.core templates' templates patch -p0 <<EOF --- templates/base.html.orig${T}2013-02-12 22:01:32.274960952 -0800 +++ templates/base.html${T}2013-02-12 22:01:47.295035445 -0800 @@ -19,6 +19,7 @@ <link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.css"> <link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.responsive.css"> <link rel="stylesheet" href="{{ STATIC_URL }}css/mezzanine.css"> +<link rel="stylesheet" href="{{ STATIC_URL }}css/rodmtech.css"> {% ifinstalled cartridge.shop %} <link rel="stylesheet" href="{{ STATIC_URL }}css/cartridge.css"> {% endifinstalled %} @@ -87,9 +88,8 @@ <div class="container"> <div class="row">
-<div class="span2 left"> +<div class="span1 left"> {% block left_panel %} - <div class="panel tree">{% page_menu "pages/menus/tree.html" %}</div> {% endblock %} </div>
@@ -115,8 +115,6 @@
<footer> <div class="container"> -{% page_menu "pages/menus/footer.html" %} -<br style="clear:both"> <p> {% trans "Powered by" %} <a href="http://mezzanine.jupo.org">Mezzanine</a>{% ifinstalled cartridge.shop %}, EOF
tell hg only to ignore static/media...
patch -p0 <<EOF --- .hgignore.orig${T}Wed Feb 13 06:54:35 2013 -0800 +++ .hgignore${T}Wed Feb 13 10:33:51 2013 -0800 @@ -7,4 +7,4 @@ local_settings.py
syntax: regexp -^static/ +^static/media EOF hg commit -m 'tell hg only to ignore static/media' .hgignore
...then add static content to ./static/(css)|(js)|(img)
mkdir -p static/css static/js static/img curl -L https://bitbucket.org/rmorison/rodmtech/raw/tip/static/misc/rodmtech_net_initstatic.tgz | tar xvzf - hg add static/css static/js static/img
hg commit -m 'first customization: - customize base.html - some custom css - remove left & bottom menus - add title, tagline and tz to settings '
# customize the homepage template: append list of recent posts when on home page python manage.py collecttemplates mezzanine.pages hg add templates hg commit -m 'mezzanine.pages templates' patch -p0 <<EOF --- templates/base.html${T}Mon Dec 31 01:09:11 2012 -0800 +++ templates/base.html${T}Mon Dec 31 01:42:39 2012 -0800 @@ -93,22 +99,12 @@ {% endblock %} </div>-<div class="span7 middle"> +<div class="{% block main_span %}span9{% endblock %} middle"> {% block main %}{% endblock %} </div>
-<div class="span3 right"> - {% nevercache %} - {% include "includes/user_panel.html" %} - {% endnevercache %} - <div class="panel"> - {% block right_panel %} - {% ifinstalled mezzanine.twitter %} - {% include "twitter/tweets.html" %} - {% endifinstalled %} - {% endblock %} - </div> -</div> +{% block optional_right_panel %} +{% endblock %}
</div> </div> EOF patch -p0 <<EOF --- templates/pages/index.html.orig${T}2013-02-12 17:01:24.000000000 -0800 +++ templates/pages/index.html${T}2013-02-12 22:44:38.415784934 -0800 @@ -1,5 +1,7 @@
+{% load blog_tags i18n future %} + {% block main %} <!-- This template is provided as a custom template for the homepage, for @@ -7,4 +9,18 @@ free to modify it. --> {{ block.super }} +<hr/> +{% block blog_recent_posts %} +{% blog_recent_posts 5 as recent_posts %} +{% if recent_posts %} +<h3>{% trans "Recent Posts" %}</h3> +<ul class="unstyled recent-posts"> +{% for recent_post in recent_posts %} +<li><a href="{{ recent_post.get_absolute_url }}" + >{{ recent_post.title }}</a></li> +{% endfor %} +</ul> +{% endif %} +{% endblock %} + {% endblock %} EOF hg commit -m 'customize pages templates: - widen main content blocki '
# add SyntaxHighligher to site, syntaxhl tinymce plugin, turn on other tinymce options ( cd /tmp && \ curl http://alexgorbatchev.com/SyntaxHighlighter/download/download.php?sh_current \ --output syntaxhighlighter.zip && \ unzip syntaxhighlighter.zip \ ) mkdir static/syntaxhighlighter cp -a /tmp/syntaxhighlighter_3.0.83/styles/ /tmp/syntaxhighlighter_3.0.83/scripts/ static/syntaxhighlighter/ ( cd /tmp && \ curl -L https://github.com/RichGuk/syntaxhl/archive/master.zip --output master.zip && \ unzip master.zip \ ) mv /tmp/syntaxhl-master/ static/syntaxhl curl -L https://bitbucket.org/rmorison/rodmtech/raw/tip/static/misc/rodmtech_net_tinymce_setup.tgz | tar xvzf -must fix relative path in syntaxhl because we're loading external
sed --in-place \ -e "s?../../tiny_mce_popup.js?/static/grappelli/tinymce/jscripts/tiny_mce/tiny_mce_popup.js?" \ static/syntaxhl/dialog.htm
customize tinymce setup and twitter settings
patch -p0 <<EOF --- settings.py.orig${T}Wed Feb 13 06:54:35 2013 -0800 +++ settings.py${T}Wed Feb 13 07:14:56 2013 -0800 @@ -305,6 +305,23 @@
DEBUG_TOOLBAR_CONFIG = {"INTERCEPT_REDIRECTS": False}
+##################### +# TINYMCE SETTTINGS # +##################### + +TINYMCE_SETUP_JS = "js/tinymce_setup.js" +RICHTEXT_ALLOWED_STYLES = ('font-size', 'color', 'background-color', 'font-family', 'height') + + +##################### +# TWITTER SETTTINGS # +##################### + +TWITTER_DEFAULT_QUERY_TYPE = "user" +TWITTER_DEFAULT_QUERY = "rodmtech" +TWITTER_DEFAULT_NUM_TWEETS = 5 + + ################### # DEPLOY SETTINGS # ################### EOF
include syntaxhighlighter scripts and css in base template
patch -p0 <<EOF --- templates/base.html.org${T}2013-02-13 06:51:01.268494885 -0800 +++ templates/base.html${T}2013-02-12 22:44:13.047659149 -0800 @@ -19,6 +19,8 @@ <link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.css"> <link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.responsive.css"> <link rel="stylesheet" href="{{ STATIC_URL }}css/mezzanine.css"> +<link rel="stylesheet" href="{{ STATIC_URL }}syntaxhighlighter/styles/shThemeDefault.css"> +<link rel="stylesheet" href="{{ STATIC_URL }}syntaxhighlighter/styles/shCore.css"> <link rel="stylesheet" href="{{ STATIC_URL }}css/rodmtech.css"> {% ifinstalled cartridge.shop %} <link rel="stylesheet" href="{{ STATIC_URL }}css/cartridge.css"> @@ -29,6 +31,10 @@ {% compress js %} <script src="{{ STATIC_URL }}mezzanine/js/{{ settings.JQUERY_FILENAME }}"></script> <script src="{{ STATIC_URL }}js/bootstrap.min.js"></script> +<script src="{{ STATIC_URL }}syntaxhighlighter/scripts/shCore.js"></script> +<script src="{{ STATIC_URL }}syntaxhighlighter/scripts/shBrushPython.js"></script> +<script src="{{ STATIC_URL }}syntaxhighlighter/scripts/shBrushBash.js"></script> +<script src="{{ STATIC_URL }}syntaxhighlighter/scripts/shBrushCpp.js"></script> <script> \$(function() { \$('.middleinput:text, textarea').addClass('xlarge'); @@ -121,6 +127,10 @@ </div> </footer>
+<script type="text/javascript"> + SyntaxHighlighter.all() +</script> +
</body> EOF hg add static hg commit -m 'Add SyntaxHighligher, syntaxhl tinymce plugin, turn on other tinymce options'
add tweets back to index.html (was in base.html)
patch -p0 <<EOF --- templates/pages/index.html.orig${T}2013-02-13 13:36:25.969114562 -0800 +++ templates/pages/index.html${T}2013-02-13 06:51:01.268494885 -0800 @@ -1,13 +1,11 @@
-{% load blog_tags i18n future %} +{% load mezzanine_tags blog_tags i18n future %}
+<!--CMS Page block--> +{% block main_span %}span6{% endblock %} {% block main %} -<!-- -This template is provided as a custom template for the homepage, for -when it is configured as an editable page in the navigation tree. Feel -free to modify it. ---> + {{ block.super }} <hr/> {% block blog_recent_posts %} @@ -24,3 +22,22 @@
{% endblock %} + + +<!--Right panel block--> +{% block optional_right_panel %} + +<div class="span3 right"> + {% nevercache %} + {% include "includes/user_panel.html" %} + {% endnevercache %} + <div class="panel"> + {% block right_panel %} + {% ifinstalled mezzanine.twitter %} + {% include "twitter/tweets.html" %} + {% endifinstalled %} + {% endblock %} + </div> +</div> + +{% endblock %} EOF hg commit -m 'add tweets back to index.html (was in base.html)'
# remove syntaxhighlighter toolbar, doesn't do much in latest release patch -b -p0 <<EOF --- templates/base.html${T}Thu Feb 14 23:39:56 2013 -0800 +++ templates/base.html${T}Fri Feb 15 00:33:56 2013 -0800 @@ -128,7 +128,8 @@ </footer><script type="text/javascript"> - SyntaxHighlighter.all() + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all() </script>
{% include "includes/footer_scripts.html" %} EOF hg commit -m "remove syntaxhighlighter toolbar, doesn't do much in latest release"
#sit back, stir with content and enjoy!
python manage.py runserver