Introduction

Masonite is an increasingly popular Python web framework that has garnered a lot of attention in the Python community recently.

I am not here to say that Django is crap and that Masonite is the best thing in the entire world but I have talked with a lot of developers over the past year on why they made the switch from Django to Masonite. Below I will go into some detail on the common reasons I have found between them all and why Masonite may make more sense to use for your next project.

One of these developers in particular, Abram Isola, gave some really excellent feedback on why his contract bid (with an extremely large company) ended up winning over all other bids.

Before we start, here are a few links if you want to follow Masonite to explore a bit further:

Ok, let's get started :)

1. Existing Databases

Some business applications require you to use an existing database in order to create a new integration for them.

Managing an existing database with Django is not particularly difficult. You can use something like inspect db with Django in order to generate the proper models and model schema attributes. The issue really arises when you have to manage several databases within the same application, some of which are existing and some of which you need to manage yourself.

You can still do this with Django with something like database routers but it requires a good amount of setup and testing. When you're starting development on an application, you just want to hit the ground running and start the business logic.

Active Record Pattern ORM

Masonite and Django both use the Active Record Style of ORM but the main difference is that Orator has more of a dynamically passive approach to it.

For example, with Django, you specify the columns on the table by using attributes on the class.

In Django this may look something like:



from django.db import models class Musician ( models . Model ): first_name = models . CharField ( max_length = 50 ) last_name = models . CharField ( max_length = 50 ) instrument = models . CharField ( max_length = 100 )

So now whenever you retrieve, store and exchange data between your model and the database, Django knows what type of data to handle.

Orator is a bit more dynamic. Orator will use the schema the table has in order to map the values of the attributes. In fact, Orator does not need explicit definitions of attributes at all. A comparable model in Masonite would look like this:



from config.database import Model class Musician ( Model ): pass

Notice we do not specify a firstname, lastname or instrument because Orator knows when it fetches the data from the table, which attributes to set on the model.

2. Class scaffolding

Masonite has what it calls "craft" commands. These are called craft commands because they are a simple command like:



$ craft model Project

that .. "crafts" .. these classes for you so you can stop writing redundant boilerplate over and over again. We all know that the start of a controller starts the same, we all know that the declaration of a function based view starts the same, we all know that a class-based view generally starts the same.

We as developers are constantly writing the same boilerplate over and over again when we get into the rinse-and-repeat cycle of development. Create a file, create some class boilerplate, create the class definition, imports the require classes, etc.

This is why Masonite has over a dozen commands that allow you to create views, controllers, queue jobs, commands, middleware, models, database seeds, etc all from the command line. This saves you and your team a lot of time in development.

Spending time writing out that class definition doesn't only take time from the developer but also breaks the concentration of the developer. You as a developer just wants to generate the class definition and then immediately start working on the business logic that class needs to contain.

Also, the developer no longer needs to remember what base classes or imports are required to be imported in order to get that boilerplate code up and running. Just let the craft command do all the hard work for you so you can keep focusing on your application.

If you want to save a lot of time writing boilerplate code then consider using Masonite for your next application.

3. Folder Structure

This is typically a personal preference and many developers may not share this reason but Masonite lends an extremely solid folder structure.

Masonite has a few different philosophies by default.

One of these is to keep 1 class 1 file. Some developers may think this is normal but many still write multiple classes per file generally. Once you start using the 1 class 1 file system you will never look back.

Another philosophy is to maintain a Separation of Concerns. If you run:



$ craft job SomeJob

for example, it scaffolds that class in the app/jobs directory. Need to craft a middleware? Middleware will be created in the app/http/middleware directory. Need to create a recurring task? Tasks will be created in the app/tasks directory. For on and so forth.

This allows you to not accidentally bundle up all your logic in the same place which makes refactoring later on a huge headache. It's generally good practice to keep all related logic together in their respective modules.

Self Contained Apps

Django, on the other hand, has a good starting structure and also boasts the self-contained apps portion of the framework. This allows you to create self-contained packages that can swap around, be removed, plugged into other applications if done correctly, etc.

The issue with this is that it is fantastic in theory, terrible in practice. In fact, it's my opinion that this is a bit of an anti-pattern, at least the way Django does it.

Anybody who has created a self-contained app knows that it works really well for the first few days and then you start to wrestle it as your app models start to depend on other apps. Finally, you end up putting all your models into a single app and then building your entire application into there. Maybe you use other self-contained apps as packages but they usually end up eventually breaking the "self-contained" promise.

I think this is one of Django's biggest sells and it is a bit of an over promise. While Django sells you on a single application that is broken up into self-contained apps, Masonite is building a single app with a very well structured separation of the concerns file structure to keep you rolling.

4. Middleware

Masonite's middleware system allows for some very easy implementations while also staying very complex and dynamic. Abram Isola chose Masonite over Django because Masonite's middleware has a couple of capabilities that Django simply does not.

Firstly, Masonite has 2 types of middleware. Both types use the exact same class but it just depends on where you put the class after you create it.

The first type of Masonite middleware is what's called HTTP Middleware. This middleware runs of every request like you would normally expect.



HTTP_MIDDLEWARE = [ AuthenticationMiddleware , ]

The second type of middleware is what's called Route Middleware:



ROUTE_MIDDLEWARE = { 'auth' : AuthenticationMiddleware , }

This is also the same middleware class you wrote before, just inside a different list a few lines down the config file. Route middleware is a bit more flexible. You can attach it to a specific route:



ROUTES = [ Get ( '/dashboard' , 'DashboardController@show' ). middleware ( 'auth' ) ]

or a group of routes:



ROUTES = [ RouteGroup ([ Get ( '/dashboard' , 'DashboardController@profile' ), Get ( '/dashboard/stats' , 'DashboardController@stats' ), Get ( '/dashboard/users' , 'DashboardController@users' ), ], middleware = [ 'auth' ]) ]

If your application needs very precise access controls or simple integrations of middleware, you should consider Masonite for your next project.

Django does have middleware bit it runs on every request and you need to specify inside the middle if it should actually execute any logic based on some input like the request route.

Django Middleware Example

def global_auth_middleware ( get_response ): def middleware ( request ): if not request . user . is_authenticated : return redirect ( '/login/' ) return get_response ( request ) return middleware

Masonite Middleware Example

from masonite.request import Request class AuthenticationMiddleware : def __init__ ( self , request : Request ): self . request = request def before ( self ): if not self . request . user (): self . request . redirect_to ( 'login' ) def after ( self ): pass

5. Built in features and drivers

Django and Masonite are both called "batteries included frameworks" but Masonite is boasted as the "Modern and developer-centric Python web framework" because of the types of batteries included features that it contains.

Masonite has features for built-in Amazon S3 uploading, RabbitMQ queue support, Mailgun, and SMTP email sending support, simple database seeding to easily teardown, rebuild and seed your database with data, built in Pusher for websocket support, built in recurring task scheduling and so much more. All of these features that would be "must haves" if it didn't take so much time to integrate them now takes seconds to set up.

Does your application have notifications? Easy just use the websocket features to push out notifications to your users.

Does your application send email? Queue all of them with RabbitMQ so your application is much more responsive.

Does your application handle user uploads? Use the Amazon S3 upload feature to manage them.

Does some parts of your application require some tasks to run every hour or every day at midnight? Easy just use the Task scheduling feature to schedule tasks to run every day, every 3 days, or every 5 days at 3 pm easily.

Masonite takes a lot of these features that you may spend several hours researching, implementing and testing and allows you to stay focused on your own business logic and use the integrations we built for you!

Django does have a lot of features out of the box but not remotely as many as Masonite and we are typically adding new features every 2 weeks. You could wake up tomorrow with brand new integration. Update Masonite and you're ready to rock and roll.

Thanks for giving me the time to explain why people are switching from Django to Masonite :)

Be sure to follow Masonite using the links below: