30 Oct 2020

feedDjango community aggregator: Community blog posts

Django News - New Django Girls Leadership - Oct 29th 2020

News

Ola & Ola step down from Django Girls Foundation

The Django Girls Foundation welcomed a new team of trustees: Anna, Aisha, Claire, Leona, and Rachell ❤️.

djangogirls.org

Python Software Foundation News: Python Software Foundation Fellow Members for Q3 2020

🎉 Congratulations to Katia Lira (DEFNA Board member), Mariatta Wijaya (DjangoCon US Keynote speaker), and other Pythoniasts for being picked as PSF Fellow Members.

blogspot.com

DjangoCon US 2020 Video

⏰ The deadline has been extended. Please take a minute to record a short video for the virtual conference this year.

defna.org

Articles

A Django REST API in a Single File

The third in a series of writing Django apps in a single file, following previous posts on synchronous and asynchronous use cases.

adamj.eu

How to Setup Django with React

A detailed guide to the various steps required to have React play well with Django.

mattsegal.dev

Password Reset Views in Django

Learn how to setup password reset views with django.contrib.auth.

dev.to

Podcasts

PythonBytes #204 - Take the PSF survey and Will & Carlton drop by

Django Fellow Carlton Gibson and DSF Board Member Will Vincent talk about moving from prototype to production in Django as well as all things deployment.

pythonbytes.fm

Django Chat #77 - MongoDB with Aaron Bassett

Aaron is a developer advocate at MongoDB and Board Member of the Django Software Foundation. We discuss relational vs non-relational databases, the developer advocate role, and giving virtual conference talks.

djangochat.com

Django Riffs - Application Examination

All about applications within the context of a larger Django project.

djangoriffs.com

Running in Production - A Django-based Jewelry E-Commerce Store

Dan Purcell goes over building an e-commerce store with Django that processes up to 3,000 orders per second. It's running on 12+ web servers on DigitalOcean and the site has been up and running since 2014.

runninginproduction.com

JustDjango - Eric Vanular of Collective Energy

Eric is an indie hacker, software developer, consultant and creator of Collective Energy, a community for people working together to combat climate change. He also created Enviro.work which is an affiliated green jobs board. He built it using Django.

justdjango.com

Projects

jazzband/django-floppyforms

Full control of form rendering.

github.com

django-crispy-forms/django-crispy-forms/

DRY Django forms.

github.com

matthiask/django-tree-queries

Query Django model trees using adjacency lists and recursive common table expressions. Supports PostgreSQL, sqlite3 (3.8.3 or higher) and MariaDB (10.2.2 or higher) and MySQL (8.0 or higher, if running without ONLY_FULL_GROUP_BY).

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

30 Oct 2020 12:42am GMT

29 Oct 2020

feedDjango community aggregator: Community blog posts

Sending Invites - Building SaaS #77

In this episode, I worked on the form that will send invites to users for the new social network app that I'm building. We built the view, the form, and the tests and wired a button to the new view. The first thing that we do was talk through the new changes since the last stream. After discussing the progress, I took some time to cover the expected budget for the application to get it to an MVP.

29 Oct 2020 5:00am GMT

28 Oct 2020

feedDjango community aggregator: Community blog posts

MongoDB - Aaron Bassett

Support the Show

Our podcast does not have a sponsor and is a labor of love. To support the show, please consider purchasing one of the books on LearnDjango.com or suggest one to a friend.

28 Oct 2020 10:00pm GMT

Generating random avatar images in Django/Python

tl;dr; <img src="/avatar.random.png" alt="Random avataaar"> generates this image:

