20 Jul 2018

feedDjango community aggregator: Community blog posts

My Todoist Setup

What is this?

Like a lot of others my first experience with todo managers was actually Wunderlist. At the time I was a college student and it was great for helping keep track of projects and other assignments. I never really dove to deep into GTD or any real kind of process then. It was just a bunch of tasks messily thrown in one project with dates attached. As college went on and I started freelancing I quickly realized I needed more help. That's when I started working on this system.

Why Todoist?

Eventually Microsoft bought Wunderlist. A truly sad day for Wunderlist fans, as Microsoft has a slight history of destroying things they buy. This gave me a good reason to find a new todo manager though. I looked at everything available (and still spend to much time looking at new ones now!), but finally settled on Todoist Premium.I love Todoist minimal interface, managers like Any.do and Asana just had to much clutter. Todoist also offers a really brilliant input interface as well. When adding tasks to Todoist you can add information (Projects, tags, due date, priority, etc) about the task just by typing, no need for clicking or special key bindings! This also holds true for the mobile interface. At the same time Todoist offers an extremely full featured tagging and filtering system. Unfortunately these two features are only available in Premium though. Due to all of this I ended up choosing Todoist as my task manager.

Why It Started

Over the years my simple process of just adding everything to `Inbox` with a due date just wasn't cutting it, so I started adding tags to help organize everything. This had some draw backs through, mainly that nothing organized still. I had all the tasks written out, I had them tagged with semi-important bits of information, I had due dates, but there was no consistence behind anything. I was definitely doing better, getting more stuff done, but I was still forgetting a lot too. So I decided to make some rules and stick with them.

The Process

I'm not going to say this is the best way to manage your tasks, it's just what works for me. It's a mish-mash everything I've read about and strip down to fit specifically what I need. So no guarantee that it'll work for you, but hopefully it helps in some way!

Tags

Todoist and GTD call these `contexts`, I just call them tags. Tags are the real foundation of this system.Tags can be separated into 4 categories, every task should have only one tag out of each category, making 4 tags total. The tags are as follows:

Timing

These tags will help figure out when a task can be started or when it is due. This tag also uses the builtin feature of `due date` for some of the tags.

Type

These tags help figure out what the task needs to be completed.

** Imagine you have an essay due, you might have a few tasks like so:

Each of these items are individual tasks separate from each other, but still related working towards a single goal. In this instance it might help to keep the tasks together, and that is what @process is for:

Location

Location tags help organize where a task can be completed. This will help later with filters when we want to view lists for at home or on the job. Everyone's locations will change, but here are a few I use daily:

Difficulty

These are actually optional for the most part. I use these tags to denote how hard a task will be to complete. I find it makes it easier to get started in my routine if I can quickly pick something easy to do.

Filters

Todoist ships with a really interesting query system that when used correctly sets Todoist apart from all of the competitors, in my opinion. What this allows us to do is use the tags above to categorize all of our tasks, now we can build custom lists. This also means that all new tasks added (as long as they follow the rules of the tags above) will always show up on the right lists, at the right time! No more browsing through lists looking for tasks to do, just write a filter!

This system uses one main template that you can change based on location:

Actionable Now

@waiting-for & (overdue|today), ((@next ) & (@action | @appointment | @process))

This filter will show every task tagged with @waiting-for that has its `due date:` set to today or earlier. It will also, in a separate list show all tasks tagged with @next and one of the following: @action, @appointment, or @proces

If you followed the rules for the tags above, you should see every task that is due or ready to be worked on.

This Week

(7 days | overdue) & @waiting-for, @next & (@action | @appointment | @process)

This filter is basically the same as `Actionable Now`, the only difference is that you will get a list of the next 7 days, instead of just today.

Appointments Today

@appointment & (today | overdue)

This filter will show every task that is sync'd in from Google Calendar that is due today or earlier.

@location Today

(today | overdue) & @location & (@action | @appointment | @process)), @next & @location & (@action | @appointment | @process)

This filter can be customized by replacing @location with whatever location tag you want to use. This will display a list of all tasks that are tagged with the @location, is tagged with one of the following @action, @appointment, or @process, and is due today or earlier or tagged with @now. This should allow you to see all the tasks that are ready to start today, at the location you pick.

Overview

@waiting-for & 30 days

This filter just gives a quick overview of the next month.

No Tags

(no date & no labels)

This filter is just kind of a safety net, if anything shows up in it, make sure it's tagged correctly.

Working in the process

There isn't really a lot to work. As tasks come in, make sure they are tagged correctly. If it's done right you will have a number of filters that provide a simplified list of exactly what you need to work on.

What about Projects?

I've never really worried much about Projects. I've always used the following:

This just groups the tasks together by project (which I prefer), but it doesn't really matter how you organize the projects, you'll rarely be looking at them.

Like My Work?

I publish everything 3-4 days early on my personal blog. I talk about everything from productivity and apps to programming and algorithms! Make sure to check it out and be the first to see my articles!

20 Jul 2018 12:50am GMT

12 Jul 2018

feedDjango community aggregator: Community blog posts

Web Development Tutorial: PHP vs. Python & Django

In this tutorial, we'll compare PHP and Python (Django) for web development then we'll see how to create simple demo apps with PHP and Python (using Django one of the most popular frameworks for Python).

PHP is a programming languages which has a sole purpose to create back-end web applications while Python is a general purpose programming language that can be used for web development and other fields such as data science and scientific calculations so our comparison will be between PHP and Python equipped with a web framework. The most popular web frameworks for Python are Django and Flask with Django being more popular than Flask.

In order to compare PHP with Django we need to consider many factors such as:

More experienced developers have more potential to quickly learn a new programming language than beginners

Both PHP and Python are popular languages. They are both extremely popular among web developers and power most of the websites on the web today.

Let's take a look at these three factors:

Popularity

Both PHP (dominates 80% of the market)and Python are popular languages, but for web development PHP is more popular than the most popular framework for web development in Python which is Django.

Popular websites like Facebook and Wikipedia are built in PHP.

Also many popular website and apps that you use daily are using Python. For example, YouTube, Reddit, Pinterest and Instagram etc.

Learning Curve

A learning curve describes how easy or difficult the programming language is? Which simply means how easy to become familiar with the programming syntax and to start implementing requirements using the language.

Python is a lot easier than PHP since it has clear and readable syntax so for a beginner developer it would be easier to learn. Many universities in the world are using Python as the first programming language for their students.

On the other hand, PHP has a less readable and confusing syntax which makes the learning process for a beginner developer more difficult, but to be fair, once your learn and become familiar with the syntax you can start creating websites with the same ease.

Batteries and libraries

