Skip to content

Instantly share code, notes, and snippets.

@diegosorrilha
Last active December 28, 2016 22:18
Show Gist options
  • Save diegosorrilha/a85cc0a6c47d8d248c8f6199fc233872 to your computer and use it in GitHub Desktop.
Save diegosorrilha/a85cc0a6c47d8d248c8f6199fc233872 to your computer and use it in GitHub Desktop.
Script that creates a basic Django project with a simple home page, 3 tests and settings using python-decouple.
# Shell script to create a basics Django project.
# This script require Python 3.x and pyenv
# This script was based in gist of @rg3915 => https://gist.github.com/rg3915/a264d0ade860d2f2b4bf
# The project contains:
# Settings config to Django 1.10
# Admin config
# Tests in view home
# Download:
# curl https://gist.githubusercontent.com/diegosorrilha/a85cc0a6c47d8d248c8f6199fc233872/raw/6d1996f07d041010960db735e6da83fedf8c934e/django-start.sh -o django-start.sh
# Usage:
# source django-start.sh myproject
# Colors
red=`tput setaf 1`
green=`tput setaf 2`
yellow=`tput setaf 3`
reset=`tput sgr0`
echo "${green}>>> Deactivating the virtualenv${reset}"
deactivate
PROJECT=${1-myproject}
echo "${green}>>> The name of the project is ${yellow}'$PROJECT'${reset}"
echo "${green}>>> Remove djangoproject${reset}"
rm -rf djangoproject
echo "${green}>>> Creating djangoproject${reset}"
mkdir djangoproject
cd djangoproject
echo "${green}>>> Creating virtualenv${reset}"
python -m venv .venv
echo "${green}>>> .venv is created${reset}"
# active
sleep 2
echo "${green}>>> activate the .venv${reset}"
source .venv/bin/activate
PS1="(`basename \"$VIRTUAL_ENV\"`)\e[1;34m:/\W\e[00m$ "
sleep 2
# install Django
echo "${green}>>> Installing the Django and all dependencies${reset}"
pip install -U pip
cat << EOF > requirements-base.txt
dj-database-url==0.4.1
dj-static==0.0.6
Django==1.10
python-decouple==3.0
static3==0.7.0
django-extensions==1.7.4
django-test-without-migrations==0.4
pytz
EOF
cat << EOF > requirements.txt
-r requirements-base.txt
gunicorn==19.4.1
psycopg2==2.6.1
EOF
cat << EOF > requirements-dev.txt
-r requirements-base.txt
ipython[notebook]
EOF
pip install -r requirements-dev.txt
# Create contrib/env-sample
echo "${green}>>> Creating the contrib/env-sample${reset}"
mkdir contrib
cat << EOF > contrib/env-sample
SECRET_KEY=THIS_IS_NOT_A_GOOD_SECRET
DEBUG=True
ALLOWED_HOSTS=127.0.0.1, .localhost, .herokuapp.com
EOF
echo "${green}>>> Copy env-sample to .env${reset}"
cp contrib/env-sample .env
echo "${green}>>> Creating the contrib/secret_gen.py${reset}"
cat << EOF > contrib/secret_gen.py
#!/usr/bin/env python
"""
Django SECRET_KEY generator.
"""
from django.utils.crypto import get_random_string
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
print(get_random_string(50, chars))
EOF
echo "${green}>>> Creating .gitignore${reset}"
cat << EOF > .gitignore
__pycache__/
*.py[cod]
*.sqlite3
*.env
.idea
*.DS_Store
.venv/
staticfiles/
.ipynb_checkpoints/
EOF
# Create the project
echo "${green}>>> Creating the project '$PROJECT' ...${reset}"
django-admin.py startproject $PROJECT .
cd $PROJECT
echo "${green}>>> Creating the app 'core' ...${reset}"
python ../manage.py startapp core
echo "${green}>>> Creating tests directory${reset}"
mkdir core/tests
touch core/tests/__init__.py
rm -f core/tests.py
cat << EOF > test_view_home.py
from django.test import TestCase
class HomeTest(TestCase):
def setUp(self):
self.response = self.client.get('/')
def test_get(self):
"""GET / must return status code 200"""
self.assertEqual(200, self.response.status_code)
def test_template(self):
"""Must use index.html"""
self.assertTemplateUsed(self.response, 'index.html')
def test_admin_link(self):
"""Must contains link to admin"""
self.assertContains(self.response, 'href="/admin/"')
EOF
echo "${green}>>> Creating static/css directory${reset}"
mkdir -p core/static/css
echo "${green}>>> Creating main.css${reset}"
cat << EOF > core/static/css/main.css
/* Sticky footer styles
-------------------------------------------------- */
/* http://getbootstrap.com/examples/sticky-footer-navbar/sticky-footer-navbar.css */
/* http://getbootstrap.com/2.3.2/examples/sticky-footer.html */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
#footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
background-color: #101010;
color: #ccc;
}
.credit {
/* Center vertical text */
margin: 20px 0;
}
/* Lastly, apply responsive CSS fixes as necessary */
@media (max-width: 767px) {
body {
margin-bottom: 120px;
}
#footer {
height: 120px;
padding-left: 5px;
padding-right: 5px;
}
}
/* My personal styles. */
.ok {
color: #44AD41; /*verde*/
}
.no {
color: #DE2121; /*vermelho*/
}
EOF
echo "${green}>>> Creating social.css${reset}"
cat << EOF > core/static/css/social.css
/* http://www.kodingmadesimple.com/2014/11/create-stylish-bootstrap-3-social-media-icons.html */
.social {
margin: 0;
padding: 0;
}
.social ul {
margin: 0;
padding: 5px;
}
.social ul li {
margin: 5px;
list-style: none outside none;
display: inline-block;
}
.social i {
width: 40px;
height: 40px;
color: #FFF;
background-color: #909AA0;
font-size: 22px;
text-align:center;
padding-top: 12px;
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
-o-border-radius: 50%;
transition: all ease 0.3s;
-moz-transition: all ease 0.3s;
-webkit-transition: all ease 0.3s;
-o-transition: all ease 0.3s;
-ms-transition: all ease 0.3s;
text-decoration: none;
}
.social .fa-facebook {
background: #4060A5;
}
.social .fa-twitter {
background: #00ABE3;
}
.social .fa-google-plus {
background: #e64522;
}
.social .fa-github {
background: #343434;
}
.social .fa-pinterest {
background: #cb2027;
}
.social .fa-linkedin {
background: #0094BC;
}
.social .fa-flickr {
background: #FF57AE;
}
.social .fa-instagram {
background: #375989;
}
.social .fa-vimeo-square {
background: #83DAEB;
}
.social .fa-stack-overflow {
background: #FEA501;
}
.social .fa-dropbox {
background: #017FE5;
}
.social .fa-tumblr {
background: #3a5876;
}
.social .fa-dribbble {
background: #F46899;
}
.social .fa-skype {
background: #00C6FF;
}
.social .fa-stack-exchange {
background: #4D86C9;
}
.social .fa-youtube {
background: #FF1F25;
}
.social .fa-xing {
background: #005C5E;
}
.social .fa-rss {
background: #e88845;
}
.social .fa-foursquare {
background: #09B9E0;
}
.social .fa-youtube-play {
background: #DF192A;
}
.social .fa-slack {
background: #4F3A4B;
}
.social .fa-whatsapp {
background: #65BC54;
}
.socialfooter {
margin: 0;
padding: 0;
}
.socialfooter ul {
margin: 0;
padding: 5px;
}
.socialfooter ul li {
margin: 5px;
list-style: none outside none;
display: inline-block;
}
.socialfooter i {
color: #FFF;
font-size: 22px;
text-align:center;
padding-top: 12px;
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
-o-border-radius: 50%;
transition: all ease 0.3s;
-moz-transition: all ease 0.3s;
-webkit-transition: all ease 0.3s;
-o-transition: all ease 0.3s;
-ms-transition: all ease 0.3s;
text-decoration: none;
}
.socialfooter i:hover {
color: #00ABE3;
}
EOF
echo "${green}>>> Creating templates directory${reset}"
mkdir -p core/templates/core
echo "${green}>>> Creating base.html${reset}"
cat << EOF > core/templates/base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="Django boilerplate">
<meta name="author" content="rg3915">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="shortcut icon" href="https://www.djangoproject.com/favicon.ico">
<title>
{% block title %}$PROJECT{% endblock title %}
</title>
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" href="{% static "css/main.css" %}">
<link rel="stylesheet" href="{% static "css/social.css" %}">
<!-- Bootstrap JS -->
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<style type="text/css">
body {
padding-top: 50px;
/*color: #5a5a5a;*/
}
</style>
</head>
<body>
{% include "nav.html" %}
<div id="wrap">
<div class="container">
{% block content %}{% endblock content %}
</div>
</div>
{% include "footer.html" %}
</body>
</html>
EOF
echo "${green}>>> Creating index.html${reset}"
cat << EOF > core/templates/index.html
{% extends "base.html" %}
{% block content %}
<div class="jumbotron">
<img src="http://imagens.tiespecialistas.com.br/2016/02/django-allauth.png" class="img-responsive" alt="Responsive image">
</div>
{% endblock content %}
EOF
echo "${green}>>> Creating nav.html${reset}"
cat << EOF > core/templates/nav.html
<!-- Menu -->
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="current"><a href="#"><span class="glyphicon glyphicon-home"></span> Home</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'admin:index' %}"><span class="fa fa-cog"></span> Admin</a></li>
</ul>
</div>
</div>
</div>
EOF
echo "${green}>>> Creating footer.html${reset}"
cat << EOF > core/templates/footer.html
<div id="footer">
<div class="container">
<div class="socialfooter pull-center">
<ul>
<li><a href="#"><i class="fa fa-facebook"></i></a></li>
<li><a href="#"><i class="fa fa-twitter"></i></a></li>
<li><a href="#"><i class="fa fa-google-plus"></i></a></li>
<li><a href="#"><i class="fa fa-github"></i></a></li>
<li><a href="#"><i class="fa fa-pinterest"></i></a></li>
<li><a href="#"><i class="fa fa-linkedin"></i></a></li>
<li><a href="#"><i class="fa fa-instagram"></i></a></li>
<li><a href="#"><i class="fa fa-skype"></i></a></li>
<li><a href="#"><i class="fa fa-slack"></i></a></li>
</ul>
</div>
</div>
</div>
EOF
# up one level
cd ..
# ********** EDITING FILES **********
echo "${green}>>> Refactor .env${reset}"
# find SECRET_KEY
grep "SECRET_KEY" $PROJECT/settings.py > .env
# replace =
sed -i "s/ = /=/g" .env
# replace '
sed -i "s/'//g" .env
cat << EOF >> .env
DEBUG=True
ALLOWED_HOSTS=127.0.0.1, .localhost, .herokuapp.com
EOF
echo "${green}>>> Editing settings.py${reset}"
# insert text in line below of string
cat << EOF > $PROJECT/settings.py
"""
Django settings for $PROJECT project.
Generated by 'django-admin startproject' using Django 1.10.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from decouple import config, Csv
from dj_database_url import parse as dburl
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
SECRET_KEY = config('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
#DEBUG = True
DEBUG=config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())
DEFAULT_FROM_EMAIL = 'you@mail.com'
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'test_without_migrations',
'django_extensions',
'$PROJECT.core',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)
ROOT_URLCONF = '$PROJECT.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = '$PROJECT.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
default_dburl = 'sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3')
DATABASES = {
'default': config('DATABASE_URL', default=default_dburl, cast=dburl),
}
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
EOF
echo "${green}>>> Editing wsgi.py${reset}"
# insert text in line below of string
cat << EOF > $PROJECT/wsgi.py
"""
WSGI config for $PROJECT project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
"""
import os
from dj_static import Cling
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "$PROJECT.settings")
application = Cling(get_wsgi_application())
EOF
echo "${green}>>> Editing urls.py${reset}"
cat << EOF > $PROJECT/urls.py
"""$PROJECT URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Add an import: from blog import urls as blog_urls
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
"""
from django.conf.urls import include, url
from django.contrib import admin
from $PROJECT.core.views import home
urlpatterns = [
url(r'^$', home),
url(r'^admin/', include(admin.site.urls)),
]
EOF
echo "${green}>>> Editing views.py${reset}"
cat << EOF > $PROJECT/core/views.py
from django.shortcuts import render
def home(request):
return render(request, 'index.html')
EOF
# migrate
python manage.py makemigrations
python manage.py migrate
echo "${green}>>> Running tests${reset}"
python manage.py test
clear
echo "${yellow}>>> Great! Django App created! :D ${reset}"
echo ""
echo -n "Create superuser? (y/N) "
read answer
if [ "$answer" == "y" ]; then
echo "${green}>>> Creating a 'admin' user ...${reset}"
echo "${green}>>> The password must contain at least 8 characters.${reset}"
echo "${green}>>> Password suggestions: demodemo${reset}"
python manage.py createsuperuser --username='admin' --email=''
fi
echo "${green}>>> Running tests again${reset}"
python manage.py test
echo "${green}>>> Creating the first commit${reset}"
git init
git add .
git commit -m "first commit"
sleep 2
clear
echo "${yellow}>>> Nice! $PROJECT created with superuser! :D${reset}"
echo ""
echo -n "Send project to heroku? (y/N)"
read answer
if [ "$answer" == "y" ]; then
curl https://gist.githubusercontent.com/diegosorrilha/68e2f411265c81e79ebc379a9ac26d49/raw/6b9c22779bbaf58a9de914ac78848f4701211e2b/django-start-deploy-heroku.sh -o ../django-start-deploy-heroku.sh
source ../django-start-deploy-heroku.sh $PROJECT
rm ../django-start-deploy-heroku.sh
else
clear
echo "${yellow}>>> OK! running $PROJECT in http://127.0.0.1:8000${reset}"
python manage.py runserver
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment