Преглед изворни кода

Fix merge conflicts, including migration merge issue

Edd Baldry пре 8 година
родитељ
комит
91a000a020

+ 1 - 0
.gitignore

@@ -9,6 +9,7 @@
 .~*
 common/CACHE
 bakerydemo/media/*
+bakerydemo/settings/local.py
 bakerydemodb
 __pycache__
 .*

+ 7 - 15
bakerydemo/blog/models.py

@@ -111,13 +111,10 @@ class BlogPage(Page):
 
     parent_page_types = ['BlogIndexPage']
 
-    # Defining what content type can sit under the parent
-    # The empty array means that no children can be placed under the
-    # LocationPage page model
+    # Define what content types can exist as children of BlogPage.
+    # Empty list means that no child content types are allowed.
     subpage_types = []
 
-    # api_fields = ['image', 'body']
-
 
 class BlogIndexPage(RoutablePageMixin, Page):
     """
@@ -125,8 +122,9 @@ class BlogIndexPage(RoutablePageMixin, Page):
     We need to alter the page model's context to return the child page objects - the
     BlogPage - so that it works as an index page
 
-    The RoutablePageMixin is used to allow for a custom sub-URL
+    RoutablePageMixin is used to allow for a custom sub-URL for tag views.
     """
+
     image = models.ForeignKey(
         'wagtailimages.Image',
         null=True,
@@ -145,12 +143,7 @@ class BlogIndexPage(RoutablePageMixin, Page):
         FieldPanel('introduction')
     ]
 
-    # parent_page_types = [
-    #     'home.HomePage'
-    # ]
-
-    # Defining what content type can sit under the parent. Since it's a blank
-    # array no subpage can be added
+    # What pages types can live under this page type?
     subpage_types = ['BlogPage']
 
     def get_context(self, request):
@@ -168,6 +161,7 @@ class BlogIndexPage(RoutablePageMixin, Page):
         return all related BlogPages for a given Tag or redirect back to
         the BlogIndexPage
         """
+
         try:
             tag = Tag.objects.get(slug=tag)
         except Tag.DoesNotExist:
@@ -179,9 +173,7 @@ class BlogIndexPage(RoutablePageMixin, Page):
         blogs = BlogPage.objects.filter(tags=tag).live().descendant_of(self)
 
         context = {
-            'title': 'Posts tagged with: {}'.format(tag.name),
+            'tag': tag,
             'blogs': blogs
         }
         return render(request, 'blog/blog_index_page.html', context)
-
-    # api_fields = ['introduction']

+ 27 - 0
bakerydemo/breads/migrations/0002_auto_20170217_0853.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-02-17 08:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('wagtailimages', '0018_remove_rendition_filter'),
+        ('breads', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='breadsindexpage',
+            name='image',
+            field=models.ForeignKey(blank=True, help_text='Location listing image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image'),
+        ),
+        migrations.AddField(
+            model_name='breadsindexpage',
+            name='introduction',
+            field=models.TextField(blank=True, help_text='Text to describe the index page'),
+        ),
+    ]

+ 17 - 2
bakerydemo/breads/models.py

@@ -11,7 +11,6 @@ from wagtail.wagtailsnippets.models import register_snippet
 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 
 
-
 @register_snippet
 class Country(models.Model):
     """
@@ -103,8 +102,24 @@ class BreadsIndexPage(Page):
     BreadPage - so that it works as an index page
     """
 
+    introduction = models.TextField(
+        help_text='Text to describe the index page',
+        blank=True)
+    image = models.ForeignKey(
+        'wagtailimages.Image',
+        null=True,
+        blank=True,
+        on_delete=models.SET_NULL,
+        related_name='+',
+        help_text='Location listing image'
+    )
     subpage_types = ['BreadPage']
 
+    content_panels = Page.content_panels + [
+        FieldPanel('introduction'),
+        ImageChooserPanel('image'),
+    ]
+
     def get_context(self, request):
         context = super(BreadsIndexPage, self).get_context(request)
 
@@ -112,7 +127,7 @@ class BreadsIndexPage(Page):
         # replace this with your own query as appropriate
         all_resources = self.get_children().live()
 
-        paginator = Paginator(all_resources, 5) # Show 5 resources per page
+        paginator = Paginator(all_resources, 5)  # Show 5 resources per page
 
         page = request.GET.get('page')
         try:

+ 21 - 0
bakerydemo/locations/migrations/0003_auto_20170215_0723.py

@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-02-15 07:23
+from __future__ import unicode_literals
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('locations', '0002_auto_20170211_2229'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='locationpage',
+            name='lat_long',
+            field=models.CharField(help_text="Comma separated lat/long. (Ex. 64.144367, -21.939182)                    Right click Google Maps and select 'What's Here'", max_length=36, validators=[django.core.validators.RegexValidator(code='invalid_lat_long', message='Lat Long must be a comma-separated numeric lat and long', regex='^(\\-?\\d+(\\.\\d+)?),\\s*(\\-?\\d+(\\.\\d+)?)$')]),
+        ),
+    ]

+ 22 - 0
bakerydemo/locations/migrations/0004_locationsindexpage_image.py

@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-02-17 08:20
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('wagtailimages', '0018_remove_rendition_filter'),
+        ('locations', '0003_auto_20170215_0723'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='locationsindexpage',
+            name='image',
+            field=models.ForeignKey(blank=True, help_text='Location listing image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image'),
+        ),
+    ]

+ 20 - 0
bakerydemo/locations/migrations/0005_locationsindexpage_introduction.py

@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-02-17 08:24
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('locations', '0004_locationsindexpage_image'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='locationsindexpage',
+            name='introduction',
+            field=models.TextField(blank=True, help_text='Text to describe the index page'),
+        ),
+    ]

+ 16 - 0
bakerydemo/locations/migrations/0008_merge_20170218_0921.py

@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-02-18 09:21
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('locations', '0007_auto_20170215_1411'),
+        ('locations', '0005_locationsindexpage_introduction'),
+    ]
+
+    operations = [
+    ]

+ 17 - 1
bakerydemo/locations/models.py

@@ -85,13 +85,29 @@ class LocationsIndexPage(Page):
     Index page for locations
     """
 
+    introduction = models.TextField(
+        help_text='Text to describe the index page',
+        blank=True)
+    image = models.ForeignKey(
+        'wagtailimages.Image',
+        null=True,
+        blank=True,
+        on_delete=models.SET_NULL,
+        related_name='+',
+        help_text='Location listing image'
+    )
     subpage_types = ['LocationPage']
 
+    content_panels = Page.content_panels + [
+        FieldPanel('introduction'),
+        ImageChooserPanel('image'),
+    ]
+
     def get_context(self, request):
         context = super(LocationsIndexPage, self).get_context(request)
         context['locations'] = LocationPage.objects.descendant_of(
             self).live().order_by(
-            '-first_published_at')
+            'title')
         return context
 
 

+ 0 - 1
bakerydemo/settings/__init__.py

@@ -1 +0,0 @@
-from .dev import *

+ 2 - 2
bakerydemo/settings/base.py

@@ -51,7 +51,7 @@ INSTALLED_APPS = [
     'wagtail.contrib.modeladmin',
     'wagtail.wagtailcore',
     'wagtail.contrib.wagtailapi',
-    
+
     'rest_framework',
     'modelcluster',
     'taggit',
@@ -106,7 +106,7 @@ WSGI_APPLICATION = 'bakerydemo.wsgi.application'
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': 'bakerydemodb',
+        'NAME': os.path.join(BASE_DIR, 'bakerydemodb')
     }
 }
 

+ 0 - 5
bakerydemo/settings/dev.py

@@ -6,8 +6,3 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 
 # BASE_URL required for notification emails
 BASE_URL = 'http://localhost:8000'
-
-try:
-    from .local import *
-except ImportError:
-    pass

+ 0 - 2
bakerydemo/settings/heroku.py

@@ -3,8 +3,6 @@ import dj_database_url
 from .base import *
 
 
-DEBUG = True
-
 # Accept all hostnames, since we don't know in advance which hostname will be used for any given Heroku instance.
 # IMPORTANT: Set this to a real hostname when using this in production!
 # See https://docs.djangoproject.com/en/1.10/ref/settings/#allowed-hosts

+ 3 - 0
bakerydemo/settings/local.py.example

@@ -0,0 +1,3 @@
+from bakerydemo.settings.dev import *   # noqa
+
+# Override settings here

+ 10 - 0
bakerydemo/static/css/main.css

@@ -75,6 +75,15 @@ a.btn:hover {
   color: white;
 }
 
+a.btn-sm {
+    padding: 6px 8px;
+    font-size: 10px;
+    line-height: normal;
+    -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+            border-radius: 4px;
+    }
+
 input {
   border-radius: 3px;
   border: none;
@@ -571,3 +580,4 @@ time.location-time {
   padding-right: 0;
   padding-left: 0;
 }
+

+ 20 - 7
bakerydemo/templates/base/gallery_page.html

@@ -2,14 +2,27 @@
 {% load wagtailimages_tags gallery_tags %}
 
 {% block content-header %}
-    {{ page.title }}
-
-    <div class="image">
-        {% image page.image width-500 as photo %}
-              <img src="{{ photo.url }}" width="{{ photo.width }}" height="{{ photo.height }}" alt="{{ photo.alt }}" />
+{% image self.image fill-1920x600 as hero_img %}
+<div class="container-fluid hero" style="background-image:url('{{ hero_img.url }}')">
+<div class="hero-gradient-mask"></div>
+    <div class="container">
+        <div class="row">
+            <div class="col-md-7 col-md-offset-2">
+                <h1>{{ page.title }}</h1>
+                <p class="stand-first">{{ page.subtitle }}</p>
+            </div>
+        </div>
     </div>
+</div>
 {% endblock content-header %}
 
 {% block content-body %}
-    {% gallery page.choices %}
-{% endblock content %}
+<div class="container">
+    <div class="row">
+        <div class="col-xs-12">
+            {{ page.introduction }}
+            {% gallery page.choices %}
+        </div>
+    </div>
+</div>
+{% endblock content-body %}

+ 1 - 6
bakerydemo/templates/base/home_page.html

@@ -2,12 +2,7 @@
 {% load wagtailimages_tags %}
 
 {% block content-header %}
-    {{ page.title }}
-
-    <div class="image">
-        {% image page.image width-500 as photo %}
-        <img src="{{ photo.url }}" width="{{ photo.width }}" height="{{ photo.height }}" alt="{{ photo.alt }}" />
-    </div>
+    {% include "base/include/header.html" %}
 {% endblock content-header %}
 
 {% block content-body %}

+ 0 - 1
bakerydemo/templates/base/include/footer.html

@@ -1,4 +1,3 @@
 {% load wagtailcore_tags %}
 
-
 {{ footer_text|richtext }}

+ 16 - 0
bakerydemo/templates/base/include/header.html

@@ -0,0 +1,16 @@
+{% load wagtailcore_tags %}
+{% load wagtailimages_tags %}
+
+<div class="container">
+
+    <div class="image">
+        {% image page.image width-500 as photo %}
+        <img src="{{ photo.url }}" width="{{ photo.width }}" height="{{ photo.height }}" alt="{{ photo.alt }}" />
+    </div>
+
+    <div class="row">
+        <div class="col-md-7 col-md-offset-2">
+            <h2>{{ page.title }}</h2>
+        </div>
+    </div>
+</div>

+ 14 - 21
bakerydemo/templates/blog/blog_index_page.html

@@ -2,30 +2,23 @@
 {% load wagtailimages_tags %}
 
 {% block content-header %}
-<div class="container">
-    <div class="row">
-        <div class="col-md-7 col-md-offset-2">
-            {{ page.title }}
-        </div>
-    </div>
-</div>
+    {% include "base/include/header.html" %}
 {% endblock content-header %}
 
 {% block content-body %}
-<div class="container">
-    <div class="row">
-        <div class="col-md-7 col-md-offset-2">
-            {% for blog in blogs %}
-                <div>
-                    <h2><a href="{{ blog.url }}">{{ blog.title }}</a></h2>
-                    {{ blog.body|truncatewords_html:10 }}
-
-                    {% for tag in blog.get_tags  %}
-                        <a href="{{ tag.url }}">{{ tag }}</a>
-                    {% endfor %}
-                </div>
-            {% endfor %}
+    <div class="container">
+        <div class="row">
+            <div class="col-md-7 col-md-offset-2">
+                {% if tag %}
+                    <h3>Posts tagged with "{{ tag }}":</h3>
+                {% endif %}
+                {% for blog in blogs %}
+                    <div>
+                        <h2><a href="{{ blog.url }}">{{ blog.title }}</a></h2>
+                        {{ blog.body|truncatewords_html:10 }}
+                    </div>
+                {% endfor %}
+            </div>
         </div>
     </div>
-</div>
 {% endblock content-body %}

+ 6 - 3
bakerydemo/templates/blog/blog_page.html

@@ -26,9 +26,12 @@
 
             {{ page.body }}
 
-            {% for tag in page.get_tags  %}
-                <a href="{{ tag.url }}">{{ tag }}</a>
-            {% endfor %}
+            {% if page.get_tags %}
+                Tagged with:<br />
+                {% for tag in page.get_tags  %}
+                    <a href="{{ tag.url }}" class="btn btn-sm">{{ tag }}</a>
+                {% endfor %}
+            {% endif %}
         </div>
     </div>
 </div>

+ 13 - 9
bakerydemo/templates/breads/breads_index_page.html

@@ -2,17 +2,21 @@
 {% load wagtailimages_tags %}
 
 {% block content-header %}
-    {{ page.title }}
-    {% for bread in resources %}
-		<div>
-			<div class="col-xs-12">
-				<div><a href="{{ bread.slug }}">{{ bread.title }}</a></div>
-			</div>
-		</div>
-	{% endfor %}
-{% block content-header %}
+    {% include "base/include/header.html" %}
+{% endblock content-header %}
 
 {% block content-body %}
+
+    <p>{{ page.introduction}}</p>
+
+    {% for bread in resources %}
+        <div>
+            <div class="col-xs-12">
+                <div><a href="{{ bread.slug }}">{{ bread.title }}</a></div>
+            </div>
+        </div>
+    {% endfor %}
+
 	{% if resources.has_other_pages %}
 	<div class="clearfix">
 	  <div class="pagination-wrapper">

+ 2 - 1
bakerydemo/templates/locations/locations_index_page.html

@@ -6,6 +6,7 @@
     <div class="row">
         <div class="col-md-12">
             <h1>{{ page.title }}</h1>
+            <p>{{ page.introduction }}</p>
         </div>
     </div>
 </div>
@@ -32,4 +33,4 @@
         {% endfor %}
     </div>
 </div>
-{% endblock content-body %}
+{% endblock content-body %}

+ 9 - 2
bakerydemo/templates/tags/gallery.html

@@ -1,7 +1,14 @@
 {% load wagtailimages_tags %}
 
 {% for img in images %}
-{% image img max-285x200 as img_obj %}
-<div class="col-sm-6"><img src="{{img_obj.url}}" class="img-responsive" /></div>
+{% image img fill-285x200-c100 as img_obj %}
+<div class="col-sm-6">
+	<a href="">
+		<figure class="gallery-figure">
+			<img src="{{img_obj.url}}" class="img-responsive" />
+			<figcaption>{{ img.title }}</figcaption>
+		</figure>
+	</a>
+</div>
 {{ image.title }}
 {% endfor %}

+ 7 - 1
bakerydemo/wsgi.py

@@ -8,7 +8,13 @@ https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
 """
 
 import os
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bakerydemo.settings")
 
+import dotenv
 from django.core.wsgi import get_wsgi_application
+
+
+dotenv.read_dotenv(os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env'))
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bakerydemo.settings.dev")
+
 application = get_wsgi_application()

+ 5 - 0
manage.py

@@ -2,7 +2,12 @@
 import os
 import sys
 
+import dotenv
+
+
 if __name__ == "__main__":
+    dotenv.read_dotenv()
+
     os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bakerydemo.settings")
 
     from django.core.management import execute_from_command_line

+ 60 - 1
readme.md

@@ -51,7 +51,16 @@ With PIP installed run the following commands:
 
     git clone git@github.com:wagtail/bakerydemo.git
     cd wagtaildemo
-    pip install -r requirements/base.txt
+    pip install -r requirements.txt
+
+Next, we'll set up our local environment variables. We use [django-dotenv](https://github.com/jpadilla/django-dotenv)
+to help with this. It reads environment variables located in a file name .env in the top level directory of the project. The only variable we need to start is `DJANGO_SETTINGS_MODULE`:
+
+    $ cp bakerydemo/settings/local.py.example bakerydemo/settings/local.py
+    $ echo "DJANGO_SETTINGS_MODULE=bakerydemo.settings.local" > .env
+
+Execute the following commands:
+
     ./manage.py migrate
     ./manage.py load_initial_data
     ./manage.py runserver
@@ -82,6 +91,56 @@ Log into the admin with the credentials ``admin / changeme``.
 
 To learn more about Heroku, read [Deploying Python and Django Apps on Heroku](https://devcenter.heroku.com/articles/deploying-python).
 
+### Storing Wagtail Media Files on AWS S3
+
+If you have deployed the demo site to Heroku, you may want to perform some additional setup.  Heroku uses an
+[ephemeral filesystem](https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem).  In laymen's terms, this means
+that uploaded images will disappear at a minimum of once per day, and on each application deployment.  To mitigate this,
+you can host your media on S3.
+
+This documentation assumes that you have an AWS account, an IAM user, and a properly configured S3 bucket. These topics
+are outside of the scope of this documentation; the following [blog post](https://wagtail.io/blog/amazon-s3-for-media-files/)
+will walk you through those steps.
+
+Next, you will need to add `django-storages` and `boto3` to `requirements/heroku.txt`.
+
+Then you will need to edit `settings/heroku.py`:
+
+    INSTALLED_APPS.append('storages')
+
+You will also need to add the S3 bucket and access credentials for the IAM user that you created.
+
+    AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME', 'changeme')
+    AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID', 'changeme')
+    AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY', 'changeme')
+    AWS_S3_CUSTOM_DOMAIN = '{}.s3.amazonaws.com'.format(AWS_STORAGE_BUCKET_NAME)
+
+Next, you will need to set these values in the Heroku environment.  The next steps assume that you have
+the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) installed and configured. You will
+execute the following commands to set the aforementioned environment variables:
+
+    heroku config:set AWS_STORAGE_BUCKET_NAME=changeme
+    heroku config:set AWS_ACCESS_KEY_ID=changeme
+    heroku config:set AWS_SECRET_ACCESS_KEY=changeme
+
+Do not forget to replace the `changeme` with the actual values for your AWS account.
+
+Finally, we need to configure the `MEDIA_URL` as well as inform Django that we want to use `boto3` for the storage
+backend:
+
+    MEDIA_URL = 'https://{}/'.format(AWS_S3_CUSTOM_DOMAIN)'
+    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
+
+Commit these changes and push to Heroku and you should now have persistent media storage!
+
+### Sending email from the contact form
+
+The following setting in `base.py` and `heroku.py` ensures that live email is not sent by the demo contact form.
+
+`EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'`
 
+In production on your own site, you'll need to change this to:
 
+`EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'`
 
+and configure [SMTP settings](https://docs.djangoproject.com/en/1.10/topics/email/#smtp-backend) appropriate for your email provider.

+ 8 - 5
requirements/base.txt

@@ -1,5 +1,8 @@
-Django
-elasticsearch
-wagtail
-wagtailfontawesome
-Pillow
+Django==1.10.5
+django-dotenv==1.4.1
+# http://docs.wagtail.io/en/v1.8.1/topics/search/backends.html#elasticsearch-backend
+# Not utilized by default; uncomment and review the above document if you require elasticsearch
+# elasticsearch==5.1.0
+wagtail==1.9
+wagtailfontawesome==1.0.6
+Pillow==4.0.0

+ 4 - 4
requirements/heroku.txt

@@ -1,6 +1,6 @@
 -r base.txt
 # Additional dependencies for Heroku deployment
-dj-database-url
-gunicorn
-psycopg2
-whitenoise
+dj-database-url==0.4.1
+gunicorn==19.6.0
+psycopg2==2.6.2
+whitenoise==3.2.2

+ 5 - 6
vagrant/provision.sh

@@ -9,10 +9,6 @@ PYTHON=$VIRTUALENV_DIR/bin/python
 PIP=$VIRTUALENV_DIR/bin/pip
 
 
-# Create database
-su - vagrant -c "createdb $PROJECT_NAME"
-
-
 # Virtualenv setup for project
 su - vagrant -c "virtualenv --python=python3 $VIRTUALENV_DIR"
 # Replace previous line with this if you are using Python 2
@@ -31,6 +27,10 @@ su - vagrant -c "$PIP install -r $PROJECT_DIR/requirements/base.txt"
 # Set execute permissions on manage.py as they get lost if we build from a zip file
 chmod a+x $PROJECT_DIR/manage.py
 
+# copy local settings file
+cp $PROJECT_DIR/bakerydemo/settings/local.py.example $PROJECT_DIR/bakerydemo/settings/local.py
+# add .env file for django-dotenv environment variable definitions
+echo DJANGO_SETTINGS_MODULE=$PROJECT_NAME.settings.local > $PROJECT_DIR/.env
 
 # Run syncdb/migrate/load_initial_data/update_index
 su - vagrant -c "$PYTHON $PROJECT_DIR/manage.py migrate --noinput && \
@@ -41,9 +41,8 @@ su - vagrant -c "$PYTHON $PROJECT_DIR/manage.py migrate --noinput && \
 # Add a couple of aliases to manage.py into .bashrc
 cat << EOF >> /home/vagrant/.bashrc
 export PYTHONPATH=$PROJECT_DIR
-export DJANGO_SETTINGS_MODULE=$PROJECT_NAME.settings.dev
 
-alias dj="django-admin.py"
+alias dj="./manage.py"
 alias djrun="dj runserver 0.0.0.0:8000"
 
 source $VIRTUALENV_DIR/bin/activate