PHP has many libraries, frameworks and CMSs than Python. For example WordPress, the most popular CMS platfrom which everyone is using create a website is built in PHP. Also popular eCommerce solutions like Magento and WooCommerce are developed in PHP. Python with Django also offers many libraries a quite a few CMSs but not as equal to PHP.

Now let's see a list of pros and cons for both Python (and as a result Django) and PHP:

Let's start with Python pros and cons:

The pros and cons of PHP:

Conclusion

The best recommendation, for beginner developers is to try out both languages and then choose the one they are more comfortable with. But you need also to consider the job market and learning resources. Python is easier to learn while PHP offers you a better chance for quickly getting a job and has more learning resources around the world.

12 Jul 2018 5:00am GMT

09 Jul 2018

feedDjango community aggregator: Community blog posts

Pipenv Virtual Environments for Python

`Pipenv` is an **amazing** rep...

09 Jul 2018 10:46pm GMT

Changing Default Python 3 in Terminal for Mac OS

Sometimes Python gets upgraded...

09 Jul 2018 10:46pm GMT

Equivalents in Python and JavaScript. Part 4

In the last three parts of the series of articles about analogies in Python and JavaScript, we explored lots of interesting concepts like serializing to JSON, error handling, using regular expressions, string interpolation, generators, lambdas, and many more. This time we will delve into function arguments, creating classes, using class inheritance, and defining getters and setters of class properties.

Function arguments

Python is very flexible with argument handling for functions: you can set default values there, allow a flexible amount of positional or keyword arguments (*args and **kwargs). When you pass values to a function, you can define by name to which argument that value should be assigned. All that in a way is now possible in JavaScript too.

Default values for function arguments in Python can be defined like this:

from pprint import pprint

def report(post_id, reason='not-relevant'):
pprint({'post_id': post_id, 'reason': reason})

report(42)
report(post_id=24, reason='spam')

In JavaScript that can be achieved similarly:

function report(post_id, reason='not-relevant') {
console.log({post_id: post_id, reason: reason});
}

report(42);
report(post_id=24, reason='spam');

Positional arguments in Python can be accepted using the * operator like this:

from pprint import pprint

def add_tags(post_id, *tags):
pprint({'post_id': post_id, 'tags': tags})

add_tags(42, 'python', 'javascript', 'django')

In JavaScript positional arguments can be accepted using the ... operator:

function add_tags(post_id, ...tags) {
console.log({post_id: post_id, tags: tags});
}

add_tags(42, 'python', 'javascript', 'django');

Keyword arguments are often used in Python when you want to allow a flexible amount of options:

from pprint import pprint

def create_post(**options):
pprint(options)

create_post(
title='Hello, World!',
content='This is our first post.',
is_published=True,
)
create_post(
title='Hello again!',
content='This is our second post.',
)

A common practice to pass multiple optional arguments to a JavaScript function is through a dictionary object, for example, options.

function create_post(options) {
console.log(options);
}

create_post({
'title': 'Hello, World!',
'content': 'This is our first post.',
'is_published': true
});
create_post({
'title': 'Hello again!',
'content': 'This is our second post.'
});

Classes and inheritance

Python is an object-oriented language. Since ECMAScript 6 standard support, it's also possible to write object-oriented code in JavaScript without hacks and weird prototype syntax.

In Python you would create a class with the constructor and a method to represent its instances textually like this:

class Post(object):
def __init__(self, id, title):
self.id = id
self.title = title

def __str__(self):
return self.title

post = Post(42, 'Hello, World!')
isinstance(post, Post) == True
print(post) # Hello, World!

In JavaScript to create a class with the constructor and a method to represent its instances textually, you would write:

class Post {
constructor (id, title) {
this.id = id;
this.title = title;
}
toString() {
return this.title;
}
}

post = new Post(42, 'Hello, World!');
post instanceof Post === true;
console.log(post.toString()); // Hello, World!

Now we can create two classes Article and Link in Python that will extend the Post class. Here you can also see how we are using super to call methods from the base Post class.

class Article(Post):
def __init__(self, id, title, content):
super(Article, self).__init__(id, title)
self.content = content

class Link(Post):
def __init__(self, id, title, url):
super(Link, self).__init__(id, title)
self.url = url

def __str__(self):
return '{} ({})'.format(
super(Link, self).__str__(),
self.url,
)

article = Article(1, 'Hello, World!', 'This is my first article.')
link = Link(2, 'DjangoTricks', 'https://djangotricks.blogspot.com')
isinstance(article, Post) == True
isinstance(link, Post) == True
print(link)
# DjangoTricks (https://djangotricks.blogspot.com)

In JavaScript the same is also doable by the following code:

class Article extends Post {
constructor (id, title, content) {
super(id, title);
this.content = content;
}
}

class Link extends Post {
constructor (id, title, url) {
super(id, title);
this.url = url;
}
toString() {
return super.toString() + ' (' + this.url + ')';
}
}

article = new Article(1, 'Hello, World!', 'This is my first article.');
link = new Link(2, 'DjangoTricks', 'https://djangotricks.blogspot.com');
article instanceof Post === true;
link instanceof Post === true;
console.log(link.toString());
// DjangoTricks (https://djangotricks.blogspot.com)

Class properties: getters and setters

In object oriented programming, classes can have attributes, methods, and properties. Properties are a mixture of attributes and methods. You deal with them as attributes, but in the background they call special getter and setter methods to process data somehow before setting or returning to the caller.

The basic wireframe for getters and setters of the slug property in Python would be like this:

class Post(object):
def __init__(self, id, title):
self.id = id
self.title = title
self._slug = ''

@property
def slug(self):
return self._slug

@slug.setter
def slug(self, value):
self._slug = value

post = new Post(1, 'Hello, World!')
post.slug = 'hello-world'
print(post.slug)

In JavaScript getters and setters for the slug property can be defined as:

class Post {
constructor (id, title) {
this.id = id;
this.title = title;
this._slug = '';
}

set slug(value) {
this._slug = value;
}

get slug() {
return this._slug;
}
}

post = new Post(1, 'Hello, World!');
post.slug = 'hello-world';
console.log(post.slug);

The Takeaways

As you might have noticed, I am offering a cheat sheet with the full list of equivalents in Python and JavaScript that you saw here described. At least for me, it is much more convenient to have some printed sheet of paper with valuable information next to my laptop, rather than switching among windows or tabs and scrolling to get the right piece of snippet. So I encourage you to get this cheat sheet and improve your programming!

Get the Ultimate Cheat Sheet of Equivalents in Python and JavaScript

Use it for good!


Cover photo by Andre Benz

09 Jul 2018 12:00pm GMT

08 Jul 2018

