Creating a Sample Project
Learn how to set up a Django project, run migrations, and start the Django server.
We'll cover the following
Now that we have an idea about what Django is, let's create our first server in Django.
To create a new project, we’ll use the django-admin
command. It comes with options we can use to create projects in Django:
django-admin startproject CoreRoot .
Don’t forget to add the .
dot at the end of this command. This will actually generate all the files in the current directory instead of creating another directory to put all the files in.
Initialize the project
Run the given terminal and execute the above command to create the CoreRoot
project. Verify the file structure using the ls
command:
We should have a structure of a file that looks like this:
Note: We've set up our work environment and created a directory
django-api
where we’ll be building our Python project. For more information, please look at the Appendix.
Run migrations
Before starting the server, let’s run the migrations. In the terminal above, after creating the CoreRoot
project, execute the given command to run migrations:
python manage.py migrate
Migrations are just a way to propagate changes made to the model in the database schema. Because Django also comes with some models (such as the User
model we can use for authentication), we need to apply these migrations. When we write our own models, we’ll also be creating migrations files and migrating them. Django has object-relational mapping (ORM) that automatically handles the interaction with the database for us.
Learning SQL and writing your own queries is quite difficult and demanding when you are new to it. It takes a long time and is quite off-putting. Fortunately, Django provides a system to take advantage of the benefits of an SQL database without having to write even a single SQL query!
This type of system is called ORM. Behind this somewhat barbaric-sounding name hides a simple and very useful operation. When we create a model in our Django application, the framework will automatically create a suitable table in the database that will save the data relating to the model.
No need to write SQL commands here—we’ll just write code in Python that will be directly translated into SQL. The command python
manage.py
migrate
will then apply these changes to the database.
Start the server
Now, run the following command to start the Django server:
python manage.py runserver
Execute the above command once the terminal loads. Go to the “Output” tab to see the output:
import errno import os import re import socket import sys from datetime import datetime from django.conf import settings from django.core.management.base import BaseCommand, CommandError from django.core.servers.basehttp import WSGIServer, get_internal_wsgi_application, run from django.utils import autoreload from django.utils.regex_helper import _lazy_re_compile naiveip_re = _lazy_re_compile( r"""^(?: (?P<addr> (?P<ipv4>\d{1,3}(?:\.\d{1,3}){3}) | # IPv4 address (?P<ipv6>\[[a-fA-F0-9:]+\]) | # IPv6 address (?P<fqdn>[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*) # FQDN ):)?(?P<port>\d+)$""", re.X, ) class Command(BaseCommand): help = "Starts a lightweight web server for development." # Validation is called explicitly each time the server is reloaded. requires_system_checks = [] stealth_options = ("shutdown_message",) suppressed_base_arguments = {"--verbosity", "--traceback"} default_addr = "0.0.0.0" default_addr_ipv6 = "::1" default_port = "8000" protocol = "http" server_cls = WSGIServer def add_arguments(self, parser): parser.add_argument( "addrport", nargs="?", help="Optional port number, or ipaddr:port" ) parser.add_argument( "--ipv6", "-6", action="store_true", dest="use_ipv6", help="Tells Django to use an IPv6 address.", ) parser.add_argument( "--nothreading", action="store_false", dest="use_threading", help="Tells Django to NOT use threading.", ) parser.add_argument( "--noreload", action="store_false", dest="use_reloader", help="Tells Django to NOT use the auto-reloader.", ) parser.add_argument( "--skip-checks", action="store_true", help="Skip system checks.", ) def execute(self, *args, **options): if options["no_color"]: # We rely on the environment because it's currently the only # way to reach WSGIRequestHandler. This seems an acceptable # compromise considering `runserver` runs indefinitely. os.environ["DJANGO_COLORS"] = "nocolor" super().execute(*args, **options) def get_handler(self, *args, **options): """Return the default WSGI handler for the runner.""" return get_internal_wsgi_application() def handle(self, *args, **options): if not settings.DEBUG and not settings.ALLOWED_HOSTS: raise CommandError("You must set settings.ALLOWED_HOSTS if DEBUG is False.") self.use_ipv6 = options["use_ipv6"] if self.use_ipv6 and not socket.has_ipv6: raise CommandError("Your Python does not support IPv6.") self._raw_ipv6 = False if not options["addrport"]: self.addr = "" self.port = self.default_port else: m = re.match(naiveip_re, options["addrport"]) if m is None: raise CommandError( '"%s" is not a valid port number ' "or address:port pair." % options["addrport"] ) self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups() if not self.port.isdigit(): raise CommandError("%r is not a valid port number." % self.port) if self.addr: if _ipv6: self.addr = self.addr[1:-1] self.use_ipv6 = True self._raw_ipv6 = True elif self.use_ipv6 and not _fqdn: raise CommandError('"%s" is not a valid IPv6 address.' % self.addr) if not self.addr: self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addr self._raw_ipv6 = self.use_ipv6 self.run(**options) def run(self, **options): """Run the server, using the autoreloader if needed.""" use_reloader = options["use_reloader"] if use_reloader: autoreload.run_with_reloader(self.inner_run, **options) else: self.inner_run(None, **options) def inner_run(self, *args, **options): # If an exception was silenced in ManagementUtility.execute in order # to be raised in the child process, raise it now. autoreload.raise_last_exception() threading = options["use_threading"] # 'shutdown_message' is a stealth option. shutdown_message = options.get("shutdown_message", "") if not options["skip_checks"]: self.stdout.write("Performing system checks...\n\n") self.check(display_num_errors=True) # Need to check migrations here, so can't use the # requires_migrations_check attribute. self.check_migrations() try: handler = self.get_handler(*args, **options) run( self.addr, int(self.port), handler, ipv6=self.use_ipv6, threading=threading, on_bind=self.on_bind, server_cls=self.server_cls, ) except OSError as e: # Use helpful error messages instead of ugly tracebacks. ERRORS = { errno.EACCES: "You don't have permission to access that port.", errno.EADDRINUSE: "That port is already in use.", errno.EADDRNOTAVAIL: "That IP address can't be assigned to.", } try: error_text = ERRORS[e.errno] except KeyError: error_text = e self.stderr.write("Error: %s" % error_text) # Need to use an OS exit because sys.exit doesn't work in a thread os._exit(1) except KeyboardInterrupt: if shutdown_message: self.stdout.write(shutdown_message) sys.exit(0) def on_bind(self, server_port): quit_command = "CTRL-BREAK" if sys.platform == "win32" else "CONTROL-C" if self._raw_ipv6: addr = f"[{self.addr}]" elif self.addr == "0": addr = "0.0.0.0" else: addr = self.addr now = datetime.now().strftime("%B %d, %Y - %X") version = self.get_version() print( f"{now}\n" f"Django version {version}, using settings {settings.SETTINGS_MODULE!r}\n" f"Starting development server at {self.protocol}://{addr}:{server_port}/\n" f"Quit the server with {quit_command}.", file=self.stdout, )
Great—we’ve just installed Django and started a Django server. Let’s talk about the structure of the project.
Project components
You may have noticed some files and directories in the django-api
directory. Well, let’s quickly talk about these:
manage.py
: This is a utility provided by Django for many different needs. It’ll help us create projects and applications, run migrations, start a server, and so on.
CoreRoot
: This is the name of the project we’ve created with thedjango-admin
command. It contains files such as the following:wsgi.py
: This file is basically used for deployment but also as the default development environment in Django.
asgi.py
: Django also supports running asynchronous codes as an ASGI application.
settings.py
: This contains all the configurations for your Django projects. You can findÂ
SECRET_KEY
, theÂINSTALLED_APPS
 list,ÂALLOWED_HOST
, and so on.urls.py
: This contains all the URLs that will be used to access resources in the project:
from django.contrib import adminfrom django.urls import pathurlpatterns = [path('admin/', admin.site.urls),]