Random avataaar
(try reloading to get a random new one. funny aren't they?)

When you use Gravatar you can convert people's email addresses to their mugshot.
It works like this:

<img src="https://www.gravatar.com/avatar/$(md5(user.email))">

But most people don't have their mugshot on Gravatar.com unfortunately. But you still want to display an avatar that is distinct per user. Your best option is to generate one and just use the user's name or email as a seed (so it's always random but always deterministic for the same user). And you can also supply a fallback image to Gravatar that they use if the email doesn't match any email they have. That's where this blog post comes in.

I needed that so I shopped around and found avataaars generator which is available as a React component. But I need it to be server-side and in Python. And thankfully there's a great port called: py-avataaars.

It depends on CairoSVG to convert an SVG to a PNG but it's easy to install. Anyway, here's my hack to generate random "avataaars" from Django:

import io
import random

import py_avataaars
from django import http
from django.utils.cache import add_never_cache_headers, patch_cache_control


def avatar_image(request, seed=None):
    if not seed:
        seed = request.GET.get("seed") or "random"

    if seed != "random":
        random.seed(seed)

    bytes = io.BytesIO()

    def r(enum_):
        return random.choice(list(enum_))

    avatar = py_avataaars.PyAvataaar(
        style=py_avataaars.AvatarStyle.CIRCLE,
        # style=py_avataaars.AvatarStyle.TRANSPARENT,
        skin_color=r(py_avataaars.SkinColor),
        hair_color=r(py_avataaars.HairColor),
        facial_hair_type=r(py_avataaars.FacialHairType),
        facial_hair_color=r(py_avataaars.FacialHairColor),
        top_type=r(py_avataaars.TopType),
        hat_color=r(py_avataaars.ClotheColor),
        mouth_type=r(py_avataaars.MouthType),
        eye_type=r(py_avataaars.EyesType),
        eyebrow_type=r(py_avataaars.EyebrowType),
        nose_type=r(py_avataaars.NoseType),
        accessories_type=r(py_avataaars.AccessoriesType),
        clothe_type=r(py_avataaars.ClotheType),
        clothe_color=r(py_avataaars.ClotheColor),
        clothe_graphic_type=r(py_avataaars.ClotheGraphicType),
    )
    avatar.render_png_file(bytes)

    response = http.HttpResponse(bytes.getvalue())
    response["content-type"] = "image/png"
    if seed == "random":
        add_never_cache_headers(response)
    else:
        patch_cache_control(response, max_age=60, public=True)

    return response

It's not perfect but it works. The URL to this endpoint is /avatar.<seed>.png and if you make the seed parameter random the response is always different.

To make the image not random, you replace the <seed> with any string. For example (use your imagination):

{% for comment in comments %}
  <img src="/avatar.{{ comment.user.id }}.png" alt="{{ comment.user.name }}">
  <blockquote>{{ comment.text }}</blockquote>
  <i>{{ comment.date }}</i>
{% endfor %}

I've put together this test page if you want to see more funny avatar combinations instead of doing work :)

28 Oct 2020 5:10pm GMT

26 Oct 2020

feedDjango community aggregator: Community blog posts

Application Examination

Full show notes are available at https://www.mattlayman.com/django-riffs/9.

26 Oct 2020 7:16pm GMT

24 Oct 2020

feedDjango community aggregator: Community blog posts

How to setup Django with React

It's not too hard to get started with either Django or React. Both have great documentation and there are lots of tutorials online. The tricky part is getting them to work together. Many people start with a Django project and then decide that they want to "add React" to it …

24 Oct 2020 6:00am GMT

23 Oct 2020

feedDjango community aggregator: Community blog posts

Django News - Some of our favorite DjangoCon Europe 2020 videos - Oct 23rd 2020

News

Sponsor @python on GitHub Sponsors

The PSF joined GitHub's sponsor's program. Their goal is to raise enough money to help support the development of CPython.

github.com

Events

PyTexas 2020 Schedule

PyTexas is this weekend, Oct 24th & 25th, and is free to attend. Donations and t-shirts may still be available.

pytexas.org

San Francisco Django Virtual Meetup

Join the San Francisco Django Meetup Group on October 28th for a free virtual meetup.

meetup.com

Articles

A Year in the Life of a DSF Board Member

An overview of 2020 activities for the Django Software Foundation Treasurer position.

wsvincent.com

Why You Should Pay for Open Source

Will Heinemann discusses making a strong case for supporting (and paying for) open-source and a recent Wagtail Space 2020 video on the topic.

wagtail.io

Simplifying Django deployments on Heroku

Eric Matthes, author of Python Crash Course, on his newly created Heroku Python buildpack that automates as much of the deployment process as possible

ehmatthes.com

Comprehending Class-Based Views in Django - Creating a CBV

The second in a series of articles on how CBVs work under-the-hood.

brennantymrak.com

feincms may still be relevant

feincms is one of the original Django CMS's and still in use. This article highlights a list of its current features.

406.ch

The Surprising Impact of Medium-Size Texts on PostgreSQL Performance

Haki Benita demonstrates the surprising impact of medium-size texts on query performance in PostgreSQL.

hakibenita.com

Quiz Wiz -- A Model for Learning

Steven writes about building a full-stack project, Quiz Wiz, using DRF, Postgres, React, etc.

github.io

Videos

DjangoCon Europe 2020: Can't get you out of my head by Aaron Bassett

What happens when you crawl 10,000,000 domains?

youtu.be

DjangoCon Europe 2020: Implementing a Cross-DB JSONField by Sage M. Abdullah

This talk explains the implementation of a cross-DB JSONField, a new feature released in Django 3.1, that can be used on all database backends supported by Django.

youtu.be

DjangoCon Europe 2020: A Pentester's Thoughts on Django Security by Pascal Uter

An overview of Django's security features, their limitations, and some general security best practices to keep in mind.

youtu.be

DjangoCon Europe 2020: Search Options in Django by Stefan Baerisch

An overview of the different ways in which you can implement search functionality in Django. We will look at the full-text search options that come with databases and the use of a dedicated search engine like Elastic Search or Postgres. Along the way, you will learn about the different ways in which you can index your data to learn how to evaluate your search results.

youtu.be

DjangoCon Europe 2020: Accessibility wins for Django projects by Thibaud Colas

Accessibility is a big topic, which can be hard to approach. We'll look at how the team behind Wagtail set to work on making their CMS more accessible, focusing on Django-specific improvements that are relevant to all projects.

youtu.be

Podcasts

Test & Code - Speeding up Django Test Suites with Adam Johnson

Django Technical Board member Adam Johnson talks about how to speed up Django tests, including parallelizing tests, moving from disk to memory, using fake data and factory function, targeted mocking, and more.

testandcode.com

Running in Production - An Inventory Management System for an E-commerce Platform with Galen Rice

Galen Rice walks us through building an internal inventory management system with Django and Python. It's running on a single bare metal server and has been up and running since 2013.

runninginproduction.com

Just Django - Allison Seboldt of Fantasy Congress

Allison is a software developer, indie hacker and creator of Fantasy Congress which is an online game that takes a fantasy sports spin on politics

justdjango.com

Projects

DJ Checkup

Sasha Romijn ran the popular site Pony Checkup for many years and DJ Checkup is an updated version. Currently there are 10 different checks run on a Django site.

djcheckup.com

sshgit: Find secrets in real time

shhgit finds committed secrets and sensitive files across GitHub, Gists, GitLab and BitBucket or your local repositories in real time.

shhgit.com

matthiask/feincms3

feincms3 offers tools and building blocks which make building a CMS that is versatile, powerful and tailor-made at the same time for each project a reachable reality.

github.com

rsinger86/drf-typed-views

Use type annotations to validate/deserialize request parameters in Dango REST Framework.

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

23 Oct 2020 4:00pm GMT

21 Oct 2020

feedDjango community aggregator: Community blog posts

gettext, JSX and ES6 template literals

gettext, JSX and ES6 template literals

I really like using gettext to translate hardcoded strings into other languages. Django's translations functionality relies on it as well.

Unfortunately, the xgettext executable which is responsible to collect translatable strings in your code has a bug where it just stops processing files when encountering ES6 template literals inside JSX tags. Support for ES6 template literals was added earlier this year but combining those literals with JSX still doesn't work.

I wrote a small Python script to extract *gettext calls from JavaScript files; the current version is here. The idea is to find all JavaScript files using git ls-files "*.js", using a regular expression to find *gettext calls and write the output to a place where Django's ./manage.py makemessages finds it.

I'm certain the code will break too with strange error messages in the near future but it seems to work well, for the moment.

Here's the current version of the code (hopefully) for your enjoyment:

#!/usr/bin/env python3

import re
import subprocess


def js_files():
    res = subprocess.run(
        ["git", "ls-files", "*js", "*mjs"],
        capture_output=True,
        encoding="utf-8",
    )
    return res.stdout.splitlines()


def gettext_calls(file):
    with open(file, encoding="utf-8") as f:
        return [
            match[0]
            for match in
            re.findall(
                r"""\b(\w*gettext\(\s*(['"]).+?\2\s*\))""",
                f.read(),
            )
        ]


if __name__ == "__main__":
    calls = []
    for file in js_files():
        calls.extend(gettext_calls(file))
    print("\n".join(sorted(set(calls))))

21 Oct 2020 8:56am GMT

20 Oct 2020

feedDjango community aggregator: Community blog posts

A Year in the Life of a DSF Board Member

What Django Software Foundation Board Member's actually do.

20 Oct 2020 3:28pm GMT

Episode 9 - Application Examination

On this episode, we will study the structure of a Django application. Applications are the core components that make up a Django project. Listen at djangoriffs.com. Last Episode On the last episode, we focused on the built-in Django administrator's site. We'll saw what it is, how you can configure it, and how you can customize it to serve your needs. What Is An Application? In Django parlance, a "web application" is a Django project.

20 Oct 2020 5:00am GMT

On using Markdown with Sphinx - onward to Evennia 0.9.5

Last post I wrote about the upcoming v1.0 of Evennia, the Python MU* creation engine. We are not getting to that 1.0 version quite yet though: The next release will be 0.9.5, hopefully out relatively soon (TM).

Evennia 0.9.5 is, as you may guess, an intermediary release. Apart from the 1.0 roadmap just not being done yet, there is one other big reason for this - we are introducing documentation versioning and for that a proper release is needed as a base to start from. Version 0.9.5 contains everything already in master branch, so if you have kept up-to-date you won't notice too much difference. Here are some highlights compared to version 0.9:

Many contributors helped out along the way. See the changelog where contributors of the bigger new features are listed.

The path to a new documentation

For many years we've used the Github wiki as our documentation hub. It has served us well. But as mentioned in my previous post, it has its drawbacks, in particular when it comes to handling documentation for multiple Evennia versions in parallel.

After considering a bunch of options, I eventually went with sphinx, because it has such a good autodoc functionality (parsing of the source-code docstrings). This is despite our wiki docs are all in markdown and I dislike restructured text quite a bit. Our code also uses friendly and in-code-readable Google-style docstrings instead of Sphinx' hideous and unreadable format.

Luckily there are extensions for Sphinx to handle this:

What could go wrong? Well, it's been quite a ride.

Getting Markdown into reST

Linking to things in recommonmark turned out to be very flaky. I ended up forking and merging a bunch of PRs from the project but that was not enough: Clearly this thing was not built to convert 200 pages of technical markdown from a github wiki.

My custom fork of recommonmark had to be tweaked a bit for my needs, such as not having to specify the .md file ending in every link and make sure the url-resolver worked as I expected. There were a bunch of other things but I will probably not merge this back, the changes are pretty Evennia-specific.

Even so, many of my wiki links just wouldn't work. This is not necessarily recommonmark's fault, but how sphinx works by grouping things into toctrees, something that the Evennia wiki doesn't have.

Also, the recommonmark way to make a toctree in Markdown is to make a list of links - you can't have any descriptive text, making the listing quite useless (apparently people only want bland lists of link-names?). After trying to figure out a way to make this work I eventually capitulated - I make pretty lists in Markdown while using a "hidden" toctree to inform sphinx how the pages are related.

Getting the wiki into the new doc site

This required more custom code. I wrote a custom importer that reads the wiki and cleans/reformats it in places where recommonmark just dies on them. I also made a preprocessor that not only finds orphan pages but also builds a toctree and remaps all links in all documents to their actual location on compilation. The remapper makes it a lot easier to move things around. The drawback is that every page needs to be uniquely named. Since this was already the case in the wiki, this was a good tradeoff. So with a lot of custom code the wiki eventually could port automatically.

The thing is, that even with all this processing, recommonmark doesn't support stuff like Markdown tables, so you still have to fall back to reST notation for those. And Napoleon, while doing a good job of parsing google docstrings, do not expect Markdown. So the end result is mostly markdown but we still have to fall back to reST for some things. It's probably as far as we get.

Deploying the docs

Figuring out how to build and deploy these components together was the next challenge. Sphinx' default Makefile was quite anemic and I also wanted something that regular contributors could use to test their documentation contributions easily. I ended up having to expand the Makefile quite a lot while also adding separate deploy scripts and interfaces to github actions (which we recently started using too).

Finally, the versioning. The sphinx-multiversion plugin works by extracting the branches you choose from git and running the sphinx compiler in each branch. The plugin initially had a bug with how our docs are located (not at the root of the package) but after I reported it, it was quickly fixed. The result is a static document site where you can select between the available versions in the sidebar.

I've not gotten down to trying to make LaTeX/PDF generation work yet. I'm dreading it quite a bit...

Where we are

The github wiki is now closed for external contributions. The v0.9.5 of the new documentation will pretty much be an import of the last state of the wiki with some minor cleanup (such as tables). While we'll fix outright errors in it, I don't plan to do many fixes of purely visual glitches from the conversion - the old wiki is still there should that be a problem.

The main refactoring and cleanup of the documentation to fit its new home will instead happen in v1.0. While the rough structure of this is already in place, it's very much a work in progress at this point.

Conclusions

Evennia 0.9.5 has a lot of features, but the biggest things are 'meta' changes in the project itself. After it is out, it's onward towards 1.0 again!


20 Oct 2020 3:21am GMT

19 Oct 2020

feedDjango community aggregator: Community blog posts

7 reasons Django Web Framework is Perfect for Startups

django web framework for python

If your startup is obsessed with its technology stack, then you are not alone. Every emerging CTO wants the most value-oriented programming language, scalable web framework, and expert developers. This article will leave behind the programming language and talented developers and talk about one of the best things in the technology stack for startups - […]

The post 7 reasons Django Web Framework is Perfect for Startups appeared first on BoTree Technologies.

19 Oct 2020 2:09pm GMT

16 Oct 2020

feedDjango community aggregator: Community blog posts

Django News - DjangoCon EU Videos Available - Oct 16th 2020

News

DjangoCon Europe 2020 - Videos now live

All 30 videos are now available on YouTube from this year's conference.

youtube.com

Events

PyTexas 2020

PyTexas is Oct 24th & 25th and online this year will be streamed for free or a donation. Don't miss the t-shirts which are very nice looking.

pytexas.org

Articles

How to Mock Environment Variables in PyTest

Three things most Django projects need--mocks, environment variables and PyTest--covered by Adam Johnson.

adamj.eu

Django's transaction.atomic()

It's not always as atomic as you might think!

charemza.name

Weeknotes 2020 WK 41 - OMG Timezones

Django Fellow Carlton Gibson's weekly notes on all things Python/Django, with a focus on timezone support.

noumenal.es

We need to talk about GitHub

On the current state of GitHub and mono/poly cultures.

thea.codes

Upgrading Python Homebrew packages using pip

A quick tip from Simon Willison on updating Python via Homebrew.

simonwillison.net

Prevent Unintended Data Modification With django-read-only - Adam Johnson

Tips to using the new django-read-only package, which provides a read-only mode for Django's database layer.

adamj.eu

Django log management with Elastic and Kibana

A hands-on guide to creating log management with Elasticsearch, Filebeat, and Kibana in a Django project.

koky.ir

Sponsored Link

Mystery Science Theatre 3000 with Your Friends

Privately stream movies and chat with your friends on WeeVee. Read about WeeVee's Django tech stack and request access today!

weevee.tv

Videos

DjangoCon 2020 | Choose, and choose quickly: Optimising ModelChoiceField - Carlton Gibson

Django Fellow Carlton Gibson on how to optimize and improve the performance of ModelChoiceField.

youtu.be

DjangoCon 2020 | How To Break Django: With Async - Andrew Godwin

Who better than Andrew Godwin to look at a variety of ways that asynchronous code can make you write some spectacularly nasty code, as well as the ways Django tries to save you from these terrible fates.

youtu.be

DjangoCon 2020 | A Pythonic Full-Text Search - Paolo Melchiorre

How to implement full-text search in a web service using only the latest versions of Django and PostgreSQL as well as the pros/cons vs more complex solutions based on external services.

youtu.be

DjangoCon 2020 | C is for Cookie 🍪 - Russell Keith-Magee

"This site uses cookies"... no kidding! Every site uses cookies! Russell provides a deep dive on what cookies actually are, how they work, are used/misued, and how they have changed as the modern web evolves.

youtu.be

DjangoCon 2020 | A Pony On The Move: How Migrations Work In Django 🐎 - Markus Holtermann

While migrations are widely used by almost every Django project ever since, there is little known about the internals of the migration framework. This talk looks into its components and how they are tied together.

youtu.be

DjangoCon 2020 | How to Hack a Django Website - Adam Johnson

Adam Johnson walks through some stories of common web vulnerabilities, and what they mean for Django.

youtu.be

Podcasts

Django Chat #76 - Ethical Ads with David Fischer

David is an engineer at Read the Docs where he focuses on EthicalAds.io, a developer and privacy-focused ad network. We talk about internet advertising and why much of it is not ethical, the open source code powering the ad server, and what it takes to serve tens of millions of monthly API requests.

djangochat.com

Just Django - Justin Mitchel of Coding for Entrepreneurs

Justin is an entrepreneur, coder, avid tech enthusiast, and creator of CodingForEntrepreneurs.com, which offers project-based courses on Django, Python, JavaScript, Machine Learning and many other technologies.

justdjango.com

Projects

django-waffle/django-waffle

Django Waffle is a feature flipper for Django. You can define the conditions for which a flag should be active, and use it in a number of ways.

github.com

springload/awesome-wagtail

A curated list of awesome packages, articles, and other cool resources from the Wagtail community.

github.com

oxan/djangorestframework-dataclasses

Dataclasses serializer for Django REST framework.

github.com

adenh93/django-typomatic

A simple solution for generating Typescript interfaces from your Django Rest Framework Serializers.

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

16 Oct 2020 4:00pm GMT

Running Django on DigitalOcean's App Platform

This article looks at how to deploy a Django application to DigitalOcean's App Platform.

16 Oct 2020 3:28am GMT

15 Oct 2020

feedDjango community aggregator: Community blog posts

Capped Social Network - Building SaaS #76

In this episode, I started a new project to build a different kind of social network. This social network will contain a max number of connections to encourage thoughtful choice when growing your personal network. We talked MVP features and put in the basics of a Django app. I had a wild thought to build a social network with a capped number of connection in the hope that users would choice their connections based on people that they really care about.

15 Oct 2020 5:00am GMT

A Django REST API in a Single File

I previously covered writing a Django application in a single file, for both synchronous and asynchronous use cases. This post covers the angle of creating a REST API using Django in a single file.

Undeniably, REST API's are a very common use case for Django these days. Nearly 80% of this year's Django community survey respondents said they use Django REST Framework (DRF). DRF is great for building API's and provides many of the tools you'd want in a production-ready application. But for building a very small API, we can get by solely with tools built into Django itself.

Without further ado, our example application is below. You can save it as app.py, and run it with python app.py runserver (tested with Django 3.1). An explanation follows after the code:

import os
import sys
from dataclasses import dataclass

from django.conf import settings
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponseRedirect, JsonResponse
from django.urls import path
from django.utils.crypto import get_random_string

settings.configure(
    DEBUG=(os.environ.get("DEBUG", "") == "1"),
    ALLOWED_HOSTS=["*"],  # Disable host header validation
    ROOT_URLCONF=__name__,  # Make this module the urlconf
    SECRET_KEY=get_random_string(
        50
    ),  # We aren't using any security features but Django requires this setting
    MIDDLEWARE=["django.middleware.common.CommonMiddleware"],
)


@dataclass
class Character:
    name: str
    age: int

    def as_dict(self, id_):
        return {
            "id": id_,
            "name": self.name,
            "age": self.age,
        }


characters = {
    1: Character("Rick Sanchez", 70),
    2: Character("Morty Smith", 14),
}


def index(request):
    return HttpResponseRedirect("/characters/")


def characters_list(request):
    return JsonResponse(
        {"data": [character.as_dict(id_) for id_, character in characters.items()]}
    )


def characters_detail(request, character_id):
    try:
        character = characters[character_id]
    except KeyError:
        return JsonResponse(
            status=404,
            data={"error": f"Character with id {character_id!r} does not exist."},
        )
    return JsonResponse({"data": character.as_dict(character_id)})


urlpatterns = [
    path("", index),
    path("characters/", characters_list),
    path("characters/<int:character_id>/", characters_detail),
]

app = get_wsgi_application()

if __name__ == "__main__":
    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

Neat, just 73 lines, or 63 not counting imports.

The first thing we do, following imports, is to call settings.configure() with the minimum configuration to get Django running. I covered most of these settings in my first single-file app post which I won't repeat too much here.

One extra thing we're compared to that post is using CommonMiddleware, one of Django's many "included batteries". In its default configuration it will redirect URL's not ending with a slash ("/") to those with one, useful for getting users to their intended content.

Second, we define some static data for our API to serve, using dataclasses (new in Python 3.7). These are great for storing and serving a small amount of unchanging data. At some point we'd want to move to using a database, but for our purposes it is easier to avoid setting this up.

(I've also shown my bad taste by making this a Rick and Morty character API.)

Third, we define three views:

Fourth, we map URL's to our views in the urlpatterns list.

Fifth, we create the WSGI application object, which allows us to deploy the application. For example, if we'd saved this file as app.py, we could run it on a production server with gunicorn app:app.

Sixth, we introduce manage.py style handling when the module is run as "__main__". This allows us to run the application with python app.py runserver locally.

Trying It Out

Here's a sample of using that API with httpie, a neat command-line tool for making HTTP requests.

First, hitting the index URL:

$ http localhost:8000
HTTP/1.1 302 Found
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Thu, 15 Oct 2020 21:05:09 GMT
Location: /characters/
Server: WSGIServer/0.2 CPython/3.8.5

This redirects us to /characters/ as expected. Fetching that, we see the JSON dat for both characters:

$ http localhost:8000/characters/
HTTP/1.1 200 OK
Content-Length: 101
Content-Type: application/json
Date: Thu, 15 Oct 2020 21:05:15 GMT
Server: WSGIServer/0.2 CPython/3.8.5

{
    "data": [
        {
            "age": 70,
            "id": 1,
            "name": "Rick Sanchez"
        },
        {
            "age": 14,
            "id": 2,
            "name": "Morty Smith"
        }
    ]
}

We might try fetching Morty's page:

$ http localhost:8000/characters/2
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Thu, 15 Oct 2020 21:05:19 GMT
Location: /characters/2/
Server: WSGIServer/0.2 CPython/3.8.5

Aha! We didn't add the trailing slash, so our request has been redirected. Fetching the complete URL, we see Morty's data:

$ http localhost:8000/characters/2/
HTTP/1.1 200 OK
Content-Length: 53
Content-Type: application/json
Date: Thu, 15 Oct 2020 21:05:21 GMT
Server: WSGIServer/0.2 CPython/3.8.5

{
    "data": {
        "age": 14,
        "id": 2,
        "name": "Morty Smith"
    }
}

Success!

Tests

These days I can't write a blog post without mentioning testing. We can use Django's built-in test framework to write some quick tests that cover all our endpoints.

Save this code in a file called tests.py, in the same folder as the application:

from django.test import SimpleTestCase


class AppTests(SimpleTestCase):
    def test_index(self):
        response = self.client.get('/')

        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['Location'], '/characters/')

    def test_list(self):
        response = self.client.get('/characters/')

        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.json()['data'][0],
            {"id": 1, "name": "Rick Sanchez", "age": 70},
        )

    def test_detail(self):
        response = self.client.get('/characters/1/')

        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.json()['data'],
            {"id": 1, "name": "Rick Sanchez", "age": 70},
        )

These tests use Django's test client to make requests and then assert on the response status code and content. Because we don't have a database, the tests can inherit from the faster SimpleTestCase, rather than using TestCase which adds some database management. We can run these tests using app.py like so:

$ python app.py test
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.004s

OK

Great!

Fin

I hope this has helped you figure out a way into building small API's with Django. If your API takes off, do check out Django REST Framework!

-Adam

15 Oct 2020 4:00am GMT