feedDjango community aggregator: Community blog posts

Pipenv Tutorial for Django Developers

Pipenv is the new officially recommended packaging tool for Python which is similar to modern package managers like NPM (Node.js) or Composer (PHP). Pipenv solves common problems, most Python developers, encounter in the typical workflow using pip and virtualenv or venv.

This tutorial will teach you to use Pipenv for managing Python dependencies and how to use the traditional existing tools, such as Pip and virtualenv, with Pipenv.

Pipenv Tutorial for Django Developers: Pipenv vs. Pip vs. virtualenv vs. venv

Pipenv vs. Pip vs. Virtualenv vs. Venv

When working with Python projects you usually use a requirements.txt and Pip to install the packages automatically (pip install -r requirements.txt) on your development machine or later on your production machine.

An example requirements.txt looks like:

Django
distribute
dj-database-url
psycopg2
wsgiref

Each line contains a dependency that Pip will install, either globally or in a virtual environment if it's activated.

We didn't specify the required versions which will install the latest versions of the wanted packages. Now, imagine that you are using this requirements file for a production environment after a while in development. This may present some problems if the newer versions have breaking changes.

You can solve the issue by adding versions (or pinning requirements) so Pip will install the same versions in production: text Django==1.4.1 distribute==0.6.27 dj-database-url==0.2.1 psycopg2==2.4.5 wsgiref==0.1.2

You may think this is going to solve your issues but is that true? Not always, because even if the requirements are determined, these packages have other dependencies which Pip will install too and if their versions are not pinned then you ended up installing the latest versions of the dependencies of your project's dependencies which may have breaking changes.

Now, how to replicate the same environment in your production environment? You can, actually, use pip freeze > requirements.txt which will produce a requirements file will all dependencies and the exact versions used in your development environment. Now, doesn't that solve our earlier issues?

In one way, Yes but this will results in other issues.

By pinning your project dependencies, you make sure you your project doesn't break when it's deployed on a production machine. Now that you've pinned the exact versions of every dependency that your project use, you need also to update these versions, manually, when it's necessary especially for patching any discovered security issues that don't have any breaking changes. This is not always convenient.

Here comes Pipenv! Pipenv relives you from manually updating the versions of sub-dependencies but in the same time allows you to have deterministic versions of your project's dependencies. So you can have the latest versions of dependencies and sub-dependencies as long as they don't introduce any breaking changes.

Multiple Project with Different Versions of Dependencies

Python is usually installed system-wide by users. In most cases when you are just using Python for running some tools you will be ok with ths setup but for developers, especially if they are working with multiple Python projects, usually, using different versions of packages you will have a hard time when switching between projects. The solution is using virtual environments (virtualenv for Python 2 or venv for Python 3) which provides isolated environments with their own python binaries and dependencies.

But since the solution already exist? What does Pipenv provide?

Pipenv includes built in support for virtual environments so once you've installed Pipenv, you don't need to install virtualenv or venv which, in many cases, results in headache for developers.

Also Pipenv allow you to specify Python 2 or Python 3 using a switch for your virtual environment.

Pipenv vs Pip Dependency Resolver

Pip itself doesn't provide dependency resolution, to avoid conflicts when many dependencies require different versions of the same dependency, so you have to explicitly specify the range for wanted versions in requirements.txt. For example

packageC >=1.0,<=2.0
packageA
packageB 

Here packageA has a requirement for a version >= 1.0 for packageC and packageB needs a version <= 2.0 of packageC. Without specifying the range Pip will fail install the required version.

You can refer to this open issue for more information.

Pipenv is smart enough to figure out the versions of the sub dependencies that meet the requirements without explicitly specifying them.

Getting Started with Pipenv with Django Example

Now that we've seen the issues pipenv solves, let's how to get started using pipenv for creating a virtual environment for a Django project and installing the dependencies. Actually this tutorial is a part of a series of tutorials to use Django with modern front-end frameworks and libraries such as Angular, React and Vue.

First, you'll need to install pipenv using pip:

$ pip install pipenv

This will install pipenv system-wide. After installing pipenv you can now stop using pip and start using pipenv which uses pip and virtualenv or venv behind the curtains.

In my system (Ubuntu 16) I got this error:

Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/usr/bin/easy_install' Consider using the --user option or check the permissions.

This is due because I'm installing the pipenv to a system-wide folder which I don't have permissions to write to.

There ate three options to generally solve that type of errors:

I'm using the second option:

python -m pip install --user pipenv

Pipenv makes use of two additional files that replace requirements.txt which are Pipfile and Pipfile.lock (the file responsible for producing deterministic builds).

Let's start by spawning a shell with a virtual environment where we can do all the work related to our current project. Run the following command from your terminal:

$ pipenv shell --three

This will create a virtual environment This is our example Pipenv file in a default location (usually the home folder) for all created virtual environments.

The --three option allow us to specify the version of Python. In this case we want Python 3. For Python 2 use --two. If you don't specify the version, the default one will be used.

You can also provide a specific version like 3.6 with the --python option. For example --python 3.6.

You'll get something similar to this output:

Creating a virtualenv for this project...
Pipfile: /home/ahmed/Desktop/djangoreactdemo/backend/Pipfile
Using /usr/bin/python3.5m (3.5.2) to create virtualenv...
⠋Running virtualenv with interpreter /usr/bin/python3.5m
Using base prefix '/usr'
New python executable in /home/ahmed/.local/share/virtualenvs/backend-mJ9anpjL/bin/python3.5m
Also creating executable in /home/ahmed/.local/share/virtualenvs/backend-mJ9anpjL/bin/python
Installing setuptools, pip, wheel...done.
Setting project for backend-mJ9anpjL to /home/ahmed/Desktop/djangoreactdemo/backend

Virtualenv location: /home/ahmed/.local/share/virtualenvs/backend-mJ9anpjL
Launching subshell in virtual environment…

Also the virtual environment will be activated.

Pipenv tutorial

Next, we can install our dependencies. Let's start with Django

$ pipenv install django

This will install the latest version of Django.

Next, let's install Django REST framework

$ pipenv install djangorestframework

Finally let's install django-cors-headers package for easily enabling CORS in our Django project

$ pipenv install django-cors-headers

After installing the required packages for our project we can inspect Pipfile. This is the content:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]

[packages]
django = "*"
djangorestframework = "*"
django-cors-headers = "*"

[requires]
python_version = "3.5"

The Pipfile uses TOML for syntax. And contains different sections such as:

Create a Django Project

Now navigate to where you want to create your Django project and run the following command to generate a new project named backend:

$ django-admin.py startproject backend

This will create a project with this structure

.
├── backend
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

You can migrate your database with:

