{"id":1072,"date":"2020-10-18T18:19:47","date_gmt":"2020-10-18T18:19:47","guid":{"rendered":"http:\/\/10.0.0.14\/?p=1072"},"modified":"2021-09-07T23:30:38","modified_gmt":"2021-09-07T23:30:38","slug":"tdd-with-django-graphene-docker-part-1","status":"publish","type":"post","link":"https:\/\/tutorials.leesonresearch.com\/tutorials\/2020\/10\/18\/tdd-with-django-graphene-docker-part-1\/","title":{"rendered":"TDD with Gatsby, Django &#038; Docker Part 1, Chapter 01 &#8212; Setup the Django Development Environment"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Part 1: Django Graphene<\/h1>\n\n\n\n<p>In this tutorial we are going to build a Todo app with Gatsby as the frontend and Django Graphene as the backend using test driven development (TDD), and Docker Compose.<\/p>\n\n\n\n<p>In Part 1 of this tutorial our focus will be on building the Django Graphene server. In Part 2 we will build the frontend with Gatsby.<\/p>\n\n\n\n<p>You will need to be comfortable with Django going forward. To bring yourself up to speed on Django check out the <a rel=\"noreferrer noopener\" href=\"https:\/\/www.djangoproject.com\/start\/\" target=\"_blank\">official Django tutorial<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dockerizing Django<\/h2>\n\n\n\n<p>What is Graphene and GraphQL? <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.graphene-python.org\/projects\/django\/en\/latest\/\" target=\"_blank\">Quoting from the official Graphene-Django docs:<\/a> <\/p>\n\n\n\n<blockquote class=\"wp-block-quote has-text-align-left is-layout-flow wp-block-quote-is-layout-flow\"><p>Graphene-Django is built on top of <a href=\"https:\/\/docs.graphene-python.org\/en\/latest\/\">Graphene<\/a>. Graphene-Django provides some additional abstractions that make it easy to add GraphQL functionality to your Django project.<\/p><\/blockquote>\n\n\n\n<p>In short what the above citation is saying, we need Graphene-Django to integrate GraphQL in our Django web app.<\/p>\n\n\n\n<p>What is GraphQL? <a href=\"https:\/\/graphql.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Quoting from the official GraphQL docs:<\/a><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.<\/p><cite><a rel=\"noreferrer noopener\" href=\"https:\/\/graphql.org\/\" target=\"_blank\">official GraphQL docs<\/a><\/cite><\/blockquote>\n\n\n\n<p>In a nutshell what they are saying in the above citation is that a Rest Framework will typically have to make multiple requests to multiple endpoints to get all the data you need for your front-end whereas with GraphQL you only need to send one request specifying the data you need. There is a wonderful in depth discussion on the differences between REST and GraphQL <a href=\"https:\/\/www.howtographql.com\/basics\/1-graphql-is-the-better-rest\/\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>Lets start by building out our directory structure.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Project Directory Structure<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nmkdir todo-app-graphql\ncd todo-app-graphql\nmkdir server\nmkdir db_backups\ntouch docker-compose.yml\ntouch Makefile\ntouch .env\ngit init\ntouch .gitignore\ntouch .dockerignore\ntouch server\/Dockerfile\ntouch server\/requirements.txt\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Populate .dockerignore File<\/h4>\n\n\n\n<p>There are a number of files we don&#8217;t want copied to our docker image so we exclude them with the following:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# Git\n.git\n.gitignore\n\n# Docker\n.docker\n\n# Python\napp\/__pycache__\/\napp\/*\/__pycache__\/\napp\/*\/*\/__pycache__\/\napp\/*\/*\/*\/__pycache__\/\n.env\/\n.venv\/\nvenv\/\n\n# Local PostgreSQL data\ndata\/\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Populate .gitignore File<\/h4>\n\n\n\n<p>Pulling from the Github .gitignore boilerplate,  <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/github\/gitignore\/blob\/master\/Python.gitignore\" target=\"_blank\">gitignore\/Python.gitignore<\/a> we populate the .gitignore file:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# Byte-compiled \/ optimized \/ DLL files\n__pycache__\/\n*.py&#x5B;cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution \/ packaging\n.Python\nbuild\/\ndevelop-eggs\/\ndist\/\ndownloads\/\neggs\/\n.eggs\/\nlib\/\nlib64\/\nparts\/\nsdist\/\nvar\/\nwheels\/\nshare\/python-wheels\/\n*.egg-info\/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date\/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test \/ coverage reports\nhtmlcov\/\n.tox\/\n.nox\/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis\/\n.pytest_cache\/\ncover\/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance\/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs\/_build\/\n\n# PyBuilder\n.pybuilder\/\ntarget\/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default\/\nipython_config.py\n\n# pyenv\n#   For a library or package, you might want to ignore these files since the code is\n#   intended to run in multiple environments; otherwise, check them in:\n# .python-version\n\n# pipenv\n#   According to pypa\/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com\/David-OConnor\/pyflow\n__pypackages__\/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv\/\nvenv\/\nENV\/\nenv.bak\/\nvenv.bak\/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n\/site\n\n# mypy\n.mypy_cache\/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre\/\n\n# pytype static type analyzer\n.pytype\/\n\n# Cython debug symbols\ncython_debug\/\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Our Project Directories and Files<\/h4>\n\n\n\n<ul>\n<li>\ntodo-app-graphql\n<ul>\n<li>db_backups<\/li>\n<li>\nserver\n<ul>\n<li>\nDockerfile\n<\/li>\n<li>\nrequirements.txt\n<\/li>\n<\/ul>\n<\/li>\n\n<li>.env<\/li>\n\n<li>\ndocker-compose-dev.yml<\/li>\n<li>\ndocker-compose.yml<\/li>\n\nMakefile\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Populate the Django Dockerfile<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ncd server\nsudo nano Dockerfile\n<\/pre><\/div>\n\n\n<p>Add the following code to todo-app-graphql\/server\/Dockerfile:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# \/todo-app-graphql\/server\/Dockerfile\n \nFROM python:3\n\n# Set PYTHONUNBUFFERED to 1 so that Python outputs to the container logs.\nENV PYTHONBUFFERED 1\n\nRUN mkdir \/server\nWORKDIR \/server\nCOPY requirements.txt \/server\/\nRUN pip3 install -r requirements.txt\nCOPY . \/server\/\n \nCMD python manage.py collectstatic --no-input;python manage.py makemigrations;python manage.py migrate\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Populate the .env File @ Project Root<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nsudo nano .env\n<\/pre><\/div>\n\n\n<p>Add the following code to todo-app-graphql\/.env:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nDATABASE_NAME=db_todo\nDATABASE_USER=user_todo\nDATABASE_PASSWORD=mypassword\nDATABASE_HOST=database\nDATABASE_PORT=5432\n \nHOST=localhost\n \nSERVER_PORT=5555\nDJANGO_SETTINGS_MODULE=todo_proj.settings\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">The Docker-Compose File<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# dockerized-django\/docker-compose.yml\n \nversion: '3'\n \nservices:\n    database:\n        container_name: postgres\n        image: postgres:latest\n        env_file:\n          - .env\n        environment:\n            - POSTGRES_DB=$DATABASE_NAME\n            - POSTGRES_USER=$DATABASE_USER\n            - POSTGRES_PASSWORD=$DATABASE_PASSWORD\n            - POSTGRES_PORT=$DATABASE_PORT\n        volumes:\n            - .\/postgres-data:\/var\/lib\/postgresql\/data\n \n    server:\n        build: .\/server\/\n        container_name: server\n        ports:\n            - '$SERVER_PORT:$SERVER_PORT'\n        volumes:\n            - .\/server\/:\/server\n        command: python manage.py runserver 0.0.0.0:$SERVER_PORT\n        environment:\n            - DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE\n            - PGHOST=$DATABASE_HOST\n        env_file:\n            - .env\n        depends_on:\n            - database\n\nvolumes:\n    postgres-data:\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Populate the Django requirements.txt File<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nDjango&gt;=3.0\npsycopg2&gt;=2.8.6\ngraphene-django&gt;=2.2.0\ndjango-autoslug&gt;=1.9.6\ndjango-filter&gt;=2.0.0\ndjango-graphql-jwt&gt;=0.1.5\ndjango-mptt&gt;=0.11.0\nPillow&gt;=6.1.0\ndjango-cors-headers&gt;=3.1.0\ndjango-jwt-auth&gt;=0.0.2\nPyJWT&gt;=1.7.1\ncoverage&gt;=5.1\nfreezegun&gt;=0.3.15\npython-dateutil&gt;=2.8.1\npytest-django&gt;=3.9.0\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Create a New Django Project<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# create django project\n# important!! note the trailing .\ndocker-compose run server django-admin startproject todo_proj .\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Edit the New Django Project Setting File<\/h4>\n\n\n\n<p>The default database for a new Django project is sql lite but we want postgresql so we need to edit the DATABASES section of our projects settings.py file.<\/p>\n\n\n\n<p>todo_proj\/settings.py<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nimport os\n\nDATABASES = { \n'default': \n  { \n    'ENGINE': 'django.db.backends.postgresql', \n    'NAME': os.environ.get('DATABASE_NAME'), \n    'USER': os.environ.get('DATABASE_USER'), \n    'PASSWORD': os.environ.get('DATABASE_PASSWORD'),    \n    'HOST': os.environ.get('DATABASE_HOST'), \n    'PORT': os.environ.get('DATABASE_PORT'), \n  } \n}\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Migrate and Create the Django Todo App<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# migrate\ndocker-compose run server python manage.py migrate\ndocker-compose up -d database\ndocker-compose up -d server\ndocker-compose run server django-admin startapp todo_app\ndocker-compose run server python manage.py createsuperuser\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Add Todo App to Django Settings<\/h4>\n\n\n\n<p>Now we add our new Todo app to the Django settings.py file:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; highlight: [8]; title: Double click to copy; notranslate\" title=\"Double click to copy\">\nINSTALLED_APPS = &#x5B;\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'todo_app',\n]\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Test the App<\/h4>\n\n\n\n<p>To see if Django is up and running go to http:\/\/localhost:5555\/admin and login with your superuser credentials and if all went well you should see our projects admin page.<\/p>\n\n\n\n<p>Note if you get an error try running migrate again:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ndocker-compose run server .\/manage.py migrate\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"367\" src=\"http:\/\/10.0.0.14\/wp-content\/uploads\/2020\/09\/django_admin_pt1.png\" alt=\"\" class=\"wp-image-973\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/09\/django_admin_pt1.png 800w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/09\/django_admin_pt1-300x138.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/09\/django_admin_pt1-768x352.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/09\/django_admin_pt1-600x275.png 600w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Coming Up in Part 2: TDD of Django Back End<\/h4>\n\n\n\n<p>In part 2 we begin building out the Django Graphene server for our Todo app using TDD, (test driven development).<\/p>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link\" href=\"tdd-with-django-graphene-docker-part-2\">Next: Part 2 &gt;<\/a><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Setup a docker-compose development and production environments for Gatsby with a Django Graphene backend.<\/p>\n","protected":false},"author":1,"featured_media":312,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,20],"tags":[15,3,21,19],"class_list":["post-1072","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-django","category-featured-tutorial","tag-django","tag-docker","tag-docker-compose","tag-graphene"],"_links":{"self":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/1072","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1072"}],"version-history":[{"count":52,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/1072\/revisions"}],"predecessor-version":[{"id":2502,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/1072\/revisions\/2502"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/media\/312"}],"wp:attachment":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1072"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1072"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1072"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}