Django Models and Migrations vs Laravel Eloquent ORM and Migrations - Part 1

A technical comparison of two giant framework ORM structure

Previously I had written Django vs Laravel vs Rails. That irked readers having a different opinion. Some of them rather than pointing out the proper logic for their dissatisfaction and suggestions for change, started bluffing. One reader pointed out that I should either share my experience or just write technical facts. Although each article is a view of the author, for some people, it needs to mention explicitly. Today, I am starting a series to compare these frameworks feature-wise. Now, I will put facts on database handling (defining tables, relations, and queries) in Django and Laravel.

Suggested Reading: Django vs Laravel vs Rails

Content:

  1. Part 1 (Current post):
    1. Database support
    2. Defining database tables
    3. Running migrations
    4. Database relationships
  2. Part 2 (Next Post):
    1. Seeding data
    2. Database query
    3. Model functions
    4. Serializers

1. Database support

Django

Officially Django supports five databases: PostgreSQL, MariaDB, MySQL, Oracle, and SQLite. There are also a number of database backends provided by third parties. Django prefers PostgreSQL. For PostgreSQL, no additional settings requires on most of the hosting platforms like Heroku.

Connecting the database is very easy by updating project/settings.py

  1. DATABASES = {
  2. # connection with postgresql
  3. "default": {
  4. "ENGINE": "django.db.backends.postgresql_psycopg2",
  5. "NAME": "your_database_name",
  6. "USER": "database_username",
  7. "PASSWORD": "database_password",
  8. "HOST": "localhost",
  9. "PORT": "5432",
  10. }
  11. }

Connecting Django with other databases is similar. Multiple databases can be used in a project. Check how to connect multiple databases.

Laravel

Currently, Laravel supports four databases: MySQL, PostgreSQL, SQLite and SQL Server. All other major databases are supported with third-party plugins.

Connecting with the database in Laravel is similar. You can configure it in config/database.php.

  1. 'mysql' => [
  2. 'host' => '196.168.1.3',
  3. 'sticky' => true,
  4. 'driver' => 'mysql',
  5. 'database' => 'database_name',
  6. 'username' => 'database_username',
  7. 'password' => 'database_password',
  8. 'charset' => 'utf8mb4',
  9. 'collation' => 'utf8mb4_unicode_ci',
  10. 'prefix' => '',
  11. ],

Laravel provides an option to set default separate databases one for SELECT statements, and another for INSERT, UPDATE, and DELETE statementsMultiple databases can be used in single Larvel projects.

Conclusion:

As both Laravel and Django are the major frameworks of their respective programming languages, they both provide the latest advanced database functionalities. If your project requires, that generally does not require, read and write in different databases then Laravel is more convenient as it provides default functionality for this purpose.

Note: Both frameworks also provide raw query execution. We will not consider this in this article as this is not done in the usual projects.

2. Defining database tables

In both Django and Laravel, tables are defined by Classes.

Django

Tables in Django are defined in app/models.py. Generally, one Model Class defines one table. Abstract Class does not define any table. By default, Many-to-many intermediatory tables are created automatically and do not have any Model class. Custom M2M intermediatory tables can be defined by model classes. A simple Model class looks like:

  1. from django.db import models
  2. class Person(models.Model):
  3. # varchar
  4. name = models.CharField(max_length=30)
  5. # integer
  6. age = models.PositiveIntergerField(blank=True, null=True)
  7. # Foreign relation
  8. species = models.ForiegnKey('living_being.Species', on_delete=models.CASCADE)
  9. def __str__(self):
  10. return self.name

After creating a model class, registering the app in INSTALLED_APPS in settings.py is required (if already not done). In the above example, only three data types are shown. Django ORM provides 31 field types. You can check them here.

Note: By default table name will be app_person. The table can have a custom name if it is defined in Meta Class.

These Model Classes are used to generate migration files as well as to manipulate databases as ORM. After defining tables in Model Classes, the actual database is altered in two steps.

Step 1: Generate migration files.

  1. python manage.py makemigrations

This command will generate migration files in app/migrations directory

Step 2: Execute migration files

  1. python manage.py migrate

After this command, the database will be manipulated as defined in migration files and migration file name entry will be added in django_migrations table. Note that migration files are manipulating the database, not Model Class. Generally, migration files are auto-generated and do not need edit but sometimes we need to change code in such a way that we have to edit migration files. For example, if we have to change the app name or move a Model Class from one app to another app then we have to update migration files accordingly.

 Laravel