$ python manage.py migrate

This will create a database.sqlite file inside your project's root folder and you'll get a similar output:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

Pipenv tutorial

Finally serve your project using the following command:

$ python manage.py runserver

Now, you can visit your web application from http://127.0.0.1:8000/:

Pipenv tutorial with Django

Using Pipenv with Existing Projects

For most cases, we'll be using an existing Django project from our front-end tutorials so you'll need to clone a project from GitHub which uses pipenv. In this case, you only need to spawn a shell and install packages from Pipfile or Pipfile.lock using the following command:

$ pipenv install --dev

This will use Pipfile.lock to install packages.

Pipenv tutorial with django

Conclusion

Pipenv is now the official package manager for Python. If you are still using pip, virtualenv or venv for your Python projects then I recommend to start making the switch. Migrating an existing project to use pipenv is very straightforward. You can follow the same steps in this tutorial for legacy projects that use a requirements.txt and run pipenv install which will automatically detect the requirements.txt file and convert it to a Pipfile.

08 Jul 2018 5:00am GMT

06 Jul 2018

feedDjango community aggregator: Community blog posts

Equivalents in Python and JavaScript. Part 3

This is the 3rd part of 4-article series about analogies in Python and JavaScript. In the previous parts we covered a large part of the traditional Python 2.7 and JavaScript based on the ECMAScript 5 standard. This time we will start looking into Python 3.6 and JavaScript based on the ECMAScript 6 standard. ECMAScript 6 standard is pretty new and supported only the newest versions of browsers. For older browsers you will need Babel to compile your next-generation JavaScript code to the cross-browser-compatible equivalents. It opens the door to so many interesting things to explore. We will start from string interpolation, unpacking lists, lambda functions, iterations without indexes, generators, and sets!

Variables in strings

The old and inefficient way to build strings with values from variables is this concatenation:

name = 'World'
value = 'Hello, ' + name + '!\nWelcome!'

This can get very sparse and difficult to read. Also it is very easy to miss whitespaces in the sentence around variables.

Since Python version 3.6 and JavaScript based on the ECMAScript 6 standard, you can use so called string interpolation. These are string templates which are filled in with values from variables.

In Python they are also called f-string, because their notation starts with letter "f":

name = 'World'
value = f"""Hello, {name}!
Welcome!"""

price = 14.9
value = f'Price: {price:.2f} €' # 'Price: 14.90 €'

In JavaScript string templates start and end with backticks:

name = 'World';
value = `Hello, ${name}!
Welcome!`;

price = 14.9;
value = `Price ${price.toFixed(2)} €`; // 'Price: 14.90 €'

Note that string templates can be of a single line as well as of multiple lines. For f-strings in Python you can pass the format for variables, but you can't call methods of a variable unless they are properties and call getter methods.

Unpacking lists

Python and now JavaScript has an interesting feature to assign items of sequences into separate variables. For example, we can read the three values of a list into variables a, b, and c with the following syntax:

[a, b, c] = [1, 2, 3]

For tuples the parenthesis can be omitted. The following is a very popular way to swap values of two variables in Python:

a = 1
b = 2
a, b = b, a # swap values

With the next generation JavaScript this can also be achieved:

a = 1;
b = 2;
[a, b] = [b, a]; // swap values

In Python 3.6 if we have an unknown number of items in a list or tuple, we can assign them to a tuple of several values while also unpacking the rest to a list:

first, second, *the_rest = [1, 2, 3, 4]
# first == 1
# second == 2
# the_rest == [3, 4]

This can also be done with JavaScript (ECMAScript 6):

[first, second, ...the_rest] = [1, 2, 3, 4];
// first === 1
// last === 2
// the_rest === [3, 4]

Lambda functions

Python and JavaScript have a very neat functionality to create functions in a single line. These functions are called lambdas. Lambdas are very simple functions that take one or more arguments and return some calculated value. Usually lambdas are used when you need to pass a function to another function as a callback or as a function to manipulate every separate elements in a sequence.

In Python, you would define a lambda using the lambda keyword, like this:

sum = lambda x, y: x + y
square = lambda x: x ** 2

In JavaScript lambdas use the => notation. If there are more than one arguments, they have to be in parenthesis:

sum = (x, y) => x + y;
square = x => Math.pow(x, 2);

Iteration without indexes

Many programming languages allow iterating through a sequence only by using indexes and incrementing their values. Then to get an item at some position, you would read it from an array, for example:

for (i=0; i<items.length; i++) {
console.log(items[i]);
}

This is not a nice syntax and is very technical - it doesn't read naturally. What we really want is just to grab each value from the list. And Python has a very neat possibility just to iterate through the elements:

for item in ['A', 'B', 'C']:
print(item)

In the modern JavaScript this is also possible with the for..of operator:

for (let item of ['A', 'B', 'C']) {
console.log(item);
}

You can also iterate through a string characters in Python:

for character in 'ABC':
print(character)

And in the modern JavaScript:

for (let character of 'ABC') {
console.log(character);
}

Generators

Python and modern JavaScript has a possibility to define special functions through which you can iterate. With each iteration they return the next generated value in a sequence. These functions are called generators. With generators you can get numbers in a range, lines from a file, data from different paginated API calls, fibonacci numbers, and any other dynamicly generated sequences.

Technically generators are like normal functions, but instead of returning a value, they yield a value. This value will be returned for one iteration. And this generation happens as long as the end of the function is reached.

To illustrate that, the following Python code will create a generator countdown() which will return numbers from the given one back to 1, (like 10, 9, 8, ..., 1):

def countdown(counter):
while counter > 0:
yield counter
counter -= 1

for counter in countdown(10):
print(counter)

Exactly the same can be achieved in modern JavaScript, but notice the asterisk at the function statement. It defines that it's a generator:

function* countdown(counter) {
while (counter > 0) {
yield counter;
counter--;
}
}
for (let counter of countdown(10)) {
console.log(counter);
}

Sets

We already had a look at lists, tuples and arrays. But here is another type of data - sets. Sets are groups of elements that ensure that each element there exists only once. Set theory also specifies set operations like union, intersection, and difference, but we won't cover them here today.

This is how to create a set, add elements to it, check if a value exists, check the total amount of elements in a set, and iterate through its values, and remove a value using Python:

s = set(['A'])
s.add('B'); s.add('C')
'A' in s
len(s) == 3
for elem in s:
print(elem)
s.remove('C')

Here is how to achieve the same in modern JavaScript:

s = new Set(['A']);
s.add('B').add('C');
s.has('A') === true;
s.size === 3;
for (let elem of s.values()) {
console.log(elem);
}
s.delete('C')

The Takeaways

