読者です 読者をやめる 読者になる 読者になる

akiyoko blog

akiyoko の IT技術系ブログです

Mezzanine プロジェクトの開発環境を PyCharm で設定する

Django Python PyCharm 開発環境 Mezzanine

はじめに

以前に「見よ!これが Python製の WordPress風フルスタックCMSフレームワーク「Mezzanine(メザニン)」だ!」という記事で、Python製の WordPress風フルスタックCMSフレームワーク「Mezzanine」を紹介しましたが、今回は、その Mezzanine プロジェクトの開発環境を、Mac版 PyCharm Professional Edition で設定するための手順を書いてみます。


PyCharm Professional Edition は Homebrew-Cask でインストールしています。

<過去記事>
akiyoko.hatenablog.jp

PyCharm の初期設定は済んでいるという前提で進めます。

<過去記事>
akiyoko.hatenablog.jp

やりたいこと

  • 最新版の Mezzanine プロジェクトを Vagrant サーバにインストール
  • Vagrant サーバと Mac上の PyCharm とのソースコード同期設定
  • リモートデバッグ設定
  • Mezzanine テーマを変更

環境

<クライアント>

  • Mac OS X 10.10.5
  • PyCharm (Professional Edition) 5.0.4

<サーバ>

  • Ubuntu 14.04 LTS(on Vagrant)
    • IPアドレス:192.168.33.103
    • ログインユーザ:vagrant

<Mezzanineプロジェクト>

  • Django 1.9.5
  • Mezzanine 4.1.0
  • Cartridge 0.11.0



 

1. PyCharm の設定(1)

1.1. Pure Python Project を作成

PyCharm を起動し、 [Create New Project] をクリックします。

[Pure Python] を選択し、

Location /Users/akiyoko/PycharmProjects/mezzanine_project
Interpreter (適当)

を設定します。Interpreter は、後でリモート側の virtualenv のものに変更するので、ここでは適当なものを選択しておきます。

f:id:akiyoko:20160313142425p:plain

ここで、[Django] プロジェクトではなく [Pure Python] を選択した理由は、[Pure Python] プロジェクトにしておかないとリモートデバッグ機能が使えない(はずだ)からです。


 

1.2. Vagrant連携

[Tools] > [Vagrant] > [Init in Project Root] を選択します。


PyCharm 上で、Vagrantfile を開いて編集します。

<変更後>

  config.vm.network "private_network", ip: "192.168.33.103"

[Tools] > [Vagrant] > [Up] でインスタンスを起動します。




 

2. Vagrantサーバの初期設定

Vagrant サーバに ssh で乗り込みます。

$ ssh vagrant@192.168.33.103

 

2.1. 最低限のインストール

$ sudo apt-get update
$ sudo apt-get -y install python-dev git tree

 

2.2. MySQL をインストール

Ubuntu サーバに MySQL をインストールします。

sudo apt-get -y install mysql-server
(root/rootpass)
sudo apt-get -y install mysql-client libmysqlclient-dev python-mysqldb

$ mysql --version
mysql  Ver 14.14 Distrib 5.5.47, for debian-linux-gnu (x86_64) using readline 6.3

sudo mysql_install_db

### 文字化け対策(セクションの最後に以下の設定を追加)
### http://blog.snowcait.info/2014/06/04/mariadb-utf8/
$ sudo vi /etc/mysql/my.cnf
---
[mysqld]
  ・
  ・
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem

# Character set settings
character-set-server = utf8

[mysqldump]
  ・
  ・
---

$ sudo service mysql restart

$ sudo mysql_secure_installation
Enter current password for root (enter for none):
Change the root password? [Y/n] n
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y
参考



データベース、データベースユーザを作成します。
なお、データベース名は Djangoプロジェクト名と合わせて myproject とします。

データベース名 myproject
データベースユーザ myprojectuser
データベースユーザパスワード myprojectuserpass
$ mysql -u root -p
mysql> create database myproject character set utf8;
mysql> create user myprojectuser@localhost identified by "myprojectuserpass";
mysql> grant all privileges on myproject.* to myprojectuser@localhost;
mysql> flush privileges;
mysql> exit


 

