100 Days of Code - Day 19 - First Backend API project using Django
(set up on mac)
Like always with any new project create a new repository in GitHub
Choose the options:
Add read me
Add .gitignore (choose python)
Copy URL and clone it on the local machine.
Each project should have it's own virtual environment. This is because technologies like python (plus any other dependancies the project uses) may be updated over time, and we want to preserve those versions created at the time of build.
In the terminal of vs code, or in the same folder as your project in your machine's terminal, type the following command:
pipenv install
pipenv shell
To get the direct location of the project's local virtual environment is being stored.
pipenv --venv
Control + Shift + P in VS Code to get the Python Select Interpreter options, in drop down select 'enter new interpreter.' On a macintosh computer, copy the url, paste as the new path, and add a forward slash to the end + python3. -- /python3
Install Django
pipenv install django
Install mysql client - allows us to connect our django application to our locally running mysql server.
pipenv install mysql-connector-python==8.0.26
pipenv install djangorestframework
At this point, it would be a good idea to make a commit to the repository.
To see the available executables with django type the command below
django-admin
First command with django (with name of project) The space and dot put files generated in this folder open. ## THE SPACE AND DOT AFTER NAME OF PROJECT IS IMPORTANT!
django-admin startproject cars_project .
This generates a folder a files. For now, we only worry about settings.py and urls.py. settings.py - deals with all of our global settings for this django application. Urls.py - define our end points and what functions are executed when those end points are used.
Adding CORS to the backend
pipenv install django-cors-headers
Inside your back-end project settings.py:
i. Add ‘corsheaders’ to INSTALLED_APPS
ii. Add ‘corsheaders.middleware.CorsMiddleware’ to MIDDLEWARE
iii. Add new setting anywhere in settings.py file: CORS_ORIGIN_ALLOW_ALL=True
Connect application to the local mysql database.
In the settings.py, look for the section on DATABASES and change the connection string.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
(set up may be different on a pc)
DATABASES = {
'default': {
'ENGINE': 'mysql.connector.django',
'NAME': 'cars_database',
'USER': 'root',
'PASSWORD': 'Apple251#',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {
'autocommit': True
}
}
}
Create a new file called local_settings.py. (It is already in the .gitignore).
In the settings.py folder at bottom add the following lines of code:
This will import all from local_settings and if error ignore it (pass)
try:
from cars_project.local_settings import *
except ImportError:
pass
Next, cut the 'DATABASES =' and 'SECRET_KEY = ' blocks of code from settings.py and put them in the local_settings.py file.
Next, go into mysql workbench and create a new data base named after current project.
CREATE DATABASE cars_database
Now we run something called MIGRATIONS. Django out of the box comes with predefined tables used for authentication. (migrate and makemigrations are available in django applications)
Notice the manage.py generated in our application. This is a file wrapped around our django admin executable giving us the freedom of not typing 'django-admin' any longer in this project and giving us further actions to commit. (manage.py)
Give the following command in the terminal:
python manage.py migrate
To check out the available commands when you want to build an app type the following command:
python manage.py
Make New App!
Next command: last space in command is name of app (cars in this instance) Notice a new folder is created.
python manage.py startapp cars
(Primary files we will be concerned with is the views.py and modles.py)
Inside of the settings.py file look for the following code and add to it:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
add: the rest frame work and added cars app.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'cars',
]
First table created in models.py file below
class Car(models.Model):
make = models.CharField(max_length=255)
model = models.CharField(max_length=255)
year = models.IntegerField()
price = models.DecimalField(max_digits=8, decimal_places=2)
Afterwards run one of the the following 2 commands in the terminal to add to the database (second is more specific):
python manage.py makemigrations
python manage.py makemigrations cars
Then run this command to make the migration:
python manage.py migrate
Serializers, writing functions in views.py file, URLs
Serializer helps translate JSON objects so it can be read by python and vise-versa.
- Create a file in cars app called serializers.py and add the following code:
from rest_framework import serializers
from .models import Car
class CarSerilaizer(serializers.ModelSerializer):
class Meta:
model = Car
fields = ['id', 'make', 'model', 'year', 'price']
Views/Functions
Next, go to views.py file and delete the render function import at the top thats auto generated.
Add the following in views.py A decorator assigns certain permissions to a function ('get, post, put, delete')
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET'])
def cars_list(request):
return
URLs
Now let's tie this function to an end point. Create a new file called urls.py in our car app. Path is a function that takes two arguments, the actual endpoint in string format and the function we want to run.
from django.urls import path
from . import views
urlpatterns = [
path('cars/', views.cars_list)
]
To run the project/end point from the terminal
python manage.py runserver
You can grab the URL shown in the terminal (port 8000) and add /cars to it in the browser.
- at this point there will be a 404 not found, one more step--register the cars register the cars url file with the project urls file. Line 17 of the cars_project urls.py file add the following:
Before
"""cars_project URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
After
"""cars_project URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/cars/', include('cars.urls')),
]
Then go to Cars folder then urls.py to delete the path '/cars' so the endpoint works well and not a repeated word in the url.
from django.urls import path
from . import views
urlpatterns = [
path('', views.cars_list)
]
"Djangos browsable API" is the result in the browser at this point.
Admin center app that comes with Django
Type the following command in your directory/terminal
python manage.py createsuperuser
Enter info for the prompts.
Changes should reflect in mysql workbench in the auth_user table.
Now run server
python manage.py runserver
Open link shown in terminal in your browser.
Make sure url is 127.0.0.1:8000/admin/
Log in
In cars app folder > admin.py, import the Car model to access it.
from django.contrib import admin
from .models import Car
# Register your models here.
admin.site.register(Car)
Refresh browser and Cars table should appear. Now we can seed data into the table!
Creating the crud functions in views.py
from django.shortcuts import get_object_or_404
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .serializers import CarSerializer
from .models import Car
@api_view(['GET', 'POST'])
def cars_list(request):
if request.method == 'GET':
cars = Car.objects.all()
serializer = CarSerializer(cars, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = CarSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
@api_view(['GET', 'PUT', 'DELETE'])
def cars_detail(request, pk):
print(request.data)
car = get_object_or_404(Car, pk=pk)
if request.method == 'GET':
serializer = CarSerializer(car)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = CarSerializer(car, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
print('==========here=========')
return Response(serializer.data)
elif request.method == 'DELETE':
car.delete()
return Response(status=status.HTTP_204_NO_CONTENT)