all information in this README.md is courtesy of General Assembly/SEIR
-
Create a directory for our project: i.e.
my_project
-
cd
intomy_project
-
Install Django:
pipenv install django
-
Install library to connect Django to PostgreSQL:
pipenv install psycopg2-binary
-
Open
my_project
:code .
-
Start Django project:
pipenv run django-admin startproject my_project .
-
Activate virtual environment:
pipenv shell
-
Create app:
django-admin startapp myapp
NOTE: my_project
is the base django project where we will handle our routes. myapp
is where we write our models, controllers, and templates.
-
Login to psql:
psql -d postgres
-
Create a database:
> CREATE DATABASE somedb;
> CREATE USER myUser WITH PASSWORD 'user';
> GRANT ALL PRIVILEGES ON DATABASE somedb TO myuser;
> \q
- Add Database details:
# my_project/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'somedb',
'USER': 'myuser',
'PASSWORD': 'user',
'HOST': 'localhost'
}
}
- Add
myapp
to installed apps:
# my_project/settings.py
INSTALLED_APPS = [
'myapp'
]
-
Start server:
python3 manage.py runserver
-
Navigate to
localhost:8000
. (You should see a page welcoming you to Django!)
- Create desired models in
myapp/models.py
:
class Post(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
title = models.CharField(max_length=100, default='untitled')
def __str__(self):
return f"{self.post.name} - {self.title}"
- Stage migration to the database:
python3 manage.py makemigrations
NOTE: Every time you make changes to your models, run makemigrations
again.
- Migrate staged changes:
python3 manage.py migrate
-
Create a super user:
python3 manage.py createsuperuser
-
Fill in the info in the boxes that pop up.
-
Import models in
myapp/admin.py
:
from django.contrib import admin
from .models import Post, Comment
admin.site.register(Post, Comment)
- Import models in
myapp/views.py
:
from django.shortcuts import render
from .models import Post, Comment
- Create views:
# List View
def post_list(request):
posts = Post.objects.all()
return render(request, 'myapp/post_list.html', {'posts': posts})
# Show View
def post_detail(request, pk):
post = Post.objects.get(id=pk)
return render(request, 'myapp/post_detail.html', {'post': post})
- Import paths, include, and admin in
my_project/urls.py
:
from django.conf.urls import include
from django.urls import path
from django.contrib import admin
urlpatterns = [
path('admin', admin.site.urls),
path('', include('myapp.urls')),
]
- Create
myapp/urls.py
:
from django.urls import path
from . import views
urlpatterns = [
# List URL
path('', views.post_list, name='post_list'),
# Show URL
path('posts/<int:pk>', views.post_detail, name='post_detail'),
]
- In
myapp
create atemplates
directory with amyapp
subdirectory
-
In
templates
'smyapp
subdirectory create basebase.html
-
Add HTML5 boilerplate to
base.html
-
Build out
base.html
template:
<body>
<h1>MyApp</h1>
<nav>
<a href="{% url 'post_list' %}">Primaries</a>
</nav>
{% block content %} {% endblock %}
</body>
-
In
templates
'smyapp
subdirectory create basepost_list.html
-
Build out
post_list.html
template:
{% extends 'myapp/base.html' %}
{% block content %}
<h2>Primaries <a href="">(+)</a></h2>
<ul>
{% for post in posts %}
<li>
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.name }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
-
In
templates
'smyapp
subdirectory create basepost_detail.html
-
Build out
post_detail.html
template:
{% extends 'myapp/base.html' %}
{% block content %}
<h2>{{ post.name }} <a href="">(edit)</a></h2>
<h3>Secondaries <a href="">(+)</a></h3>
<ul>
{% for comment in post.comments.all %}
<li>
<a href="">{{ comment.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
- Create a
forms.py
file inmyapp
:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('name',)
- Add Form View:
# myapp/views.py
from django.shortcuts import render, redirect
from .forms import PostForm
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'myapp/post_form.html', {'form': form})
- Add Form URL:
# myapp/urls.py
path('post/new', views.post_create, name='post_create'),
- In
templates
'smyapp
subdirectory create basepost_form.html
- Build out
post_form.html
template:
{% extends 'myapp/base.html' %} {% block content %}
<h1>New Post</h1>
<form method="POST" class="post-form">
{% csrf_token %} {{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}
- Add Create Link to
post_list.html
:
<h2>Post <a href="{% url 'post_create' %}">(+)</a></h2>
- Add Edit View:
# myapp/views.py
def post_edit(request, pk):
post = Post.objects.get(pk=pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'myapp/post_form.html', {'form': form})
- Add Edit URL:
# myapp/urls.py
path('post/<int:pk>/edit', views.post_edit, name='post_edit'),
- Add Edit Link in Detail Template:
<!-- myapp/templates/myapp/post_detail.html -->
<h2>
{{ post.name }} <a href="{% url 'post_edit' pk=post.pk %}">(edit)</a>
</h2>
- Add Delete View
# myapp/views.py
def post_delete(request, pk):
Post.objects.get(id=pk).delete()
return redirect('post_list')
- Add Delete URL:
# myapp/urls.py
path('posts/<int:pk>/delete', views.post_delete, name='post_delete'),
-
In
myapp
create astatic
directory with acss
subdirectory -
In
static
'scss
subdirectory create basemyapp.css
-
Add static folder to
base.html
:
{% load staticfiles %}
<head>
<title>MyApp</title>
<link rel="stylesheet" href="{% static 'css/myapp.css' %}" />
</head>
-
Install the
djangorestframework
: pipenv install djangorestframework -
Add
'rest_framework',
to yourINSTALLED_APPS
list insettings.py
-
Add this variable as a new dictionary, anywhere in
settings.py
:
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
- In the
urls
list inmy_project/urls.py
, add the following tourlpatterns
:
path('api-auth', include('rest_framework.urls', namespace='rest_framework'))
Note: the HyperlinkedModelSerializer
allows you to link from one model to another.
- Create a new file in
myapp
calledserializers.py
:
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.HyperlinkedModelSerializer):
comment = serializers.HyperlinkedRelatedField(
view_name='comment_detail',
many=True,
read_only=True
)
- Add a Meta class inside the ArtistSerializer class:
class Meta:
model = Post
fields = ('id', 'photo_url', 'nationality', 'name', 'songs',)
from rest_framework import generics
from .serializers import PostSerializer
from .models import Post
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
from django.urls import path
from . import views
from rest_framework.routers import DefaultRouter
urlpatterns = [
path('posts', views.PostList.as_view(), name='post_list'),
path('posts/<int:pk>', views.PostDetail.as_view(), name='post_detail'),
]
class PostSerializer(serializers.HyperlinkedModelSerializer):
comments = serializers.HyperlinkedRelatedField(
view_name='comment_detail',
many=True,
read_only=True,
)
+ post_url = serializers.ModelSerializer.serializer_url_field(
+ view_name='post_detail'
+ )
class Meta:
model = Post
- fields = ('id', 'photo_url', 'nationality', 'name', 'songs',)
+ fields = ('id', 'artist_url', 'photo_url', 'nationality', 'name', 'songs',)