2.3. pip をインストール

Python 2.7.9 以降であれば pip がバンドルされているが、Ubuntu 14.04LTS では Python 2.7.6 が標準なので、手動でインストールします。

「sudo apt-get -y install python-pip」でインストールすると pip のバージョンが古いので、get-pip.py で最新版を入れることにします。

$ wget https://bootstrap.pypa.io/get-pip.py
$ sudo -H python get-pip.py
$ pip --version
pip 8.1.0 from /usr/local/lib/python2.7/dist-packages (python 2.7)

2.4. virtualenv, virtualenvwrapper をインストール

### virtualenv, virtualenvwrapper をインストール
$ sudo -H pip install virtualenv virtualenvwrapper

### virtualenvwrapper の設定
$ cat << EOF >> ~/.bash_profile

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi
EOF
$ cat << EOF >> ~/.bashrc

source /usr/local/bin/virtualenvwrapper.sh
export WORKON_HOME=~/.virtualenvs
EOF
$ source ~/.bashrc


 

2.5. Mezzanineプロジェクトを作成

Overview — Mezzanine 4.1.0 documentation
に従って、Mezzanineプロジェクトのインストールをします。

### Djangoプロジェクトの virtualenv 環境を設定して activate
$ mkvirtualenv myproject

### /opt/webapps 配下にプロジェクトの外箱を作成
$ sudo mkdir -p /opt/webapps/myproject
$ sudo chown -R `whoami`. /opt/webapps

### イメージライブラリのインストール
### http://mezzanine.jupo.org/docs/overview.html#dependencies
$ sudo apt-get -y install libjpeg8 libjpeg8-dev
$ sudo apt-get -y build-dep python-imaging

### MySQLライブラリのインストール
$ pip install MySQL-python

### Mezzanine プロジェクトを作成
$ cd /opt/webapps/myproject/
### Cartridge のインストール
$ pip install -U cartridge

$ pip list |grep Django
Django (1.9.5)
$ pip list |grep Mezzanine
Mezzanine (4.1.0)
$ pip list |grep Cartridge
Cartridge (0.11.0)

### プロジェクトのディレクトリ構造は
### myproject/ as <repository_root> also as <django_project_root>
### └─ config/ as <configuration_root>
$ mezzanine-project -a cartridge config .

$ tree -a /opt/webapps/myproject/
/opt/webapps/myproject/
├── config
│   ├── dev.db
│   ├── __init__.py
│   ├── local_settings.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── deploy
│   ├── crontab.template
│   ├── gunicorn.conf.py.template
│   ├── local_settings.py.template
│   ├── nginx.conf.template
│   └── supervisor.conf.template
├── .DS_Store
├── fabfile.py
├── .gitignore
├── .hgignore
├── __init__.py
├── manage.py
└── requirements.txt

 

2.6. Django のデータベース設定を変更

### デフォルトで用意されている config/dev.db は不要なので削除
$ rm config/dev.db

### MySQL用の設定変更
$ vi config/local_settings.py

<変更前>
---
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": "dev.db",
        "USER": "",
        "PASSWORD": "",
        "HOST": "",
        "PORT": "",
    }
}
---

<変更後>
---
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "myproject",
        "USER": "myprojectuser",
        "PASSWORD": "myprojectuserpass",
        "HOST": "localhost",
        "PORT": "",
    }
}


 

2.7. デモ用のレコードを投入

createdb でデモ用のレコードを投入することができます。

### migrate実行
### --noinput オプションを付けると、デモ用の初期データ(site, superuser, 画像などのコンテンツ, etc)を自動登録
### --nodata オプションを付けると、デモ用画像やギャラリーなどのコンテンツを static 配下に自動作成しない
$ python manage.py createdb --noinput

### とりあえずデータベースをバックアップ
### http://weblabo.oscasierra.net/mysql-mysqldump-01/
### ちなみに、リストアするときは mysql -u root -p myproject < ~/myproject_init.dump
$ mysqldump --single-transaction -u root -p myproject > ~/myproject_init.dump


 

2.8. runserver で起動

$ python manage.py runserver 0.0.0.0:8000

