Dev Standards
  • Untitled
  • project-standards
    • project-success
      • index
      • production.s
    • taking-over-project
      • index
      • migrate-to-new-ios-certificates.mo
    • technical-agility
      • react-native-test.s
      • code-vocabulary-identical-business-vocabulary.s
      • under-15-minutes-project-installation.s
      • index
      • up-to-date-dependencies.s
  • react-native
    • react
      • get-element-size-or-position-with-onLayout.mo
      • binding-functions-in-react-component.s
      • enable-overflow-android.mo
    • setup
      • setup-code-push.mo
      • setup-facebook-login.mo
      • setup-and-deploy-new-project-to-staging.mo
      • add-cocoapods.mo
      • deploy-script.mo
      • setup-and-deploy-new-project-to-staging-with-hockeyapp.mo
      • add-native-module.mo
      • setup_firebase_multiple_envs.mo
      • remove-unnecessary-android-permissions.mo
      • deploy-to-production-android.mo
      • deploy-project-to-production
      • overriding-existing-app.s
      • patch-react-native-android.mo
      • setup-stripe-dev-standard.mo
    • features
      • icomoon.mo
      • lock-device-orientation.mo
      • clean-logout.s
      • deep-linking
      • offline-redux.mo
      • asyncstorage.mo
      • offline-mobx.mo
    • debugging
      • analyse-bug.mo
      • debug-network-calls.mo
      • debug-javascript-ios-device.mo
      • get-ios-logs.mo
      • debug-javascript.mo
      • handle-gradle-dependencies-clash.mo
      • debug-native-ios.mo
      • debug-two-ios-apps-simultaneously.mo
      • debug-native-android.mo
      • debug-webviews.mo
    • firebase
      • debug-events.mo
    • architecture
      • project-architecture.s
      • default-stack.s
      • file-naming.s
    • update
      • upgrade-react-native.mo
    • tests
      • setup-detox-jest.mo
    • use_http_links_in_react_native.mo
    • react-navigation
      • unmount-compoenent-on-page-change.mo
    • package-dependencies
      • handle-dependencies-with-yarn-override.mo
    • animations
      • react-native-animations.s
  • successful-sprint
    • coding
      • plan-your-ticket-to-improve-efficency.s
  • code-quality
    • components-state-testing.mo
    • mock-with-jest.mo
    • pull-request-template.s
    • pull_request_template
    • test-files-indentation.s
  • security
    • import_certificates_match.mo
    • 2FA.mo
  • contributing
    • contributing.mo
    • mo.s
    • standard.s
  • backend
    • graphql-js
      • getting-started-with-apollo-server-dataloader-knex.mo
    • node-js
      • handle-errors-and-exceptions-in-javascript.s
      • add-multiple-environments-configuration-on-loopback.s
    • django
      • deploy-to-aws.mo
      • create-user-model.mo
      • getting-started.mo
      • create-model-and-api.mo
  • performance
    • backend
      • cache-routes-using-varnish.mo
      • serve-images-as-static-files.mo
      • minimize-number-sql-queries.mo
      • python-investigation-tools.mo
      • how-to-investigate-performance.mo
      • output-sql-alchemy-orm-query.mo
    • front
      • how-to-investigate-performance.mo
      • table-and-chart-with-good-performance.mo
      • react-native-performance.s
      • simulate-network-iphone.mo
    • performance-decision-flow.s
  • git
    • merge-or-rebase-a-branch
  • editors
    • vscode
      • setup-vscode.mo
  • ops
    • docker
      • deploy-with-https.mo
  • templates
    • mo
  • react
    • redux
      • custom-redux-form-field.mo
      • pass-props-to-container.mo
    • component.s
    • lifecycle
      • trigger-action-on-props-update.mo
  • flowtype
    • flowtype.s
  • LICENCE
  • README
  • scrum
    • timebox.s
  • SUMMARY
Powered by GitBook
On this page
  • Owner: Tycho Tatitscheff
  • Context
  • Prerequisites (~10 min)
  • Steps (~35 min)
  • Initialise a new python project (~5 min)
  • Install django (~1 min)
  • Create a project and a first application (~4 min)
  • Add the first model (~5 min)
  • Complete with other models (~1 min)
  • Generate the admin (~1 min)
  • Customize the admin (~3 min)
  • Install REST Framework (~5 min)
  • Write your first rest API (~10 min)
  • Next steps
  • Troubleshooting
  1. backend
  2. django

getting-started.mo

Previouscreate-user-model.moNextcreate-model-and-api.mo

Last updated 7 years ago

Owner:

Note: Please create an or even a Pull Request with your feedback, typo correction.

Context

During this standard, we will take the example of a book library management app.

We will thus create a MAB project (BAM, reversed) and a Library app containing a Book and a Author Models.

We will create an Admin using Django Admin Framework and a rest API, using Django Rest Framework.

