HOME / BLOG / Django Basics
Intro
We will create a Demo Project with Django which uses a default base Template and integrate it with D3
📁 Create project folder
📁 Create project folder
mkdir 42-portfolio-demo cd 42-portfolio-demo
🌏 Create and load a virtual environment
This will create a Pipfile as well
sudo pipenv shell
pipenv install django
django-admin startproject portfolio_suite cd portfolio_suite
python manage.py startapp portfolio_app python manage.py migrate python manage.py runserver 3001
🏛️ Now let's define the Models, this is the Structure for our DataBase
portfolio_app/models.py
from django.db import models
class User(models.Model):
intr_username = models.CharField(max_length=30)
intra_id = models.IntegerField(unique=True, db_index=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.CharField(max_length=150)
bio = models.TextField(max_length=800)
updated_at = models.DateTimeField(auto_created=True, auto_now=True)
def _str_(self):
return "@" + self.intr_usernameThis will create a migration file where you can see all changes that will be done to the database.
python manage.py makemigrations portfolio_app
...
...
mistake on email field, should be EmailField
rm portfolio_app/migrations/0001_initial.py
The migrate command will make the database take effect upon the migrations on the migrations folder.
Change model to EmailField and make the migration
python manage.py makemigrations portfolio_app python manage.py migrate portfolio_app
Add your User to the Admin module
portfolio_app/admin.pyfrom django.contrib import admin from .models import User class UserAdmin(admin.ModelAdmin): fields = ['intra_id', 'intra_username', 'first_name', 'last_name', 'email'] list_display = ('intra_username', 'first_name', 'last_name', 'email', 'updated_at') admin.site.register(User, UserAdmin)
🔑 Create a SuperUser to access the Admin
python manage.py createsuperuser Username: test Password: test1234 Or whatever you want (never put test1234 as a password on production ofcs...)
python manage.py runserver 3001
portfolio_app/views.py
from django.shortcuts import render
from django.http import HttpResponse
def usersIndex(request):
return HttpResponse("Hello, world. You're at the users index.")portfolio_suite/urls.py
from django.contrib import admin
from django.urls import path
from portfolio_app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', views.usersIndex, name="usersIndex")
]
🦪 To explore a minimalistic inner structured shell for your application you can run:
python manage.py shell
from portfolio_app.models import User User.objects.all() User.objects.get(id=1) User.objects.get(intra_username="arosado")
🔗 Setting a urls module for the portfolio:
portfolio_app/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("users/", views.usersIndex, name="usersIndex"),
]portfolio_suite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path("", include("portfolio_app.urls")),
]Try again the routes make sure it works!
Add one more route:
portfolio_app/urls.py
...
path("users/<str:intra_username>", views.userShow, name="userShow"),That is a dynamic route, and you can access the value which will be a string input by the user on the url. Based on that value we will return the view with the username if it exists.
Add the method to the views:
Add the method to the views:
portfolio_app/views.py
from django.shortcuts import render, get_object_or_404
from .models import User
...
def userShow(request, intra_username):
return HttpResponse("Hello, world. You're at the user [%s] page." % intra_username)As you can see, you can access the parameter on the views.
run the server and visit: users/your_param
Templates
In order to recycle code we can build templates and develop contexts so we can contain the application under the same template.
♻️ This way we avoid having a bunch of html files with headers and repetitive stuff.
♻️ This way we avoid having a bunch of html files with headers and repetitive stuff.
mkdir -p mkdir portfolio_app/templates/users touch portfolio_app/templates/users/show.html
portfolio_app/views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .models import User
...
def userShow(request, intra_username):
user = get_object_or_404(User, intra_username=intra_username)
return render(request, "users/show.html", {"user": user})Beware, the parameters must be passed through a dictionary 📚
portfolio_app/templates/users/show.html
{% load static %}
<link rel="stylesheet" href="{% static 'users/style.css' %}">
USER: {{ user.first_name }}Now let's create that static cascade style sheet
mkdir -p portfolio_app/static/users touch portfolio_app/static/users/style.css touch portfolio_app/static/base.css
Now we need a base html template:
touch portfolio_app/templates/base.html
base.html
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'base.css' %}">
<title>{% block title %}42Portfolio{% endblock %}</title>
{% block custom_style_sheets %}{% endblock %}
</head>
<body>
<nav><h1>42 Portfolio</h1></nav>
<div id="content">
{% block content %}{% endblock %}
</div>
<footer>all rights reserved by 42 Lisboa</footer>
</body>
</html>portfolio_app/static/base.css
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
body {
width: 100vw;
min-height: 100vh;
margin: 0;
background: linear-gradient(-45deg, rgba(42, 42, 42, 0.1), rgba(42, 42, 42, 0.4), rgba(42, 42, 42, 0.3), rgba(42, 42, 42, 0.2));
background-size: 200% 200%;
animation: gradient 10s ease infinite;
font-family: 'Nova Mono', monospace;
}portfolio_app/static/users/style.css
b {
color: pink;
}portfolio/templates/users/show.html
{% extends "base.html" %}
{% block title %}{{ user.intra_username }}{% endblock %}
{% block custom_style_sheets %}
{% load static %}
<link rel="stylesheet" href="{% static 'users/style.css' %}">
{% endblock %}
{% block content %}
<h4>USER: <b>{{ user.first_name }}</b></h4>
{% endblock %}
Adding custom JavaScript
Add a block to your template's header:
(I also added the link to d3.min.js because I want to use it all over this template)
(I also added the link to d3.min.js because I want to use it all over this template)
portfolio_app/templates/base.html
<script src="https://d3js.org/d3.v7.min.js"></script>
{% block custom_javascripts %}{% endblock %}Now let's create a js file under the static folder
touch portfolio_app/static/users/portfolioCard.js
Load the custom js to the view where you want to use it:
portfolio_app/templates/users/show.html
{% block custom_javascripts %}
<script type="text/javascript" src="{% static 'users/portfolioCard.js' %}"></script>
{% endblock %}Great it works! But how can I for example, use the User model with JS!?
Well we can serialize the Object and the convert to JSON and deserialize in the JS ;)
So let's try to do that:
portfolio_app/views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .models import User
from django.core.serializers import serialize
from django.core.serializers.json import DjangoJSONEncoder
def usersIndex(request):
return HttpResponse("Hello, world. You're at the users index.")
def userShow(request, intra_username):
user = get_object_or_404(User, intra_username=intra_username)
serialized_user = serialize('json', [user], cls=DjangoJSONEncoder)
return render(request, "users/show.html", {"user": user, "serialized_user": serialized_user[1:-1]})portfolio_app/templates/users/show.html
...
{% block custom_javascripts %}
<script type="text/javascript" src="{% static 'users/portfolioCard.js' %}"
defer
data-user="{{ serialized_user }}">
</script>
{% endblock %}
...defer: to load after all the document was loaded completely and we pass the serialized user through a data-set
Now we can access the data-set and see the object:
portfolio_app/static/users/portfolioCarsd.js
const data = document.currentScript.dataset; const user = JSON.parse(data.user); console.log(user)
Let's add a nice svg! :)
portfolio_app/static/users/portfolioCarsd.js
const svgHeight = 300, svgWidth = 600;
const data = document.currentScript.dataset;
const user = JSON.parse(data.user);
// console.log(user)
window.addEventListener("load", () => {
d3.select( "#content" ).append( "svg" )
d3.selectAll( "svg" )
.attr( "width", svgWidth )
.attr( "height", svgHeight );
});Add some style to the base.css for the #content id
portfolio_app/static/base.css
body {
...
text-align: center;
}
#content {
display: flex;
align-items: center;
justify-items: center;
flex-flow: column;
gap: 1.5rem;
margin: 1rem auto;
padding-bottom: 1rem;
max-width: 800px;
background-image: url("https://i.pinimg.com/originals/70/72/c0/7072c003a01ab656c982542e9c38c475.jpg");
background-size: cover;
background-position: center;
}portfolio_app/static/users/style.css
h4 {
background-color: rgba(255, 255, 255, 0.8);
padding: 0.25rem;
border-radius: 0.25rem;
}
b {
color: pink;
}
svg {
margin: auto;
display: inline-block;
background-color: rgba(42, 42, 142, 0.9);
}Now have fun, you can do this to see some drag interactions on your svg, just to test the d3 library and how powerful it can be!!!
portfolio_app/static/users/style.css
const svgHeight = 300, svgWidth = 600;
const data = document.currentScript.dataset;
const user = JSON.parse(data.user);
// console.log(user)
const drawCircles2 = (svg, circles) => {
svg.selectAll( "circle" )
.data( circles ).enter().append( "circle" )
.attr( "r", d => d["r"] )
.attr( "cx", d => d["cx"] )
.attr( "cy", d => d["cy"] )
.attr( "fill", d => d["color"] );
}
window.addEventListener("load", () => {
const svg = d3.select( "#content" ).append( "svg" )
.attr( "id", "drag-drop")
d3.selectAll( "svg" )
.attr( "width", svgWidth )
.attr( "height", svgHeight );
let circles = [
{r: 20, color: "red", cx: 50, cy: 100},
{r: 20, color: "green", cx: 250, cy: 150},
{r: 20, color: "blue", cx: 350, cy: 100}
];
drawCircles2( svg, circles );
let color = undefined, widget = undefined;
svg.selectAll( "circle" )
.call( d3.drag()
.on( "start", function () {
color = d3.select( this ).attr( "fill" );
widget = d3.select( this ).attr( "fill", "lime" );
} )
.on( "drag", function () {
let pt = d3.pointer( event, this );
widget.attr( "cx", pt[0] ).attr( "cy", pt[1] )
} )
.on( "end", function () {
widget.attr( "fill", color );
widget = undefined;
color = undefined;
} )
);
});
Now we just need more data to actually create a nice visualization instead of this circles... You can use React for example and develop a REST API in Django!
Repo: https://github.com/pulgamecanica/42Portfolio-Demo/
Repo: https://github.com/pulgamecanica/42Portfolio-Demo/