http://192.168.33.103:8000/admin/
にブラウザからアクセスします。
(admin/default)


疎通がOKなら、runserver を一旦停止します。


 

3. PyCharm の設定(2)

3.1. デプロイ先サーバ設定

[Tools] > [Deployment] > [Options] の [Exclude items by name] に以下を設定します。

.svn;.cvs;.idea;.DS_Store;.git;.hg;.vagrant;Vagrantfile;*.pyc;*.swp;*.db;*.sock;*.pid

f:id:akiyoko:20160625112113p:plain

[Tools] > [Deployment] > [Configuration] で設定画面を開き、「+」ボタンをクリックしてサーバの設定を追加します。

Name mezzanine_project
Type SFTP

f:id:akiyoko:20160313155825p:plain

各種設定をします。

[Connection]

[Visible only for this project] にチェックを入れます。

SFTP host 192.168.33.103
Port 22
Root path /([Autodetect] はクリックしない。「/home/vagrant」だとファイルを同期ダウンロードできなくなる)
User name vagrant
Password vagant([Save password] にチェックを入れる)

f:id:akiyoko:20160313155856p:plain

[Mappings]

[Use this server as default] をクリックします。

Local path /Users/akiyoko/PycharmProjects/mezzanine_project(デフォルトのまま)
Deployment path /opt/webapps/myproject

f:id:akiyoko:20160313155920p:plain


 

3.2. ソースコードの同期

プロジェクトで右クリック > [Deployment] > [Download from mezzanine_project] を選択して、Vagrantサーバから PyCharm にプロジェクトをダウンロードします。


ここで、[Tools] > [Deployment] > [Automatic Upload] にチェックを入れます。


 

3.3. ローカル側でソースコードを Git管理

まず、不要なファイルを削除します。
Mercurialは使わないので .hgignore を Projectペイン上で削除します。


次に、PyCharm の Terminal を開きます。

まだ git config -l の設定をしていなければ、PyCharm の Terminal で以下を設定します。

$ cd ~/PycharmProjects/mezzanine_project/
$ git config --global user.name akiyoko
$ git config --global user.email akiyoko@users.noreply.github.com
$ git config --global color.ui auto

git init する前に、.gitignore に PyCharm 用の設定を追加しておきます。

.gitignore

*.pyc
*.pyo
*.db
.DS_Store
.coverage
local_settings.py
/static

# PyCharm
.idea/
.vagrant/
Vagrantfile


一旦コミットします。

$ git init
$ git add .
$ git commit -m "Initial commit"

 

3.4. Project Interpreter の設定

[Preferences] > [Project: mezzanine_project] > [Project Interpreter] から、[Python Interpreter] の右側の歯車アイコンをクリックし、[Add Remote] を選択します。


[Vagrant] を選択し、

Vagrant Instance Folder /Users/akiyoko/PycharmProjects/mezzanine_project(デフォルトのまま)
Vagrant Host URL ssh://vagrant@127.0.0.1:2222(デフォルトのまま)
Python interpreter path /home/vagrant/.virtualenvs/myproject/bin/python

を入力して、OK をクリックします。

f:id:akiyoko:20160313160715p:plain

作成した Remote Interpreter が選択されていることを確認して、[OK] をクリックします。



ここで、Python モジュールに参照エラーが出ないようにするために、[File] > [Invalidate Caches / Restart] を選択し、[Invalidate and Restart] をクリックして、PyCharm を再起動しておきます。


 

3.5. Run/Debug設定

Project ペインの manage.py ファイルで右クリック > [Create "manage"] を選択します。

Name manage
Script manage.py
Script parameters runserver 0.0.0.0:8000
Environment variables PYTHONUNBUFFERED=1(デフォルトのまま)
Python interpreter Project Default (Remote Python 2.7.6 Vagrant VM at ~/PycharmProjects/mezzanine_project (/home/vagrant/.virtualenvs/myproject/bin/python))
Working directory /opt/webapps/myproject
Path mappings - Local path /Users/akiyoko/PycharmProjects/mezzanine_project
Path mappings - Remote path /opt/webapps/myproject

