Вступление
В Pixly мы используем Django в качестве нашего бэкенда из-за превосходных библиотек по науке о данных и большого сообщества в экосистеме Python. Однако, когда мы решили сделать приложение-интерфейс в виде одностраничного приложения с React, мы столкнулись со многими трудностями. Мы надеемся, что наш учебник немного поможет новичкам в решении их будущих проблем.
Требования
Люди, которые следуют этому руководству, должны иметь как минимум начальный уровень знаний о Python и базовый уровень знаний Django Framework . Кроме того, базовый уровень Javascript и React является обязательным.
Этот учебник планируется сделать из трех частей:
- Бэкэнд Джанго.
- Django GraphQL API .
- Реагируйте на внешний интерфейс и связывайте клиентское приложение с Webpack.
Описание проекта
Мы сделаем глупо простое одностраничное приложение, написанное на React, которое будет взаимодействовать с нашим бэкэндом Django через API GraphQL. Приложение React будет написано с нуля с помощью веб-пакета. Шаблон create-реагировать на приложение не будет использоваться.
Существует несколько вариантов интеграции Django и React в производство:
- Вы можете запустить два сервера, один для Django Backend, а другой для Node Backend Server. Это не идеально из-за затрат, связанных с запуском двух разных серверов.
- Вы можете использовать безсерверную архитектуру, поэтому вы платите только за те функции, которые запускаются на стороне клиента, и запрашиваете у нее базу данных.
- Вы можете запустить внутренний сервер Django, который будет отвечать на запросы нашего веб-приложения. Это будет наш подход в этой серии.
Вам также может понравиться:
Учебник по Python Django для начинающих .
Наше веб-приложение будет работать в браузерах наших пользователей. Все запросы и логика внешнего интерфейса будут выполняться браузером с помощью приложения React JavaScript.
Наш проект не будет изоморфным приложением. Следовательно, нам нужен API, который будет использоваться для взаимодействия между Python-бэкендом и JavaScript-интерфейсом. У нас есть два варианта для этого; ОТДЫХ и GraphQL. Мы будем использовать GraphQL. Наш интерфейс и бэкэнд будут использовать Apollo GraphQL и инфраструктуру Graphene соответственно.
Возможно, это не лучшее решение, но мы будем использовать два сервера в разработке. В производстве мы будем использовать только один. Наше приложение-интерфейс не нуждается в сервере.
Шаг 0: Настройка среды
Примечание . Если вы решите использовать существующую среду Python, вы можете пропустить эту часть и перейти к шагу 1.
Это руководство было написано на компьютере с операционной системой Ubuntu 18.04. Интерпретатор Python по умолчанию — Python 3.6.x. Из-за необходимости чистой среды будет установлен Python 3.8, и на нем будет построена виртуальная среда.
Оболочка
1
#<---Install python 3.8--->
2
cd /opt
3
sudo wget <https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz>
4
#extract the source
6
sudo tar xzf Python-3.8.0.tgz
7
cd Python-3.8.0
9
sudo ./configure --enable-loadable-sqlite-extensions
10
#use altinstall to prevent overriding your existing python environment
12
sudo make altinstall
13
#check version of python
15
python3.8 --version
16
# print Python 3.8.0
17
# <---Create Virtual Environment--->
19
# create virtual environment folder
21
cd ~/
22
mkdir venv
23
24
# create python 3.8 virtual environment name djr-venv
25
python3.8 -m venv ~/venv/djr-venv
26
# activate it
28
source ~/venv/djr-venv/bin/activate
29
# you can deactivate it with deactivate command
Создать проект Django
Шаг 1: Установите зависимости
Оболочка
xxxxxxxxxx
1
# <--- Create Django Project --->
2
# We will create the project in the Blog folder
4
# with a name djr
5
# install our dependencies
7
pip install ipython django django_extensions django-cors-headers "graphene-django>=2.0"
Шаг 2: Создайте проект Django
Оболочка
xxxxxxxxxx
1
#start a django project
2
django-admin startproject djr
3
# change directory
5
cd djr
6
# create templates directory
8
mkdir templates
9
# create static folder
11
mkdir static
Шаг 3: Создайте новое приложение Django
Теперь мы можем создать наше приложение для создания моделей баз данных.
Оболочка
xxxxxxxxxx
1
# create our app and activate it on the settings.py
2
python manage.py startapp items
Шаг 4. Настройка параметров Django
Обновите файл настроек в соответствии с этим.
питон
xxxxxxxxxx
1
INSTALLED_APPS = [
2
'django.contrib.admin',
3
'django.contrib.auth',
4
'django.contrib.contenttypes',
5
'django.contrib.sessions',
6
'django.contrib.messages',
7
'django.contrib.staticfiles',
8
"django_extensions",# New! (useful extension)
10
'graphene_django', # New! (for graphql communication)
11
'corsheaders', # New! (for cors request in dev env)
12
"items" # ---> New! (make our app will active)
13
]
14
# New
16
# for improved interactive shell
17
# add this
18
SHELL_PLUS = "ipython"
19
# allow webpack development server to make cross-request
CORS_ORIGIN_WHITELIST = (
'<http://localhost:8080>',
)
GRAPHENE = {
'SCHEMA': 'gql.schema.schema'
}
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'corsheaders.middleware.CorsMiddleware', # New Add this
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': (os.path.join(BASE_DIR, 'templates'),), # New
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
#New
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
Now, the general structure of the directory should look like this:
Step 5: Run the Django Server
Before starting our project, we should first make a database migration.
xxxxxxxxxx
# create migration for django-orm
python manage.py migrate
Now, we can start our project and see what happens.
xxxxxxxxxx
# run server
python manage.py runserver
Now, Our Django development server is ready.
You can go to the URL address of http://127.0.0.1:8000/ and verify that it is working.
After then, you can stop the server by pressing CTRL + C.
Step 6: Create the Movie App
We will create a movie model with basic fields that a movie should have. Before that, we should give some information about the field choices.
Why is there a URL field for poster rather than image field?
Because serving static files in production is out of our scope, we decide to use only the URL field. Fetching the image from remote and then saving it to our production storage is a topic for another post. Due to this, we will save only the poster's URL, not the poster itself as an image file. Also, sending static files like images is not a good approach. We will send the exact URL of an image to the user. Then, the user's browser fetches the image from the URL.
What is slug and why should it be unique?
When browsing on Pixly, if you open The Matrix movie page, you will see that your address bar will be: https://pixly.app/movie/the-matrix-1999. The last part of the URL is the slug of The Matrix movie, which acts as an identifier which makes the URL distinctive from other movie pages. In the GraphQL part of the tutorial, you will see that this slug will be used as a query parameter, meaning that database queries will be done according to slug. Therefore, it should be unique.
We can also choose the movie id as a URL identifier, but it's clear that the URL will not be a human-readable address. Moreover, search engine indexing and ranking is a vital part of any website targeting new users. Readable URL addresses are good for users themselves and also suggested by search engine guides. For example, the Google webmaster guideline recommends using clean and concise URL structures. Let's make our model.
Let's open the items/models.py file.
xxxxxxxxxx
# items.models
from django.db import models
# Create your models here.
class Movie(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
year = models.IntegerField(null=True)
summary = models.TextField(max_length=5000,null=True)
poster_url = models.URLField(blank=True, null=True)
slug = models.SlugField(
max_length=50, null=True,blank =True, unique=True)
class Meta:
ordering = ["-year"]
def __str__(self):
return self.name
Migrate again in order to make database arrangements for our new model.
xxxxxxxxxx
python manage.py makemigrations
python manage.py migrate
Step 7: Populating Database With Initial Data
There is no movie record currently in our database. We will provide a small initial data to create some movie records. All the data is provided by the community-built The Movie Database (TMDb).
First, create a class method in order to import initial data.
xxxxxxxxxx
# items.models
class Movie(models.Model):
"""
... Model is truncated
"""
#<-----Add this class method------>
def import_records(cls, record_list):
for record in record_list:
# create record if id is not exist
if not Movie.objects.filter(id=record.get("id")).exists():
new_movie = cls.objects.create(**record)
else:
print(f"Id:{record.get('id')} is already exist.")
print("Import operation done successfully")
Then, get the initial data file from GitHub repo and set the initial_data.py file in the utils folder. The directories and the initial data looks like this.
Normally, we would have an open Django shell. However, shell_plus, which is provided by the django_extensions package, is more functional, so we will use this.
# normally we use this command
# python manage.py shell
# However django_extensions shell is more functional
# it preimports all apps we created
# open interactive shell
python manage.py shell_plus
xxxxxxxxxx
# django interactive shell
# let's first check our database for movie records
# and verify that it empty.
In [1]: Movie.objects.all()
Out[1]: <QuerySet []>
# import the list of records
In [2]: from utils.initial_data import initial_data
# create records in the database
In [2]: Movie.import_records(initial_data)
#Import operation done successfully
#Successfully imported our initial data
Our model and database are ready. You can close the shell with the quit
command.
In the next part, we will create our API with Python's GraphQL framework, Graphene, and its Django package graphene-django.