Django community: Community blog posts RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
Announcing Our New Django Book: Django Crash Course
Django Crash Course is a book consisting of a huge chunk of our corporate training materials. Right now we're offering the alpha version of the e-book at $9.99, which is a steal considering we used to teach corporate trainings for $3000 using the same curriculum materials. Even though there are other fantastic introductory Django books out there, this tutorial shows you how to do Django our way. Readers of this alpha version have the opportunity to help us really shape the direction of the book through their feedback, and to be credited as contributors or even technical reviewers, depending on experience and level of contribution. Django Crash Course: Covers Python 3.8 and Django 3.x is currently available as an e-book: The paperback, coil-bound, and hardcover versions are available for pre-order: Learn more and order the course-in-a-book here: https://www.roygreenfeld.com/collections/two-scoops-press/products/django-crash-course -
"Where did we get lucky?"
Retrospectives are probably the most important software development practice. They build a culture of continuous improvement. We may fail, but we’ll learn and do better next time. (Or, at, least, fail differently.) The most common retrospective practice revolves around some variation of these three questions: “What went well?” “What could have gone better?” “What we should we differently next time?” I want to suggest adding a fourth question: -
How to use PyMySQL with Django
Django provides MySQL and MariaDB suport out of the box. It supports the mysqlclient library as its DB API driver to connect. mysqlclient is a Python 3 compatible fork of the original Python MySQL driver, MySQLdb. It still provides a Python module called MySQLdb. On install, it compiles against either the MariaDB client library or MySQL client library - whichever one you have installed. Compiling against the C extension can be frustrating: It requires not only the MariaDB/MySQL client library, but also OpenSSL. Obtaining the C extension libraries might not be trivial on some platforms, such as AWS Lambda. After install, Pip’s wheel cache will store the one compiled version, so if you swap to another C library (e.g. MySQL -> MariaDB), the wheel might not work any more. If these are blockers for you, an alternative is to use the PyMySQL library. It’s a pure Python DB API driver - no C compilation necessary! It’s also made by the same developers as mysqlclient and is better maintained at this point. Django doesn’t officially support it, but PyMySQL ships with an (undocumented) compatibility install that can help you use it. It’s an “at your own risk” feature. I’ve done this … -
How I'm testing in 2020
Once upon a time I wrote a bit about testing, specifically how I was organizing and testing my open-source Django apps. It’s been a while since that post, though, and the calendar has even flipped over to a new penultimate digit in the year number, so it’s worth revisiting to go over what’s changed in how I do things and what’s stayed the same. And since I do maintain a couple things that aren’t … Read full entry -
My reflections on programming languages I have worked with during my career.
I've played and worked with multiple programming languages over my 15-year long career in development (and a bit before, when I studied at school and university). Every language I touched left a piece of knowledge or a feeling in me. So I decided to remember them all and try to … Read now -
Common Celery Issues on Django Projects
Here are some issues I’ve seen crop up several times in Django projects using Celery. They probably apply to other web frameworks and other task queues, I simply haven’t used others so much. 1. Enqueueing Data Rather Than References If you duplicate data from your database in your task arguments, it can go stale in the queue before the task executes. I can’t describe this more completely than Celery’s documentation on task state. See the description and example there. This is not so easy to do accidentally on Celery since version 4, which changed the default serializer from Pickle to JSON. (If you’re not sure what serializer you’re using, check your settings.) But, it is still possible to enqueue data rather than references. For example, imagine you enqueue an email with a 1 minute delay, using the user’s email address in the task arguments, rather than ID. If the user changes their email address before the ask runs, the email gets sent to the wrong address. 2. Enqueueing Tasks Within Database Transactions Although you might think Celery is for executing tasks “later/eventually,” it can execute them quickly too! If you enqueue a task from within a database transaction, it might … -
Speeding up Django pagination
I assume you have already read Optimizing the Django Admin Paginator. If not, this is basically the take-away from that article: class InfinityPaginator(Paginator): @property def count(self): return 99999999999 class MyAdmin(admin.ModelAdmin): paginator = InfinityPaginator show_full_result_count = False Though the article has a trick with using a statement_timeout, I think it's pointless. In the real world you should expect to get that overt 99999999999 count all over the place. Unless you have some sort of toy project it's very likely your database will be under load. Add some user/group filtering and you'll be always hit the time limit. What if you could make the count more realistic, but still cheap? Using a random number would be too inconsistent. Strangely enough someone decided that it's a good idea to put a count estimate idea in the postgresql wiki and, for reasons I decided to see how hard is to implement it in django, in a somewhat generalized fashion From a series of "Just because you can, you have to try it!", behold [1]: class EstimatedQuerySet(models.QuerySet): estimate_bias = 1.2 estimate_threshold = 100 def estimated_count(self): if self._result_cache is not None: return self.count() try: qs = self.model._base_manager.all() compiler = self.query.get_compiler('default') where, params = compiler.compile(self.query.where) qs = … -
Speeding up Django pagination
I assume you have already read Optimizing the Django Admin Paginator. If not, this is basically the take-away from that article: class InfinityPaginator(Paginator): @property def count(self): return 99999999999 class MyAdmin(admin.ModelAdmin): paginator = InfinityPaginator show_full_result_count = False Though the article has a trick with using a statement_timeout, I think it's pointless. In the real world you should expect to get that overt 99999999999 count all over the place. Unless you have some sort of toy project it's very likely your database will be under load. Add some user/group filtering and you'll be always hit the time limit. What if you could make the count more realistic, but still cheap? Using a random number would be too inconsistent. Strangely enough someone decided that it's a good idea to put a count estimate idea in the postgresql wiki and, for reasons I decided to see how hard is to implement it in django, in a somewhat generalized fashion From a series of "Just because you can, you have to try it!", behold [1]: class EstimatedQuerySet(models.QuerySet): estimate_bias = 1.2 estimate_threshold = 100 def estimated_count(self): if self._result_cache is not None: return self.count() try: qs = self.model._base_manager.all() compiler = self.query.get_compiler('default') where, params = compiler.compile(self.query.where) qs = … -
Django News - Issue 8 - Jan 31st 2020
News DjangoCon US 2020 Announced DjangoCon US is returning to San Diego from October 11-17th. More details to come. djangocon.us Django Day Copenhagen 2020 - Call for Proposals A one-day Django conference on April 17th, 2020. The call for proposals is now live. Submit before February 2nd! djangoday.dk Announcing CockroachDB for Django ORM A Django package for using CockroachDB, an open-source distributed database. cockroachlabs.com Articles Demos, Prototypes, and MVPs Django co-creator Jacob Kaplan-Moss concisely covers the difference between three commonly misused terms: demos, prototypes, and MVPs. jacobian.org All You Need To Know About Prefetching in Django How to use Prefetch to speed up queries in Django hakibenita.com URLs Lead the Way A detailed look at how Django process URL requests internally. mattlayman.com Podcasts Django Chat Podcast - GeoDjango with Anna Kiefer GeoDjango is a powerful built-in contrib module that turns Django into a world-class geographic Web framework. djangochat.com Projects skorokithakis/django-tokenauth: Django authentication backend that uses tokens sent over email. Django-tokenauth is a simple, passwordless authentication method based on a one-time token sent over email which does not require user registration. github.com django-weasyprint: A Django class-based view generating PDF resposes using WeasyPrint WeasyPrint turns HTML into beautiful PDF pages. This project … -
Disabling Atomic Transactions In Django Test Cases
TestCase is the most used class for writing tests in Django. To make tests faster, it wraps all the tests in 2 nested atomic blocks. In this article, we will see where these atomic blocks create problems and find ways to disable it. Select for update Django provides select_for_update() method on model managers which returns a queryset that will lock rows till the end of transaction. def update_book(pk, name): with transaction.atomic(): book = Book.objects.select_for_update().get(pk=pk) book.name = name book.save() When writing test case for a piece of code that uses select_for_update, Django recomends not to use TestCase as it might not raise TransactionManagementError. Threads Let us take a view which uses threads to get data from database. def get_books(*args): queryset = Book.objects.all() serializer = BookSerializer(queryset, many=True) response = serializer.data return response class BookViewSet(ViewSet): def list(self, request): with ThreadPoolExecutor() as executor: future = executor.submit(get_books, ()) return_value = future.result() return Response(return_value) A test which writes some data to db and then calls this API will fail to fetch the data. class LibraryPaidUserTestCase(TestCase): def test_get_books(self): Book.objects.create(name='test book') self.client = APIClient() url = reverse('books-list') response = self.client.post(url, data=data) assert response.json() Threads in the view create a new connection to the database and they don't see … -
Disabling Atomic Transactions In Django Test Cases
TestCase is the most used class for writing tests in Django. To make tests faster, it wraps all the tests in 2 nested atomic blocks. In this article, we will see where these atomic blocks create problems and find ways to disable it. Select for update Django provides select_for_update() method on model managers which returns a queryset that will lock rows till the end of transaction. def update_book(pk, name): with transaction.atomic(): book = Book.objects.select_for_update().get(pk=pk) book.name = name book.save() When writing test case for a piece of code that uses select_for_update, Django recomends not to use TestCase as it might not raise TransactionManagementError. Threads Let us take a view which uses threads to get data from database. def get_books(*args): queryset = Book.objects.all() serializer = BookSerializer(queryset, many=True) response = serializer.data return response class BookViewSet(ViewSet): def list(self, request): with ThreadPoolExecutor() as executor: future = executor.submit(get_books, ()) return_value = future.result() return Response(return_value) A test which writes some data to db and then calls this API will fail to fetch the data. class LibraryPaidUserTestCase(TestCase): def test_get_books(self): Book.objects.create(name='test book') self.client = APIClient() url = reverse('books-list') response = self.client.post(url, data=data) assert response.json() Threads in the view create a new connection to the database and they don't see … -
Episode 2 - Enter With URLs
On this episode, we discuss Django’s front door, URLs. We talk about what URLs are, how to build them in Django, and the functions Django provides to work with URLs. Listen at djangoriffs.com. What’s a URL? A URL is a Uniform Resource Locator. It is the full address that goes into a browser. Consider https://www.mattlayman.com/django-riffs/. Here are the parts: Scheme, https:// Domain name: Top Level Domain (TLD), com Domain, mattlayman Subdomain, www Path or route, /django-riffs/ URLconf Every route for Django to handle goes into a URL configuration, URLconf for short and in the documentation. -
Episode 1 - Get To Know Django
Welcome to the show notes for the first episode of Django Riffs! Django Riffs is a podcast for learning web application development in Python using the Django web framework. Listen at djangoriffs.com. Who Is This For? This podcast is for absolute Django beginners. No prior knowledge of Django or web development is expected. Experienced users may learn something new or get a good refresher from topics they might have missed in the documentation. -
GeoDjango - Anna Kiefer
Weekly DjangoChat newsletterAnna Kiefer personal siteDjangoCon US 2018 - The Power of GeoDjango by Anna KieferGeoDjango docsPostGIS -
How to deploy Django project to Dokku with Docker
In this post, I will talk about how to deploy Django project to Dokku with Docker. -
How to deploy Django project to Dokku with Docker
In this post, I will talk about how to deploy Django project to Dokku with Docker. -
Moving to Django 3.0's Field.choices Enumeration Types
One of the headline features of Django 3.0 is its Enumerations for model field choices. They’re a nicer way of defining and constraining model Field.choices. Previously, Django recommended defining some ‘constants’ on your model class to feed into choices. You would add these as separate class variables and combine them into a list of choices paired with their display strings: from django.db import models class Book(models.Model): UNPUBLISHED = 'UN' PUBLISHED = 'PB' STATUS_CHOICES = [ (UNPUBLISHED, 'Unpublished'), (PUBLISHED, 'Published'), ] status = models.CharField( max_length=2, choices=STATUS_CHOICES, default=UNPUBLISHED, ) Then your other could use those constants, for example: unpublished_books = Book.objects.filter(status=Book.UNPUBLISHED) If you wanted to use the same set of values for multiple models, you would probably move to the module level: from django.db import models UNPUBLISHED = 'UN' PUBLISHED = 'PB' STATUS_CHOICES = [ (UNPUBLISHED, 'Unpublished'), (PUBLISHED, 'Published'), ] class Book(models.Model): status = models.CharField( max_length=2, choices=STATUS_CHOICES, default=UNPUBLISHED, ) class Pamphlet(models.Model): status = models.CharField( max_length=2, choices=STATUS_CHOICES, default=PUBLISHED, ) This leaves a bunch of constants related only by their position in the class or module. It’s a bit against The Zen of Python’s final edict: Namespaces are one honking great idea – let’s do more of those! It also leaves us missing some … -
Guest Post: Sending Emails with Django
This is a guest post by Mailtrap.io team. The original post on Sending emails with Django was published at Mailtrap's blog. Some time ago, we discovered how to send an email with Python using smtplib, a built-in email module. Back then, the focus was made on the delivery of different types of messages via SMTP server. Today, we prepared a similar tutorial but for Django. This popular Python web framework allows you to accelerate email delivery and make it much easier. And these code samples of sending emails with Django are going to prove that. A simple code example of how to send an email Let's start our tutorial with a few lines of code that show you how simple it is to send an email in Django. Import send_mail at the beginning of the file from django.core.mail import send_mail And call the code below in the necessary place. send_mail( "That's your subject", "That's your message body", "from@yourdjangoapp.com", ["to@yourbestuser.com"], fail_silently=False,) These lines are enclosed in the django.core.mail module that is based on smtplib. The message delivery is carried out via SMTP host, and all the settings are set by default: EMAIL_HOST: "localhost"EMAIL_PORT: 25EMAIL_HOST_USER: (Empty string)EMAIL_HOST_PASSWORD: (Empty string)EMAIL_USE_TLS: FalseEMAIL_USE_SSL: False You … -
Django News - Issue 7 - Jan 24th 2020
News Announcing the Django Software Foundation Store: Featuring custom t-shirts, prints, and more The Django Software Foundation, the non-profit behind Django, has launched an official merchandise store. All proceeds benefit Django. threadless.com Have you checked out the Django Forum? The Django Forum is a place for discussing the Django framework and applications and projects that use it. The goal of the forum is to be a useful addition for lower-impact, more real-time discussion than Django's mailing lists. djangoproject.com Amazon Lightsail expands selection of instance blueprints Lightsail is Amazon’s VPS service; a “blueprint” is a pre-configured instance. Like a DigitalOcean “droplet”. So this is a pre-configured Django instance. amazon.com Sponsored Links Test-Driven Development with Django, Django REST Framework, and Docker From the popular TestDriven.io site, an updated course on how to build, test, and deploy a Django app with Docker, Pytest, and Django REST Framework! testdriven.io Articles Feature Checking versus Version Checking - Adam Johnson An analysis of whether to check for features in a new version of, say, Django, or to explicitly check the version number instead. Well-written and useful. adamj.eu How to create a Django project from a template A Django project template is the natural solution when the … -
Flask v Django: Bare to Production ~ Code Showdown
Hey there, In this video, I... -
OpenCV & Python: Exact Faces with a REST API
We're going to build a REST AP... -
Security Releases
Weekly DjangoChat NewsletterDjango News newsletterdjango-announce Google groupOfficial Django blog -
Introducing Django ClearCache - allows to clear cache via admin UI or command line
I've been working with the Django cache recently. And while Django has exceptional caching capabilities, I was surprised to find out that it doesn't provide a simple way to manually clear a cache. I checked online and found a couple of clear cache packages for Django, but all of them … Read now -
Django's Field Choices Don't Constrain Your Data
This post is a PSA on the somewhat unintuitive way Field.choices works in Django. Take this Django model definition: from django.db import models class Status(models.TextChoices): UNPUBLISHED = 'UN', 'Unpublished' PUBLISHED = 'PB', 'Published' class Book(models.Model): status = models.CharField( max_length=2, choices=Status.choices, default=Status.UNPUBLISHED, ) def __str__(self): return f"{self.id} - {Status(self.status).label}" If we open up a shell to manipulate them, we can easily create a Book with a given status choice: $ python manage.py shell # with ipython installed ... In [1]: from core.models import Status, Book In [2]: Book.objects.create(status=Status.UNPUBLISHED) Out[2]: <Book: 1 - Unpublished> The choices list constrains the value of status during model validation in Python: In [3]: book = Book.objects.get(id=1) In [4]: book.status = 'republished' In [5]: book.full_clean() --------------------------------------------------------------------------- ValidationError Traceback (most recent call last) <ipython-input-7-e64237e0a92a> in <module> ----> 1 book.full_clean() .../django/db/models/base.py in full_clean(self, exclude, validate_unique) 1220 1221 if errors: -> 1222 raise ValidationError(errors) 1223 1224 def clean_fields(self, exclude=None): ValidationError: {'status': ["Value 'republished' is not a valid choice."]} This is great for ModelForms and other cases using validation. Users can’t select invalid choices and get messaging about what’s wrong. Unfortunately, it’s still easy for us, as developers, to write this invalid data to the database: In [6]: book.save() Woops! It’s … -
Having some fun with Python
The other day on a Slack I hang out in, someone posted an amusing line of Python code: port = "{port}:{port}".format(port=port) If it’s not clear after the inevitable Swedish-chef-muppet impression has run through your mind, this string-formatting operation will replace the contents of port with a string containing two copies of whatever was in port, separated by a colon. So if port was "foo", now it will … Read full entry