ここで、「Add content roots to PYTHONPATH」と「Add source roots to PYTHONPATH」のチェックを外します。

f:id:akiyoko:20160314074038p:plain

デバッグ実行できるか確認できれば、OKです。




 

3.6. テンプレート設定

ここで、Mezzanine本体の templates をコピーしておきます。

Vagrant サーバ側で、

$ cd /opt/webapps/myproject/
### Mezzanine のテンプレートをコピー
$ cp -a ~/.virtualenvs/myproject/lib/python2.7/site-packages/mezzanine/core/templates .
### Cartridge のテンプレートをコピー
$ cp -a ~/.virtualenvs/myproject/lib/python2.7/site-packages/cartridge/shop/templates .

を実行した後、PyCharm 上でファイルを同期(ダウンロード)します。


テンプレート(htmlファイル)が参照エラーで真っ赤に染まってしまっている場合は、[Preferences] > [Languages & Frameworks] > [Python Template Languages] から、「Template language」を「Django」に設定すれば解消するはずです。

f:id:akiyoko:20160313161637p:plain






 

4. テーマ変更

参考


試しに、
https://github.com/thecodinghouse/mezzanine-themes.git
の moderna テーマを入れてみます。


ローカル側で、以下を実行します。

$ cd ~/dev/
$ git clone https://github.com/thecodinghouse/mezzanine-themes.git
$ cp -a mezzanine-themes/moderna ~/PycharmProjects/mezzanine_project/

コマンドでコピーしたファイルはサーバ側に自動転送されないので、[Deployment] > [Upload to mezzanine_project] で手動アップロードしておきます。


コピーしたテーマを Djangoアプリケーションとして設定するために、config/settings.py の INSTALLED_APPS の最後、および TEMPLATES/DIRS の先頭に追加します。

config/settings.py

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            os.path.join(PROJECT_ROOT, "moderna/templates"),
            os.path.join(PROJECT_ROOT, "templates")
        ],
        "APP_DIRS": True,
        ・
        ・
]

INSTALLED_APPS = (
    ・
    ・
    "mezzanine.twitter",
    # "mezzanine.accounts",
    # "mezzanine.mobile",
    "moderna",
)

まとめ

Mezzanine は普通の Django プロジェクトなので、インストールやテンプレートの設定自体は Django のものと何ら変わりません。


あとはドキュメントを読むだけですね。

Mezzanine — Mezzanine 4.1.0 documentation



 

参考

最新版 Mezzanine インストール時のパッケージ情報
$ pip freeze
beautifulsoup4==4.4.1
bleach==1.4.2
Cartridge==0.11.0
chardet==2.3.0
Django==1.9.5
django-contrib-comments==1.7.0
filebrowser-safe==0.4.3
future==0.15.2
grappelli-safe==0.4.2
html5lib==0.9999999
Mezzanine==4.1.0
MySQL-python==1.2.5
oauthlib==1.0.3
Pillow==3.2.0
PyPDF2==1.25.1
pytz==2016.3
reportlab==3.3.0
requests==2.9.1
requests-oauthlib==0.6.1
six==1.10.0
tzlocal==1.2.2
xhtml2pdf==0.0.6


 

各種 URLconf

config/urls.py

from __future__ import unicode_literals

from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.views.i18n import set_language
from mezzanine.core.views import direct_to_template
from mezzanine.conf import settings

from cartridge.shop.views import order_history


admin.autodiscover()

# Add the urlpatterns for any custom Django applications here.
# You can also change the ``home`` view to add your own functionality
# to the project's homepage.

urlpatterns = i18n_patterns(
    # Change the admin prefix here to use an alternate URL for the
    # admin interface, which would be marginally more secure.
    url("^admin/", include(admin.site.urls)),
)

if settings.USE_MODELTRANSLATION:
    urlpatterns += [
        url('^i18n/$', set_language, name='set_language'),
    ]