Laravel is a very flexible framework. You don't need to create ORM (known as Eloquent ORM)  for small projects as you can directly query on tables using Query Builder. When query using a query builder, you need not write a raw query. We will discuss this when comparing queries in a later section.

In Laravel, tables are defined in migrations rather than Models. First migration files are created with artisan command:

  1. php artisan make:migration create_users_table

The new migration will be placed in your database/migrations directory. Each migration file name contains a timestamp which allows Laravel to determine the order of the migrations. A migration file looks like this:

  1. <?php
  2. use Illuminate\Database\Migrations\Migration;
  3. use Illuminate\Database\Schema\Blueprint;
  4. use Illuminate\Support\Facades\Schema;
  5. class CreatePersonTable extends Migration
  6. {
  7. /**
  8. * Run the migrations.
  9. *
  10. * @return void
  11. */
  12. public function up()
  13. {
  14. Schema::create('person', function (Blueprint $table) {
  15. // Primary key (optional otherwise will be created automatically)
  16. $table->id();
  17. // Varchar
  18. $table->string('name');
  19. // DATETIME field
  20. $table->timestamps();
  21. });
  22. }
  23. /**
  24. * Reverse the migrations.
  25. *
  26. * @return void
  27. */
  28. public function down()
  29. {
  30. Schema::drop('person');
  31. }
  32. }

 Note that in the above code, there are two functions - up and down. up() runs when migration is moved forward and down() runs when migration runs backward. If you have some background with modern MVC frameworks, then you already know that moving forward means executing migration on a database level and moving backward means undo the changes done by this migration.

Here up() function will create the table and down() function will delete the table. We will see more about migrations in the next section when we will compare Django migrations with Laravel migrations.

$table->string('name') is creating a column in person table.

Conclusion:

Both Laravel and Django provide functionality for defining tables in code and auto-creating tables via migrations (we will see in the next section how to migrate). In Django, tables are defined in Model Class and migrations are generated automatically by command. You do not define the OMR class again. But in Laravel, the terminal command only generates migration files and you have to write code for the table manually. ORM Classes (know as Model Classes) are defined explicitly. Model Class in Laravel does not alter table structure.

Laravel executes different operations for forwarding and backward migrations but Django only undoes the migration in the rollback command. We will compare Django and Laravel migrations in more depth in the next section.

3. Running Migrations

In the last section, we have already seen the command for generating and executing migrations. In this section, we will see what more migrations can do.

Django

In Django, after defining Model Classes, we need to create and run migrations as mentioned in the second section. Sometimes we need to revert a migration. Migration can be revert back by the following command:

  1. manage.py migrate app_name migration_file_name

For more details, check this SO answer https://stackoverflow.com/a/43267471/4115953. For more details on reversing migrations follow https://docs.djangoproject.com/en/3.1/topics/migrations/#reversing-migrations

All available migrations can be found by:

  1. python manage.py showmigrations

manage.py accepts optional arguments --fake and--fake-initial for updating the migration table without applying migrations to the database. When the Django app runs, Django compares the difference between Models and Migration files. In most cases, migration files do not require any manual modification but sometimes we need to modify these files. Ex. for migrating a table from one app to another app, we need to create a new class and delete the old class (logically) but we have to just rename the existing class in the database. For such cases, Django provides SeparateDatabaseAndState for different logic for state and database. 

  1. operations = [
  2. migrations.SeparateDatabaseAndState(
  3. database_operations=[
  4. # database logic
  5. ],
  6. state_operations=[
  7. # state logic
  8. ])
  9. ]

Check for more details on migrations https://docs.djangoproject.com/en/dev/ref/migration-operations/

Laravel

We had created Laravel migrations in the previous section. Just like Django, for applying these migrations to the database, we need to execute a command.

  1. php artisan migrate

On revert, Django undoes the same thing that it has created in the migration. But Laravel migrations provide different functions (as we see in the last section). Apart from this Laravel has the following artisan commands related to the migrations:

  • migrate:rollback: for reverting last migrations. with --steps=n option, it can revert back to n migrations.
  • migrate:reset: revert all migrations
  • migrate:refresh: revert all migrations and then apply all migrations

Conclusion