Prerequisites (~10 min)

  • Have HomeBrew installed (ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)) (~3 min)

  • Have $PATH environment variable prioritizing Homebrew package (export PATH=/usr/local/bin:/usr/local/sbin:$PATH in .bashrc or similar) (~3 min)

  • Have Python 3.6 installed (brew install python3): 3.6 is needed for [f"{variable} text" syntax] (), if you have version 3.x (x lower then 6, just use the old format "{} text".format(variable) (~2 min)

  • Have virtualenv installed (pip3 install virtualenv) (~1 min)

  • If you use Visual Studio Code, read (~5 min)

Steps (~35 min)

Important Note: You should commit between each steps, as you have a shippable application at the end of each steps. This will help you reverting if you delete important stuff.

Initialise a new python project (~5 min)

  • Create a directory for the project: mkdir ~/Code/django_formation

  • Go to the directory: cd ~/Code/django_formation

  • Init a git directory: git init

  • Create a python env for your project virtualenv -p $(which python3) .venv

  • Add this python env to project .gitignore: echo ".venv" > .gitignore

  • Activate the virtualenv source .venv/bin/activate

CHECK 1: You should see the name of the env in front or your terminal prompt

CHECK 2: Python should now points to your env:

(.venv) ➜  django git:(master) ✗ which python
~/Code/django_formation/django/.venv/bin/python

CHECK 3: you should have a .env and a .git folder, plus a .gitignore file

(.venv) ➜  django git:(master) ✗ ls -lath
drwxr-xr-x   9 user  staff   306B Aug  3 14:18 .git
drwxr-xr-x   5 user  staff   170B Aug  3 14:18 .
-rw-r--r--   1 user  staff     6B Aug  3 14:18 .gitignore
drwxr-xr-x   7 user  staff   238B Aug  3 14:16 .venv
drwxr-xr-x  67 user  staff   2.2K Aug  3 14:03 ..

Install django (~1 min)

  • Install django with pip: pip install django

  • Save the dependencies to a lockfile: pip freeze > requirements.txt

CHECK 1: you should have a requirements.txt containing:

(.venv) ➜  django git:(master) ✗ cat requirements.txt
Django==1.11.4
pytz==2017.2

CHECK 2: django commands should be available django-admin.py

Create a project and a first application (~4 min)

  • Start new project MAB (Mobile Application Backend, or BAM reversed): django-admin.py startproject mab . (Note the trailing '.' character)

  • Go to mab: cd mab

  • Create a first app Library (that will store and manage BAM books): django-admin.py startapp library

  • Add 'mab.library' to the INSTALLED_APPS, in the settings.py (DO NOT REPLACE THE WHOLE FILE)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mab.library'
]
  • Go back to root of the project: cd ~/Code/django_formation

  • Migrate the database: python manage.py migrate

  • Create the django super user: python manage.py createsuperuser and fill with a username, an email and a very-secret(™) password

CHECK:

  • Run the server: python manage.py runserver

  • Access http://127.0.0.1:8000 and see the "It worked page"

  • Access http://127.0.0.1:8000/admin, connect and see the admin page with the username/password created above

Add the first model (~5 min)

  • Open mab/library/models.py in Pycharm (or other, if you still resists).

  • Lets start with a model Author: a model derive from models.Model, and for project documentation have a small docstring explaining what it is

from django.db import models

class Author(models.Model):
    """Represent the author of a book"""
    pass
from django.db import models

class Author(models.Model):
    """Represent the author of a book"""
    first_name = models.CharField(
        max_length=20, 
        verbose_name="The first name of the author", 
        null=False, 
        blank=False
    )
    last_name = models.CharField(
        max_length=20, 
        verbose_name="The first name of the author",
        null=False,
        blank=False
    )
    created = models.DateTimeField(
        auto_now_add=True, 
        verbose_name="The creation date of the author in database"
    )
    modified = models.DateTimeField(
        auto_now=True, 
        verbose_name="The modification date of the author in database"
    )

NOTE: it is a good practice to add created and modified fields to models, and add a verbose name.

  • Create auto-magically the migrations: python manage.py makemigrations

  • Migrate the database: python manage.py migrate

CHECK 1:

  • Launch python manage.py showmigrations: you should see a table with django internal migrations and your migration for library app

CHECK 2:

  • Open the migrated sqlite file

  • See the new table

Complete with other models (~1 min)

  • Edit the models.py file so it looks like:

from django.db import models

SUBJECTS_ENUMS = (
    ('front', 'Front End'),
    ('back', 'Backend'),
    ('devops', 'Dev-Ops'),
    ('lean', 'Lean'),
    ('agile', 'Agile'),
)


class Author(models.Model):
    """Represent the author of a book"""
    first_name = models.CharField(max_length=20, verbose_name="The first name of the author", null=False, blank=False)
    last_name = models.CharField(max_length=20, verbose_name="The first name of the author", null=False, blank=False)
    created = models.DateTimeField(auto_now_add=True, verbose_name="The creation date of the author in database")
    modified = models.DateTimeField(auto_now=True, verbose_name="The modification date of the author in database")

    def __str__(self):
        # The name of the object
        return f"{self.first_name} {self.last_name}"