urlpatterns += [

    # Cartridge URLs.
    url("^shop/", include("cartridge.shop.urls")),
    url("^account/orders/$", order_history, name="shop_order_history"),

    # We don't want to presume how your homepage works, so here are a
    # few patterns you can use to set it up.

    # HOMEPAGE AS STATIC TEMPLATE
    # ---------------------------
    # This pattern simply loads the index.html template. It isn't
    # commented out like the others, so it's the default. You only need
    # one homepage pattern, so if you use a different one, comment this
    # one out.

    url("^$", direct_to_template, {"template": "index.html"}, name="home"),

    # HOMEPAGE AS AN EDITABLE PAGE IN THE PAGE TREE
    # ---------------------------------------------
    # This pattern gives us a normal ``Page`` object, so that your
    # homepage can be managed via the page tree in the admin. If you
    # use this pattern, you'll need to create a page in the page tree,
    # and specify its URL (in the Meta Data section) as "/", which
    # is the value used below in the ``{"slug": "/"}`` part.
    # Also note that the normal rule of adding a custom
    # template per page with the template name using the page's slug
    # doesn't apply here, since we can't have a template called
    # "/.html" - so for this case, the template "pages/index.html"
    # should be used if you want to customize the homepage's template.
    # NOTE: Don't forget to import the view function too!

    # url("^$", mezzanine.pages.views.page, {"slug": "/"}, name="home"),

    # HOMEPAGE FOR A BLOG-ONLY SITE
    # -----------------------------
    # This pattern points the homepage to the blog post listing page,
    # and is useful for sites that are primarily blogs. If you use this
    # pattern, you'll also need to set BLOG_SLUG = "" in your
    # ``settings.py`` module, and delete the blog page object from the
    # page tree in the admin if it was installed.
    # NOTE: Don't forget to import the view function too!

    # url("^$", mezzanine.blog.views.blog_post_list, name="home"),

    # MEZZANINE'S URLS
    # ----------------
    # ADD YOUR OWN URLPATTERNS *ABOVE* THE LINE BELOW.
    # ``mezzanine.urls`` INCLUDES A *CATCH ALL* PATTERN
    # FOR PAGES, SO URLPATTERNS ADDED BELOW ``mezzanine.urls``
    # WILL NEVER BE MATCHED!

    # If you'd like more granular control over the patterns in
    # ``mezzanine.urls``, go right ahead and take the parts you want
    # from it, and use them directly below instead of using
    # ``mezzanine.urls``.
    url("^", include("mezzanine.urls")),

    # MOUNTING MEZZANINE UNDER A PREFIX
    # ---------------------------------
    # You can also mount all of Mezzanine's urlpatterns under a
    # URL prefix if desired. When doing this, you need to define the
    # ``SITE_PREFIX`` setting, which will contain the prefix. Eg:
    # SITE_PREFIX = "my/site/prefix"
    # For convenience, and to avoid repeating the prefix, use the
    # commented out pattern below (commenting out the one above of course)
    # which will make use of the ``SITE_PREFIX`` setting. Make sure to
    # add the import ``from django.conf import settings`` to the top
    # of this file as well.
    # Note that for any of the various homepage patterns above, you'll
    # need to use the ``SITE_PREFIX`` setting as well.

    # url("^%s/" % settings.SITE_PREFIX, include("mezzanine.urls"))

]

# Adds ``STATIC_URL`` to the context of error pages, so that error
# pages can use JS, CSS and images.
handler404 = "mezzanine.core.views.page_not_found"
handler500 = "mezzanine.core.views.server_error"


/home/vagrant/.virtualenvs/myproject/local/lib/python2.7/site-packages/mezzanine/urls.py

"""
This is the main ``urlconf`` for Mezzanine - it sets up patterns for
all the various Mezzanine apps, third-party apps like Grappelli and
filebrowser.
"""

from __future__ import unicode_literals
from future.builtins import str

from django.conf.urls import include, url
from django.contrib.sitemaps.views import sitemap
from django.views.i18n import javascript_catalog
from django.http import HttpResponse

from mezzanine.conf import settings
from mezzanine.core.sitemaps import DisplayableSitemap


urlpatterns = []

# JavaScript localization feature
js_info_dict = {'domain': 'django'}
urlpatterns += [
    url(r'^jsi18n/(?P<packages>\S+?)/$', javascript_catalog, js_info_dict),
]