As you know from the previous parts, I am offering a cheat sheet with the whole list of equivalents in Python and JavaScript, both, time honored and future proof. To have something printed in front of your eyes is much more convenient than switching among windows or scrolling up and down until you find what you exactly were searching for. So I suggest you to get the cheat sheet and use it for good!

Get the Ultimate Cheat Sheet of Equivalents in Python and JavaScript

In the next and last part of the series, we will have a look at function arguments, classes, inheritance, and properties. Stay tuned!


Cover photo by Alex Knight

06 Jul 2018 12:00pm GMT

04 Jul 2018

feedDjango community aggregator: Community blog posts

Plain text pypi description formatting: possible cause

Sometimes projects have a plaintext description on pypi.org. You see the restructuredtext formatting, but it isn't applied. See my own z3c.dependencychecker 2.4.2 for example.

I use an editor with restructuredtext syntax highlighting. I double-checked everything. I used docutils. I used pypi's own readme_renderer to check it. Not a single error.

But still, after some tries, the formatting was still off. Then a fellow contributor adjusted one of the setup() keywords in our setup.py: something might have to be a string (as in another package, with a perfectly-rendering description) instead of a list (as we had). Sadly, no luck.

But it made me investigate the other keyword arguments. I noticed, next to long_description, the description. This is normally a one-line description. In our case, it was a multi-line string:

long_description = u'\n\n'.join([ ... some files .... ])

description = """
Checks which imports are done and compares them to what's
in setup.py and warns when discovering missing or unneeded
dependencies.
"""