class Book(models.Model):
    title = models.CharField(max_length=40, null=False, blank=False, verbose_name="The title of the book")
    isbn = models.CharField(max_length=13, null=False, blank=False, verbose_name="The ISBN number")
    author = models.ForeignKey(Author, null=False, verbose_name="Link to the author of the book")
    subject = models.CharField(max_length=10, choices=SUBJECTS_ENUMS, null=False, blank=False, verbose_name="Main subject of the book")
    buy_date = models.DateField(verbose_name="The date when BAM buy the book")
    created = models.DateTimeField(auto_now_add=True, verbose_name="The creation date of the author in database")
    modified = models.DateTimeField(auto_now=True, verbose_name="The modification date of the author in database")

    def __str__(self):
        # The name of the object
        return f"{self.title}"
  • Make migrations and migrate

Generate the admin (~1 min)

  • Open admin.py

from django.contrib import admin
from .models import Author, Book

admin.site.register(Author)
admin.site.register(Book)

CHECK:

  • Access http://127.0.0.1:8000/admin, connect and see the admin page

Customize the admin (~3 min)

  • You can edit the admin to profit from django powerful admin

from django.contrib import admin
from .models import Book, Author


# The inline would list for every author the books they made
class BookInline(admin.TabularInline):
    model = Book
    readonly_fields = (
        'title',
        'isbn',
        'author',
        'subject',
        'buy_date',
        'created',
        'modified'
    )

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


class AuthorAdmin(admin.ModelAdmin):
    # the field on edition page
    # (xxx, yyy), will put xxx and yyy on the same line
    fields = (
        ('first_name', 'last_name'),
        ('created', 'modified')
    )
    # the not editable field
    readonly_fields = (
        'created',
        'modified'
    )
    # pagination control on the list
    list_per_page = 10
    # fields available for full text search
    search_fields = ('first_name', 'last_name')
    # name of the list column
    list_display = ('first_name', 'last_name')
    # inlines
    inlines = (BookInline,)


class BookAdmin(admin.ModelAdmin):
    # the field on edition page
    # (xxx, yyy), will put xxx and yyy on the same line
    fields = (
        ('title', 'isbn'),
        'author',
        'subject',
        'buy_date',
        ('created', 'modified')
    )
    # the not editable field
    readonly_fields = (
        'created',
        'modified'
    )
    # pagination control on the list
    list_per_page = 10
    # Extra date selector
    date_hierarchy = 'buy_date'
    # fields available for full text search
    search_fields = ('title', 'subject')
    # name of the list column
    list_display = ('title', 'subject', 'buy_date', 'author')
    # filter side bar in list page
    list_filter = ('subject',)

admin.site.register(Author, AuthorAdmin)
admin.site.register(Book, BookAdmin)

CHECK:

  • Access http://127.0.0.1:8000/admin, connect and see the admin page

Install REST Framework (~5 min)

  • Run pip install djangorestframework

  • Save the dependencies to a lockfile: pip freeze > requirements.txt

  • Add 'rest_framework' to your INSTALLED_APPS setting.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mab.library',
    'rest_framework'
]
  • Add django rest framework urls, in urls.py (optional)

from django.conf.urls import url, include
urlpatterns = [
    ...
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    ...
]

Write your first rest API (~10 min)

  • Create a file rest.py in the same folder as models.py

  • Copy the following

from rest_framework import routers, serializers, viewsets
from .models import Book

# Serializers define the API representation.
class BookSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Book
        fields = ('title', 'subject', 'buy_date')

# ViewSets define the view behavior.
class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'books', BookViewSet)
  • Add router urls, in urls.py

from django.conf.urls import url, include
from django.contrib import admin
from mab.library import rest

urlpatterns = [
    url(r'^', include(rest.router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^admin/', admin.site.urls),
]

Next steps

Troubleshooting

NOTE: this way of organizing app inside project is not the default, but, in a smaller extends, it is the recommended way for django by , the best book in the world about good practise with django.

NOTE: In order to keep the method of operation simple, we use the built in sqlite adapters. You can read more to change it the .

NOTE: for editing Python code, I recommend using . The debugging and auto complete features helps a lot. There is a community edition that is free to use. That being said, committed on making VSCode great again, even for python. Stay tuned.

Lets add the first fields in the Author models: there is a lot of available fields in django.db.models and even more available in platform specifics modules (eg, ), or in external plugins

Install

Django documentation is well organized:

Beware, at least 1/3 of the article are not about Python and really NSFW. is really the best resource for python learning in French, especially django.

Django has a strong community on and

Tycho Tatitscheff
issue
https://cito.github.io/blog/f-strings/
this article
Two Scoops of Django
beautiful documentation
Pycharm
@yann
postgres array or json fields
https://sqlitestudio.pl
GraphQL with django
Screencast of django
Best Book ever for django
Awesome Django
https://docs.djangoproject.com/en/1.11/
Sam et Max blog
Reddit
blogs