if settings.DEBUG and "debug_toolbar" in settings.INSTALLED_APPS:
    try:
        import debug_toolbar
    except ImportError:
        pass
    else:
        urlpatterns += [
            url(r'^__debug__/', include(debug_toolbar.urls)),
        ]

# Django's sitemap app.
if "django.contrib.sitemaps" in settings.INSTALLED_APPS:
    sitemaps = {"sitemaps": {"all": DisplayableSitemap}}
    urlpatterns += [
        url("^sitemap\.xml$", sitemap, sitemaps),
    ]

# Return a robots.txt that disallows all spiders when DEBUG is True.
if getattr(settings, "DEBUG", False):
    urlpatterns += [
        url("^robots.txt$", lambda r: HttpResponse("User-agent: *\nDisallow: /",
                                                   content_type="text/plain")),
    ]

# Miscellanous Mezzanine patterns.
urlpatterns += [
    url("^", include("mezzanine.core.urls")),
    url("^", include("mezzanine.generic.urls")),
]

# Mezzanine's Accounts app
if "mezzanine.accounts" in settings.INSTALLED_APPS:
    # We don't define a URL prefix here such as /account/ since we want
    # to honour the LOGIN_* settings, which Django has prefixed with
    # /account/ by default. So those settings are used in accounts.urls
    urlpatterns += [
        url("^", include("mezzanine.accounts.urls")),
    ]

# Mezzanine's Blog app.
blog_installed = "mezzanine.blog" in settings.INSTALLED_APPS
if blog_installed:
    BLOG_SLUG = settings.BLOG_SLUG.rstrip("/") + "/"
    blog_patterns = [
        url("^%s" % BLOG_SLUG, include("mezzanine.blog.urls")),
    ]
    urlpatterns += blog_patterns

# Mezzanine's Pages app.
PAGES_SLUG = ""
if "mezzanine.pages" in settings.INSTALLED_APPS:
    # No BLOG_SLUG means catch-all patterns belong to the blog,
    # so give pages their own prefix and inject them before the
    # blog urlpatterns.
    if blog_installed and not BLOG_SLUG.rstrip("/"):
        PAGES_SLUG = getattr(settings, "PAGES_SLUG", "pages").strip("/") + "/"
        blog_patterns_start = urlpatterns.index(blog_patterns[0])
        urlpatterns[blog_patterns_start:len(blog_patterns)] = [
            url("^%s" % str(PAGES_SLUG), include("mezzanine.pages.urls")),
        ]
    else:
        urlpatterns += [
            url("^", include("mezzanine.pages.urls")),
        ]


/home/vagrant/.virtualenvs/myproject/local/lib/python2.7/site-packages/mezzanine/core/urls.py

from __future__ import unicode_literals

from django.conf.urls import url
from django.contrib.auth import views as auth_views

from mezzanine.conf import settings
from mezzanine.core import views as core_views


urlpatterns = []

if "django.contrib.admin" in settings.INSTALLED_APPS:
    urlpatterns += [
        url("^password_reset/$", auth_views.password_reset,
            name="password_reset"),
        url("^password_reset/done/$", auth_views.password_reset_done,
            name="password_reset_done"),
        url("^reset/done/$", auth_views.password_reset_complete,
            name="password_reset_complete"),
        url("^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$",
            auth_views.password_reset_confirm, name="password_reset_confirm"),
    ]

urlpatterns += [
    url("^edit/$", core_views.edit, name="edit"),
    url("^search/$", core_views.search, name="search"),
    url("^set_site/$", core_views.set_site, name="set_site"),
    url("^set_device/(?P<device>.*)/$", core_views.set_device,
        name="set_device"),
    url("^asset_proxy/$", core_views.static_proxy, name="static_proxy"),
    url("^displayable_links.js$", core_views.displayable_links_js,
        name="displayable_links_js"),
]


/home/vagrant/.virtualenvs/myproject/local/lib/python2.7/site-packages/mezzanine/generic/urls.py

from __future__ import unicode_literals

from django.conf.urls import url

from mezzanine.generic import views


urlpatterns = [
    url("^admin_keywords_submit/$", views.admin_keywords_submit,
        name="admin_keywords_submit"),
    url("^rating/$", views.rating, name="rating"),
    url("^comment/$", views.comment, name="comment"),
]


/home/vagrant/.virtualenvs/myproject/local/lib/python2.7/site-packages/mezzanine/blog/urls.py

from __future__ import unicode_literals

from django.conf.urls import url

from mezzanine.blog import views
from mezzanine.conf import settings


# Trailing slahes for urlpatterns based on setup.
_slash = "/" if settings.APPEND_SLASH else ""

# Blog patterns.
urlpatterns = [
    url("^feeds/(?P<format>.*)%s$" % _slash,
        views.blog_post_feed, name="blog_post_feed"),
    url("^tag/(?P<tag>.*)/feeds/(?P<format>.*)%s$" % _slash,
        views.blog_post_feed, name="blog_post_feed_tag"),
    url("^tag/(?P<tag>.*)%s$" % _slash,
        views.blog_post_list, name="blog_post_list_tag"),
    url("^category/(?P<category>.*)/feeds/(?P<format>.*)%s$" % _slash,
        views.blog_post_feed, name="blog_post_feed_category"),
    url("^category/(?P<category>.*)%s$" % _slash,
        views.blog_post_list, name="blog_post_list_category"),
    url("^author/(?P<username>.*)/feeds/(?P<format>.*)%s$" % _slash,
        views.blog_post_feed, name="blog_post_feed_author"),
    url("^author/(?P<username>.*)%s$" % _slash,
        views.blog_post_list, name="blog_post_list_author"),
    url("^archive/(?P<year>\d{4})/(?P<month>\d{1,2})%s$" % _slash,
        views.blog_post_list, name="blog_post_list_month"),
    url("^archive/(?P<year>\d{4})%s$" % _slash,
        views.blog_post_list, name="blog_post_list_year"),
    url("^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/"
        "(?P<slug>.*)%s$" % _slash,
        views.blog_post_detail, name="blog_post_detail_day"),
    url("^(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<slug>.*)%s$" % _slash,
        views.blog_post_detail, name="blog_post_detail_month"),
    url("^(?P<year>\d{4})/(?P<slug>.*)%s$" % _slash,
        views.blog_post_detail, name="blog_post_detail_year"),
    url("^(?P<slug>.*)%s$" % _slash,
        views.blog_post_detail, name="blog_post_detail"),
    url("^$", views.blog_post_list, name="blog_post_list"),
]


/home/vagrant/.virtualenvs/myproject/local/lib/python2.7/site-packages/mezzanine/pages/urls.py

from __future__ import unicode_literals

from django.conf.urls import url
from django.conf import settings

from mezzanine.pages import page_processors, views


page_processors.autodiscover()

# Page patterns.
urlpatterns = [
    url("^admin_page_ordering/$", views.admin_page_ordering,
        name="admin_page_ordering"),
    url("^(?P<slug>.*)%s$" % ("/" if settings.APPEND_SLASH else ""),
        views.page, name="page"),
]


/home/vagrant/.virtualenvs/myproject/local/lib/python2.7/site-packages/cartridge/shop/urls.py

from __future__ import unicode_literals

from django.conf.urls import url
from mezzanine.conf import settings

from cartridge.shop import views


_slash = "/" if settings.APPEND_SLASH else ""

urlpatterns = [
    url("^product/(?P<slug>.*)%s$" % _slash, views.product,
        name="shop_product"),
    url("^wishlist%s$" % _slash, views.wishlist, name="shop_wishlist"),
    url("^cart%s$" % _slash, views.cart, name="shop_cart"),
    url("^checkout%s$" % _slash, views.checkout_steps, name="shop_checkout"),
    url("^checkout/complete%s$" % _slash, views.complete,
        name="shop_complete"),
    url("^invoice/(?P<order_id>\d+)%s$" % _slash, views.invoice,
        name="shop_invoice"),
    url("^invoice/(?P<order_id>\d+)/resend%s$" % _slash,
        views.invoice_resend_email, name="shop_invoice_resend"),
]