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_username
This 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/