by a Django Noob
https://slides.com/marksteve/django-workshop
https://github.com/marksteve/django-workshop
I go by marksteve in the internet
I create sites and apps for a living and for fun
I'm a Django Noob
Let's get started then!
# Setup our virtualenv
python3 -m venv venv
# Activate it
source venv/bin/activate
# Install django
echo "django<1.8" > requirements.txt
pip install -r requirements.txt
# Check if installed
django-admin --version# Start a django project
django-admin startproject tindero .
# Try it out
python manage.py runserver
# Now go to http://localhost:8000
# It should look like this:# Perform initial db migrations
python manage.py migrate
# Check the db out
sqlite db.sqlite3
sqlite> .tables
# Create admin user
python manage.py createsuperuser
# Run the server and go to
# http://localhost:8000/admin/
# You should be able to log indjango-admin startproject PROJECT_NAME PROJECT_DIR
python manage.py runserver
python manage.py migrate
python manage.py createsuperuser
Most apps require some sort of user authentication and management. The user system bundled with Django is feature-filled and very flexible.
# Create an app for registration
python manage.py startapp registration# Create an app for registartion
python manage.py startapp registration
# Add the app to your INSTALLED_APPS
# tindero/settings.py
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'registration',
)
# Add auth urls
# tindero/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns(
'',
url(r'^', include('django.contrib.auth.urls')),
url(r'^admin/', include(admin.site.urls)),
)
# Create registration templates folder
mkdir -p registration/templates/registration
# Create login template
# registration/templates/registration/login.html
<!doctype html>
<html>
<body>
<form action="{% url "login" %}" method="post">
{% csrf_token %}
<h2>Login</h2>
{{ form.as_p }}
<p>
<button type="submit">
Login
</button>
</p>
</form>
</body>
</html>
# Run the server and try accessing
# http://localhost:8000/login/# Add register view
# registration/views.py
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
form = UserCreationForm()
context = dict(form=form)
return render(request, 'registration/register.html',
context)
# Create register template
# registration/templates/registration/register.html
<!doctype html>
<html>
<body>
<form action="{% url "register" %}" method="post">
{% csrf_token %}
<h2>Register</h2>
{{ form.as_p }}
<p>
<button type="submit">
Register
</button>
</p>
</form>
</body>
</html>
# Add URLconf for register view
# registration/urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns(
'',
url(r'^register/', views.register, name='register'),
)
# Include registration URLconf to project URLconf
# tindero/urls.py
urlpatterns = patterns(
'',
url(r'^', include('django.contrib.auth.urls')),
url(r'^', include('registration.urls')),
url(r'^admin/', include(admin.site.urls)),
)
python manage.py startapp APP_NAME
Project configuration lives in
settings.py
urls.py
views.py
# Create main app
python manage.py startapp app
# Add app to INSTALLED_APPS
# tindero/settings.py
INSTALLED_APPS = (
...
'app',
)
# Create user profile model
# app/models.py
from django.contrib.auth.models import User
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(User)
photo = models.ImageField(upload_to='photos')
bio = models.TextField()
def __unicode__(self):
return self.user.get_full_name()
# Add upload settings
# tindero/settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
# Install Pillow
pip install pillow
# Make migrations
python manage.py makemigrations app
# Apply migrations
python manage.py migrate
# Hook models to admin
# app/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from . import models
class UserProfileInline(admin.StackedInline):
model = models.UserProfile
can_delete = False
verbose_name_plural = 'profile'
class UserAdmin(UserAdmin):
inlines = (UserProfileInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)# Hook models to admin
# app/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from . import models
class UserProfileInline(admin.StackedInline):
model = models.UserProfile
can_delete = False
verbose_name_plural = 'profile'
class UserAdmin(UserAdmin):
inlines = (UserProfileInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)# Create index view
# app/views.py
from django.contrib.auth.models import User
from django.shortcuts import render
def index(request):
context = dict(
tindero=User.objects.order_by('?')[0],
)
return render(request, 'index.html', context)
# Create app URLconf
# app/urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns(
'',
url(r'^$', views.index, name='index'),
)
# Add app and media root to project URLconf
# tindero/urls.py
from django.conf import settings
from django.conf.urls import include, patterns, url
from django.conf.urls.static import static
from django.contrib import admin
urlpatterns = patterns(
'',
url(r'^', include('django.contrib.auth.urls')),
url(r'^', include('registration.urls')),
url(r'^', include('app.urls')),
url(r'^admin/', include(admin.site.urls)),
) + static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
# Create index template
# app/templates/index.html
<!doctype html>
<html>
<body>
<div class="tindero">
<img src="{{ tindero.userprofile.photo.url }}">
<div class="name">
{{ tindero.username }}
</div>
<div class="bio">{{ tindero.userprofile.bio }}</div>
</div>
</body>
</html>
# Require login
# app/views.py
from django.contrib.auth.decorators import login_required
...
@login_required
def index(request):
...
# Set login urls
# tindero/settings.py
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'index'# Don't include logged in user
# app/views.py
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.shortcuts import render
@login_required
def index(request):
try:
tindero = (User.objects
.exclude(id=request.user.id)
.order_by('?')[0])
except IndexError:
tindero = None
context = dict(tindero=tindero)
return render(request, 'index.html', context)
# Update template
# app/templates/index.html
<!doctype html>
<html>
<body>
<div class="tindero">
{% if tindero %}
<img src="{{ tindero.userprofile.photo.url }}">
<div class="name">
{{ tindero.username }}
</div>
<div class="bio">{{ tindero.userprofile.bio }}</div>
{% else %}
Wait for more people to join!
{% endif %}
</div>
</body>
</html>
# Add UserVote model
# app/models.py
class UserVote(models.Model):
user = models.ForeignKey(User)
voter = models.ForeignKey(User, related_name='given_vote')
vote = models.BooleanField(default=False)
class Meta:
unique_together = (('user', 'voter'))
# Migrate
python manage.py makemigrations app
python manage.py migrate# Create voting views
# app/views.py
def create_vote(request, user_id, vote):
user = User.objects.get(pk=user_id)
models.UserVote.objects.create(
user=user,
voter=request.user,
vote=vote,
)
return redirect('index')
@login_required
def nice(request, user_id):
return create_vote(request, user_id, True)
@login_required
def nope(request, user_id):
return create_vote(request, user_id, False)
# NOTE: Don't forget to import redirect and models!
from django.shortcuts import redirect
from . import models
# Add urls for new views
# app/urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns(
'',
url(r'^$', views.index, name='index'),
url(r'^nice/(?P<user_id>\d+)$', views.nice, name='nice'),
url(r'^nope/(?P<user_id>\d+)$', views.nope, name='nope'),
)
# Add links to template
# app/templates/index.html
<div class="tindero">
{% if tindero %}
<img src="{{ tindero.userprofile.photo.url }}">
<div class="name">
{{ tindero.username }}
</div>
<div class="bio">{{ tindero.userprofile.bio }}</div>
<a href="{% url "nice" user_id=tindero.id %}">
Nice
</a>
<a href="{% url "nope" user_id=tindero.id %}">
Nope
</a>
{% else %}
Wait for more people to join!
{% endif %}
</div>
# Exclude users you already voted on
# app/views.py
tindero = (User.objects
.exclude(id=request.user.id)
.exclude(uservote__voter=request.user)
.order_by('?')[0])
# Create profile form
# apps/forms.py
from django.forms import ModelForm
from . import models
class UserProfileForm(ModelForm):
class Meta:
model = models.UserProfile
exclude = ('user',)
# Add profile view
# app/views.py
from . import forms
@login_required
def profile(request):
try:
profile = request.user.userprofile
except models.UserProfile.DoesNotExist:
profile = None
if request.method == 'POST':
form = forms.UserProfileForm(request.POST, request.FILES,
instance=profile)
if form.is_valid():
if profile:
form.save()
else:
profile = form.save(commit=False)
profile.user = request.user
profile.save()
form = forms.UserProfileForm(instance=profile)
context = dict(form=form)
return render(request, 'profile.html', context)# Add profile template
# app/templates/profile.html
<!doctype html>
<html>
<body>
<form action="{% url "profile" %}" method="post"
enctype="multipart/form-data">
{% csrf_token %}
<h2>Profile</h2>
{{ form.as_p }}
<p>
<button type="submit">
Save
</button>
</p>
</form>
</body>
</html>
# Add profile url
# app/urls.py
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns(
'',
url(r'^$', views.index, name='index'),
url(r'^nice/(?P<user_id>\d+)/$', views.nice, name='nice'),
url(r'^nope/(?P<user_id>\d+)/$', views.nope, name='nope'),
url(r'^profile/$', views.profile, name='profile'),
)
# Show matches
# app/views.py
def create_vote(request, user_id, vote):
user = User.objects.get(pk=user_id)
models.UserVote.objects.create(
user=user,
voter=request.user,
vote=vote,
)
if vote:
if models.UserVote.objects.filter(
user=request.user,
voter=user,
vote=True,
).count():
return render(request, 'match.html', dict(
match=user,
))
return redirect('index')
# Create match template
# app/templates/match.html
<!doctype html>
<html>
<body>
<h2>It's a match!</h2>
<p>
<img src="{{ request.user.userprofile.photo.url }}">
<img src="{{ match.userprofile.photo.url }}">
</p>
<p>You and {{ match.username }} like each other!</p>
<p><a href="{% url "index" %}">Play more!</a></p>
</body>
</html>
# Create a base template
# app/templates/base.html
{% load staticfiles %}
<!doctype html>
<html>
<head>
<title>Tindero</title>
<link
rel="stylesheet"
type="text/css"
href="{% static "css/main.css" %}">
</head>
<body>
<div class="page">
<div class="app">
<h1><a href="{% url "index" %}">Tindero</a></h1>
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>
# Update templates to extend base template
# registration/templates/registration/login.html
{% extends "base.html" %}
{% block content %}
<form action="{% url "login" %}" method="post">
{% csrf_token %}
<h2>Login</h2>
{{ form.as_p }}
<p>
<button type="submit">
Login
</button>
</p>
</form>
{% endblock %}