Both Laravel and Django are modern and mature frameworks. They provide full control to the programmers. Their ways are slightly different (according to community preferences) but they are fully featured.

4. Database Relationships

The beauty of modern framework ORMs is database table relationships. In the next part, we will see the magic of these ORMs while comparing database queries. Database ORMs almost replace the dirty "join" SQL queries with perfect efficiency. Although there are still some exceptional cases where raw queries are required.

Django

Django provides one-to-one, many-to-one, and many-to-many relationships. Django does not provide a one-to-many relationship. You need to use many-to-one in reverse order. I have been working on Django for the last five years and I never required a one-to-many relationship. Django has a default reverse mapping for many-to-one fields. This can be disabled if not required for any specific relation.

Note: For one-to-one and one-to-many fields, it needs to mention what will happen if the related entry is deleted. This is not the case for many-to-many.

  1. class Profile(models.Model):
  2. # one-to-one (one Profile for one User)
  3. # can be called as profile.user (from Profile instance)
  4. # reverse call will be user.profile (from User instance)
  5. user = OneToOneField(User, on_delete=models.CADCADE)
  6. class Contact(models.Model):
  7. # many-to-one (many Contacts for one User)
  8. # can be called as contact.user (from Contact instance)
  9. # reverse call will be user.contact_set (from User instance)
  10. user = ForeignKey(User, on_delete=models.CASCADE)
  11. class Newspaper(models.Model):
  12. # many-to-many (Many News in one Newspaper, One news in many Newspapers)
  13. # can be called as newspaper.news (from Newspaper instance)
  14. # reverse call will be news.newspaper_set (from News instance)
  15. news = ManyToMany(News)

Laravel

Laravel provides all four relationships:

  1. One To One
  2. One To Many
  3. One To Many (inverse)
  4. Many To Many

Having an extra one-to-many relationship may seem a luxury but just like Django, Laravel does not have a reverse mapping. So, having an extra relationship is extra work.

NOTE: In Laravel, you have to define the relationship in the migration tables also.

  1. <?php
  2. // Profile.php
  3. class Profile extend Model {
  4. // One To One
  5. // create a function which will return a relation
  6. // NOTE: for reverse access, you need to define belongTo in User Model
  7. public function user() {
  8. return $this->hasOne('App\Models\User');
  9. }
  10. }
  11. // User.php
  12. class User extend Model {
  13. // Reverse Mapping
  14. public function profile() {
  15. return $this->belongsTo('App\Models\Profile');
  16. }
  17. // One To Many
  18. public function contacts() {
  19. return $this->hasMany('App\Models\Contact');
  20. }
  21. }
  22. // Contact.php
  23. class Contact extend Model {
  24. // Reverse Mapping, One To Many (inverse)
  25. public function user() {
  26. return $this->belongsTo('App\Models\User');
  27. }
  28. }
  29. // Newspaper.php
  30. class Newspaper extend Model {
  31. // Many To Many
  32. // NOTE: for reverse access, you need to define belongsToMany in News Model
  33. public function news() {
  34. return $this->belongsToMany('App\Models\News');
  35. }
  36. }

Conclusion

Although both frameworks provide the same functionality, Laravel needs more work for writing Models and Migrations. With default reverse relation mapping and auto migration generation, Django has an upper hand.

I will compare database seeding, database query, model operations, and serializer in the next part.




About Harish Kumar

Harish, a technical core team member at www.lyflink.com with five year experience in full stack web and mobile development, spends most of his time on coding, reading, analysing and curiously following businesses environments. He is a non-graduate alumni from IIT Roorkee, Computer Science and frequently writes on both technical and business topics.

Related Articles

With the expanding market of mobile apps, the developers are struggling to maintain the code bases for Native apps. M...
5 Elite and Imperative Hybrid App Frameworks
Django is a great framework in python. But all of the hosting do not provide django hosting in their shared or free h...
Cheap Django Hosting
Laravel provides blade template. Blade files are similar to php files and cover all features of php files. In additio...
Blade Template in Laravel 7

Complete Python Bootcamp: Go from zero to hero in Python 3

Top Posts

Recent Posts

The Complete Web Developer Course - Build 25 Websites

Meet on Twitter

Subscribe

Subscribe now and get weekly updates directly in your inbox!

Any Course on Udemy in $6 (INR 455)

Development Category (English)300x250

Best Udemy Courses

PHP with Laravel for beginners - Become a Master in Laravel