setup(
    name='z3c.dependencychecker',
    version=version,
    description=description,
    long_description=long_description,

I changed it to a single line and yes, the next release worked fine on pypi!

(Note that I also toyed a bit with encodings in that pull request, but I don't think that had any influence).

So: take a look at the description field if your project also has rendering problems (assuming that your long_description is fine).

04 Jul 2018 4:00am GMT

03 Jul 2018

feedDjango community aggregator: Community blog posts

Equivalents in Python and JavaScript. Part 2

Last time we started a new series of articles about analogies in Python and JavaScript. We had a look at lists, arrays, dictionaries, objects, and strings, conditional assignments, and parsing integers. This time we will go through more interesting and more complex things like serializing dictionaries and lists to JSON, operations with regular expressions, as well as raising and catching errors.

JSON

When working with APIs it is very usual to serialize objects to JSON format and be able to parse JSON strings.

In Python it is done with the json module like this:

import json
json_data = json.dumps(dictionary, indent=4)
dictionary = json.loads(json_data)

Here we'll indent the nested elements in the JSON string by 4 spaces.

In JavaScript there is a JSON object that has methods to create and parse JSON strings:

json_data = JSON.stringify(dictionary, null, 4);
dictionary = JSON.parse(json_data);

Splitting strings by regular expressions

Regular expressions are multi-tool that once you master, you can accomplish lots of things.

In the last article, we saw how one can join lists of strings into a single string. But how can you split a long string into lists of strings? What if the delimiter can be not a single character as the comma, but a range of possible variations? This can be done with regular expressions and the split() method.

In Python, the split() method belongs to the regular expression pattern object. This is how you could split a text string into sentences by punctuation marks:

import re

# One or more characters of "!?." followed by whitespace
delimiter = re.compile(r'[!?\.]+\s*')

text = "Hello!!! What's new? Follow me."
sentences = delimiter.split(text)
# sentences == ['Hello', "What's new", 'Follow me', '']

In JavaScript the split() method belongs to the string:

// One or more characters of "!?." followed by whitespace
delimiter = /[!?\.]+\s*/;

text = "Hello!!! What's new? Follow me.";
sentences = text.split(delimiter)
// sentences === ["Hello", "What's new", "Follow me", ""]

Matching regular expression patterns in strings

Regular expressions are often used to validate data from the forms.

For example, to validate if the entered email address is correct, you would need to match it against a regular expression pattern. In Python that would look like this:

import re

# name, "@", and domain
pattern = re.compile(r'([\w.+\-]+)@([\w\-]+\.[\w\-.]+)')

match = pattern.match('hi@example.com')
# match.group(0) == 'hi@example.com'
# match.group(1) == 'hi'
# match.group(2) == 'example.com'

If the text matches the pattern, it returns a match object with the group() method to read the whole matched string, or separate captures of the pattern that were defined with the parenthesis. 0 means getting the whole string, 1 means getting the match in the first group, 2 means getting the match in the second group, and so on. If the text doesn't match the pattern, the None value will be returned.

In JavaScript the match() method belongs to the string and it returns either a match object, or null. Pretty similar:

// name, "@", and domain
pattern = /([\w.+\-]+)@([\w\-]+\.[\w\-.]+)/;

match = 'hi@example.com'.match(pattern);
// match[0] === 'hi@example.com'
// match[1] === 'hi'
// match[2] === 'example.com'

The match object in JavaScript acts as an array. Its value at the zeroth position is the whole matched string. The other indexes correspond to the captures of the pattern defined with the parenthesis.


Moreover, sometimes you need to search if a specific value exists in a string and at which letter position it will be found. That can be done with the search() method.

In Python this method belongs to the regular expression pattern and it returns the match object. The match object has the start() method telling at which letter position the match starts:

text = 'Say hi at hi@example.com'
first_match = pattern.search(text)
if first_match:
start = first_match.start() # start == 10

In JavaScript the search() method belongs to the string and it returns just an integer telling at which letter position the match starts. If nothing is found, -1 is returned:

text = 'Say hi at hi@example.com';
first_match = text.search(pattern);
if (first_match > -1) {
start = first_match; // start === 10
}

Replacing patterns in strings using regular expressions

Replacing with regular expressions usually happen when cleaning up data, or adding additional features. For example, we could take some text and make all email addresses clickable.

Python developers would use the sub() method of the regular expression pattern:

html = pattern.sub(
r'<a href="mailto:\g<0>">\g<0></a>',
'Say hi at hi@example.com',
)
# html == 'Say hi at <a href="mailto:hi@example.com">hi@example.com</a>'

JavaScript developers would use the replace() method of the string:

html = 'Say hi at hi@example.com'.replace(
pattern,
'<a href="mailto:$&">$&</a>',
);
// html === 'Say hi at <a href="mailto:hi@example.com">hi@example.com</a>'

In Python the captures, also called as "backreferences", are accessible in the replacement string as \g<0>, \g<1>, \g<2>, etc. In JavaScript the same is accessible as $&, $1, $2, etc. Backreferences are usually used to wrap some strings or to switch places of different pieces of text.


It is also possible to replace a match with a function call. This can be used to do replacements within replacements or to count or collect some features of a text. For example, using replacements with function calls in JavaScript, I once wrote a fully functional HTML syntax highlighter.

Here let's change all email addresses in a text to UPPERCASE.

In Python, the replacement function receives the match object. We can use its group() method to do something with the matched text and return a text as a replacement:

text = pattern.sub(
lambda match: match.group(0).upper(),
'Say hi at hi@example.com',
)
# text == 'Say hi at HI@EXAMPLE.COM'

In JavaScript the replacement function receives the whole match string, the first capture, the second capture, etc. We can do what we need with those values and then return some string as a replacement:

text = 'Say hi at hi@example.com'.replace(
pattern,
function(match, p1, p2) {
return match.toUpperCase();
}
);
// text === 'Say hi at HI@EXAMPLE.COM'

Error handling

Contrary to Python, client-side JavaScript normally isn't used for saving or reading files or connecting to remote databases. So try..catch blocks are quite rare in JavaScript compared to try..except analogy in Python.

Anyway, error handling can be used with custom user errors implemented and raised in JavaScript libraries and caught in the main code.

The following example in Python shows how to define a custom exception class MyException, how to raise it in a function, and how to catch it and handle in a try..except..finally block:

class MyException(Exception):
def __init__(self, message):
self.message = message

def __str__(self):
return self.message

def proceed():
raise MyException('Error happened!')

try:
proceed()
except MyException as err:
print('Sorry! {}'.format(err))
finally:
print('Finishing')

The following example in JavaScript does exactly the same: here we define a MyException class, throw it in a function, and catch it and handle in the try..catch..finally block.

function MyException(message) {
this.message = message;
this.toString = function() {
return this.message;
}
}

function proceed() {
throw new MyException('Error happened!');
}

try {
proceed();
} catch (err) {
if (err instanceof MyException) {
console.log('Sorry! ' + err);
}
} finally {
console.log('Finishing');
}

The MyException class in both languages has a parameter message and a method to represent itself as a string using the value of the message.

Of course, exceptions should be raised/thrown just in the case of errors. And you define what is an error in your module design.

The Takeaways

As I mentioned last time, you can grab a side-by-side comparison of Python and JavaScript that I compiled for you (and my future self). Side by side you will see features from traditional list, array, dictionary, object, and string handling to modern string interpolation, lambdas, generators, sets, classes, and everything else. Use it for good.

Get the Ultimate Cheat Sheet of Equivalents in Python and JavaScript

In the next part of the series, we will have a look at textual templates, list unpacking, lambda functions, iteration without indexes, generators, and sets. Stay tuned!


Cover photo by Benjamin Hung.

03 Jul 2018 12:00pm GMT

30 Jun 2018

feedDjango community aggregator: Community blog posts

A few JavaScript Functions for Images and Files

> This post will be updated as...

30 Jun 2018 6:58pm GMT

Equivalents in Python and JavaScript. Part 1

Although Python and JavaScript are quite different languages, there are some analogies which full stack Python developers should know when developing web projects. In this series of 4 parts, I will explore what is similar in each of those languages and what are the common ways to solve common problems. This is not meant to be a reference and I will skip the basics like primitive variable types, conditions, and loops. But I will dig into more complex structures and data operations using both, Python and JavaScript. Also, I will try to focus on the practical use cases. This series should be interesting for the developers of Django, Flask, or another Python framework who want to get a grasp of traditional and modern vanilla JavaScript. On the other hand, it will be useful for the front-enders who want to better understand how the backend is working and maybe even start their own Django website.

Parsing integers

We'll begin with integer parsing.

In Python that's straightforward:

number = int(text)

But in JavaScript you have to explain what number system you expect: decimal, octal, hexadecimal, or binary:

number = parseInt(text, 10);

To use the "normal" decimal number system we are passing number 10 as the second parameter of the parseInt() function. 8 goes for octal, 16 for hexadecimal, or 2 - for binary. If the second parameter is missing, the number in text starts with zero, and you are using a slightly older browser, the number in the text will be interpreted as octal. For example,

parseInt('012') == 10  // in some older browsers
parseInt('012', 10) == 12

And that can really mess up your calculations.

Conditional assignment

For conditional assignment, Python and JavaScript have different syntaxes, but conditional assignments are quite popular in both languages. That's popular, because it's just a single statement to have a condition checking, the true-case value, and the false-case value.

Since Python 2.7 you can write conditional assignments like this:

value = 'YES' if positive == True else 'NO'

In JavaScript conditional assignments are done using ternary operator ?:, similar to the ones in C, C++, C#, Java, Ruby, PHP, Perl, Swift, and ActionScript:

value = positive === true? 'YES': 'NO';

Object attribute value by attribute name

The normal way to access an object's attribute is by the dot notation in both, Python and JavaScript:

obj.color = 'YELLOW'

But what if you want to refer to an attribute by its name saved as a string? For example, the attribute name could be coming from a list of attributes or the attribute name is combined from two strings like 'title_' + lang_code.

For that reason, in Python, there are functions getattr() and setattr(). I use them a lot.

attribute = 'color'
value = getattr(obj, attribute, 'GREEN')
setattr(obj, attribute, value)

In JavaScript you can treat an object like a dictionary and pass the attribute name in square brackets:

attribute = 'color';
value = obj[attribute] || 'GREEN';
obj[attribute] = value;

To retrieve a default value when an object has no such attribute, in Python, getattr() has the third parameter. In JavaScript, if obj attribute doesn't exist, it will return the undefined value. Then it can be OR-ed with the default value that you want to assign. That's a common practice in JavaScript that you can find in many JavaScript libraries and frameworks.

Dictionary value by key

This is similar to the previous one. The normal way to assign a dictionary's value by key in both languages is using the square brackets:

dictionary = {}
dictionary['color'] = 'YELLOW'

To read a value in Python you can use the square-bracket notation, but it will fail on non-existing keys with KeyError. The more flexible way is to use the get() method which returns None for non-existing keys. Also you can pass an optional default value as the second parameter:

key = 'color'
value = dictionary.get(key, 'GREEN')

In JavaScript you would use the same trick as with object attributes, because dictionaries and objects are the same there:

key = 'color';
value = dictionary[key] || 'GREEN';

Slicing lists and strings

Python has the slice [:] operator to get parts of lists, tuples, and similar more complex structures, for example Django QuerySets:

items = [1, 2, 3, 4, 5]
first_two = items[:2] # [1, 2]
last_two = items[-2:] # [4, 5]
middle_three = items[1:4] # [2, 3, 4]

In JavaScript arrays have the slice() method with the same effect and similar usage:

items = [1, 2, 3, 4, 5];
first_two = items.slice(0, 2); // [1, 2]
last_two = items.slice(-2); // [4, 5]
middle_three = items.slice(1, 4); // [2, 3, 4]

But don't mix it up with the splice() method which modifies the original array!


The [:] slice operator in Python also works for strings:

text = 'ABCDE'
first_two = text[:2] # 'AB'
last_two = text[-2:] # 'DE'
middle_three = text[1:4] # 'BCD'

In JavaScript strings just like arrays have the slice() method:

text = 'ABCDE';
first_two = text.slice(0, 2); // 'AB'
last_two = text.slice(-2); // 'DE'
middle_three = text.slice(1, 4); // 'BCD'

Operations with list items

In programming it is very common to collect and analyze sequences of elements. In Python that is usually done with lists and in JavaScript with arrays. They have similar syntax and operations, but different method names to add and remove values.

This is how to concatenate two lists, add one value to the end, add one value to the beginning, get and remove a value from the beginning, get and remove a value from the end, and delete a certain value by index in Python:

items1 = ['A']
items2 = ['B']
items = items1 + items2 # items == ['A', 'B']
items.append('C') # ['A', 'B', 'C']
items.insert(0, 'D') # ['D', 'A', 'B', 'C']
first = items.pop(0) # ['A', 'B', 'C']
last = items.pop() # ['A', 'B']
items.delete(0) # ['B']

This is how to do exactly the same with arrays in JavaScript:

items1 = ['A'];
items2 = ['B'];
items = items1.concat(items2); // items === ['A', 'B']
items.push('C'); // ['A', 'B', 'C']
items.unshift('D'); // ['D', 'A', 'B', 'C']
first = items.shift(); // ['A', 'B', 'C']
last = items.pop(); // ['A', 'B']
items.splice(0, 1); // ['B']

Joining lists of strings

It is very common after having a list or array of strings, to combine them into one string by a separator like comma or new line.

In Python that is done by the join() method of a string where you pass the list or tuple. Although it might feel unnatural, you start with the separator there. But I can assure that you get used to it after several times of usage.

items = ['A', 'B', 'C']
text = ', '.join(items) # 'A, B, C'

In JavaScript the array has the join() method where you pass the separator:

items = ['A', 'B', 'C'];
text = items.join(', '); // 'A, B, C'

The Takeaways

I compiled the whole list of equivalents of Python and JavaScript to a cheat sheet that you can print out and use for good. Side by side it compares traditional Python 2.7 and JavaScript based on ECMAScript 5 standard, as well as newer Python 3.6 and JavaScript based on ECMAScript 6 standard with such goodies as string interpolation, lambdas, generators, classes, etc.

Buy The Ultimate Cheat Sheet of Equivalents in Python and JavaScript

In the next part of the series, we will have a look at JSON creation and parsing, operations with regular expressions, and error handling. Stay tuned!


Cover photo by Benjamin Hung.

30 Jun 2018 8:33am GMT

25 Jun 2018

feedDjango community aggregator: Community blog posts

Hello world!

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

25 Jun 2018 3:42pm GMT

24 Jun 2018

feedDjango community aggregator: Community blog posts

python django Automatic Testing part 4

Know the testing output
The testing output of django here we will see that when we run our tests we will see number of test messages as the test runner prepares itself .Test runner is a component which orchestrates the execution of tests and provides the outcome to the user it may use a graphical interface a textual interface or return a special value to indicate the results of executing the tests
If you wish you can control the level of detail of these messages with the verbosity option on the command line like you can run tests with more detail (higher verbosity) by passing in the -v flag some of the other options are
-b,--buffer:
the standard output and standard error streams are buffered during the test run output during a passing test is discarded output is echoed normally on test fail or error and is added to the failure messages
-c,--catch:
control c during the test run waits for the current test to end and then reports all the results so far A second control-c raises the normal KeyboardInterrupt exception
-f --failfast:
stop the test run on the first error or failure
--locals:
show local variables in tracebacks
and you can get all the command line options put -h as
python -m unittest -h
here is an example of using -v

python -m unittest -v test_module
likewise we can use the options and after running the tests here
Creating test database...
Creating table myapp_database
Creating table myapp_mineral
This here tells you that the test runner is creating a test database as described in the previous posts once the database has been created Django will run your tests if every thing goes well we will see something like this as for example

----------------------------------------------------------------------

Ran 22 tests in 0.221s

OK
otherwise we will get error like this
======================================================================
FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/dev/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll
self.assertIs(future_poll.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (failures=1)

To learn more about python unittest you can go to this link one thing to note here the return code for the test runner script is 1 for any number of failed and erroneous test if all tests pass the return code is 0 this feature is useful if you're using the test runner script in a shell script and need to test for success or failure at that level


Thats for this post guys more on testing will be on next post please comment share and follow this blog

24 Jun 2018 10:26pm GMT

20 Jun 2018

feedDjango community aggregator: Community blog posts

A good Django view function cache decorator for http.JsonResponse

I use this a lot. It has served me very well. The code:

import hashlib
import functools

import markus  # optional
from django.core.cache import cache
from django import http
from django.utils.encoding import force_bytes, iri_to_uri

metrics = markus.get_metrics(__name__)  # optional


def json_response_cache_page_decorator(seconds):
    """Cache only when there's a healthy http.JsonResponse response."""

    def decorator(func):

        @functools.wraps(func)
        def inner(request, *args, **kwargs):
            cache_key = 'json_response_cache:{}:{}'.format(
                func.__name__,
                hashlib.md5(force_bytes(iri_to_uri(
                    request.build_absolute_uri()
                ))).hexdigest()
            )
            content = cache.get(cache_key)
            if content is not None:

                # metrics is optional
                metrics.incr(
                    'json_response_cache_hit',
                    tags=['view:{}'.format(func.__name__)]
                )

                return http.HttpResponse(
                    content,
                    content_type='application/json'
                )
            response = func(request, *args, **kwargs)
            if (
                isinstance(response, http.JsonResponse) and
                response.status_code in (200, 304)
            ):
                cache.set(cache_key, response.content, seconds)
            return response

        return inner

    return decorator

To use it simply add to Django view functions that might return a http.JsonResponse. For example, something like this:

@json_response_cache_page_decorator(60)
def search(request):
    q = request.GET.get('q')
    if not q:
        return http.HttpResponseBadRequest('no q')
    results = search_database(q)
    return http.JsonResponse({
        'results': results,
    })

The reasons I use this instead of django.views.decorators.cache.cache_page() is because of a couple of reasons.

Disclaimer: This snippet of code comes from a side-project that has a very specific set of requirements. They're rather unique to that project and I have a full picture of the needs. E.g. I know what specific headers matter and don't matter. Your project might be different. For example, perhaps you don't have markus to handle your metrics. Or perhaps you need to re-write the query string for something to normalize the cache key differently. Point being, take the snippet of code as inspiration when you too find that django.views.decorators.cache.cache_page() isn't good enough for your Django view functions.

20 Jun 2018 6:55pm GMT

19 Jun 2018

feedDjango community aggregator: Community blog posts

Checking if you're pwned (with Django)

Back in March I announced the release of a couple security-related projects for Django, one that implements the Referrer-Policy header, and one that uses the Pwned Passwords database of Have I Been Pwned to check users' passwords.

Today I've bumped the version and rolled a new release of pwned-passwords-django; if you're reading this, version 1.2 is on the Python Package Index, and is only a pip install away. And, of course, there's full documentation available ...

Read full entry

19 Jun 2018 4:52am GMT

18 Jun 2018

feedDjango community aggregator: Community blog posts

Make ALL Your Django Forms Better

Website experiences need to be consistent as much as they need to be well thought out and aesthetically pleasing. Structure, visual design, user interactions, and accessibility concerns are among many considerations that go into building quality websites. While achieving consistency of experience and implementation is an essential goal of web development, efficiency of execution is also very important. An efficient workflow means this consistent experience doesn't require redoing work across the site.

This post is about efficient consistency when building forms across your site.

Django helps you build forms, but one size doesn't fit all. It can render your forms on its own, or you can take more control of the form markup in your HTML. When Django renders your forms, you adhere to its defaults and assumptions. When those don't match your site's designs or other requirements, you have to do it yourself. But you can squeeze more flexibility out of Django's own form rendering. This lets you match your form styles and implementations site-wide without losing the valuable tools Django has out-of-the-box to make form rendering easier.

Why change what Django does?

Maybe you've always been fine using the forms exactly as Django renders them for you. Or, maybe you've been building custom forms in Django for so long you don't see what's wrong with providing your own widget classes or adding the extra attributes to your fields. And, of course, you can get a lot of customization out of simply re-styling the form pieces in CSS after Django has done its rendering, so you have lots of options for flexibility.

There have been a lot of situations where I need to change how lots of forms are rendered, usually across an entire site:

None of the above are difficult to account for. The problem we're looking at is applying this list of concerns, and more, to all form fields on an entire site, and that often includes forms that come from third-party Django apps where you don't even have access to change the forms themselves. (Short of forking all your third-party apps, which is a really crappy proposition.)

These situations are also increasingly difficult to deal with on existing sites, because the larger the site gets, the more forms it has.

Ideally, make the changes once

Django and Python have some assumptions and guidelines about code. One of the most important ones is removing verbosity and redundancy. The current approaches do neither, so let's find a better way.

We'll look at two things we can do. The first is the larger impact on our flexibility. The second is a smaller, but also useful method of customizing form defaults.

Django widget templates

As part of the 1.11 release of Django, widgets are now rendered by templates, just like everything else. This gives you the opportunity to create your own widgets much more easily. But, it also gives us an opportunity to override the templates Django uses for the built-in widgets it comes with.

Obviously, this advice assumes that your project has been upgraded to the 1.11 release of Django or higher.

There is a new type of component in a Django project, the Form Renderer. You can imagine this is very much related to what we're trying to do! There is a setting to select which Form Renderer you use, and Django itself comes with three choices, but you could implement your own. For our purposes, one of the built-in renderers will work, just not the default.

The default form renderer is the DjangoTemplates renderer, which sounds like it would do exactly what we need, but does not. This renderer uses its own template engine, separate from your project settings. It will load the default widgets first and then look in all your applications for widget templates for all your custom widgets.

We'll use the TemplateSettings renderer, instead, which loads templates exactly as the rest of our project is configured.

  
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

Now that the form rendering can be configured with regard to templates, let's look at some settings that will load our widget templates in the order we want. Some of this can be changed to adapt to your needs, but this is what worked for our project:

  
"DIRS": [
    "project/templates/",
],

"loaders": [
    "django.template.loaders.filesystem.Loader",
    "django.template.loaders.app_directories.Loader",
],

We're telling Django to first look for templates in our project's own templates directory, which is where we're going to put our widget templates. You could also override widgets in an app, but for overriding the defaults I think it is appropriate to do so in a global context.

One of the important overrides we made was to change how attributes inside the input tags are rendered. All the default widget templates exist in django/forms/widgets/ under any templates directory they're being looked up in, so our project has the template project/templates/django/forms/widgets/attrs.html.

Of course, we aren't going to override all the default widget templates. Although, you could, if you wanted to! For the templates we don't override, we still want the renderer to look in Django's form app. To do this, we need to add django.forms to our INSTALLED_APPS list, but we put it at the end, so that any overrides that might exist inside other apps can be found first and the defaults are always the last ones used.

  
INSTALLED_APPS = [
    ...

    'django.forms', # must be last!
]

What did we do by overriding these widget templates?

The new Form Rendering system in Django 1.11 adds a lot of control we didn't have before, and it was really fun to explore it and see how it could help us. Overall, I'm extremely happy with the result.

A trick for a little more customization

Django widget templates are a supported feature, and there are lots of other features in the framework that make tailoring your setup to a project's needs really easy. That said, what do you do about things you can't customize, but have a good case for?

As an example, let's look at one more thing Django forms do out-of-the-box. When Django renders a form for you, it renders a series of both labels and fields. We've talked about customizing the fields, but the labels are actually external to the widgets and their templates.

I'm going to use a silly example, but a real one. In our design, we did not like the colons Django includes as a suffix of every label. Of course, there were lots of ways around this. I could create my forms with an empty label_suffix option, for example. But, if you've read this far, you'll know that doing anything more than once is too often for me.

There is no setting you can use to change the default label suffix globally across a project. But there is a trick you can employ to make the base Form class that all your forms derive from use a different default: just replace the base Form class with one that does what you want!

  
from django import forms

class BaseForm(forms.Form):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('label_suffix', '')  
        super(BaseForm, self).__init__(*args, **kwargs)

forms.Form = BaseForm

This is a roundabout way to accomplish our little goal, and I admit it is a trivial goal. You might find other reasons to do this, with other changes that you want to make across all the forms on your site. A fair warning is due, however. This is monkeypatching, it is generally frowned upon, and you have to be careful with changes that will affect code you didn't write.

I think this is a light and safe use, but be careful if you do anything more with it!

Conclusion

We haven't gone over anything complex here. Using some simple tricks and an easy application of new features supported by Django can go a long way towards creating great form experiences across your site.

Hopefully, this helps you work faster with even better results for you, your clients, and your users.

18 Jun 2018 6:00pm GMT