A Rubyist's guide to Django (Models)
Tags: rails, django, beginners, tutorial
Published: 2023-08-04 04:50:30

Ruby and Python is very similar and so should Rails and Django.

When creating models, Django uses a different approach and its great! Its easier to explain with examples.


## Creating a Model

### Rails

The ruby way is to use _Active Record_ which you will use the rails command in your terminal, for example when generating a model for a book:

```
rails generate model book name:string rating:integer
```
And by doing this, rails will generate for you a migration file, the model file, and the test files.

Simple enough, as long as you get the terminal commands correct without typos. Just run the migration next.
```
rails db:migrate
```
The thing I like about rails is that each model file will be completely empty, and it allows you to focus on writing your model specific methods. However, to refer back to my attributes (if I forget my attributes name), I will have to go to my schema file.


### Django

Django uses your models.py file to create your migration file instead of your command line.

In your models.py you can define your model class for books like so:
```
# models.py
from django.db import models


class Book(models.Model)
    name = models.CharField(max_length=100)
    rating = models.IntegerField()
```
Your model book is inheriting _django models_ just like ruby model is inheriting from _Active Records_. 

Your attributes are created directly in your class method and not in the command line.

So you might be wondering now _Active Records_ creates all the attributes methods behind the scene based on the column names, and now I have to do this in django? AND that I didn't even created the migration file yet.

That's the beautiful part of django, which is the migration file is created based on your models. Now you can run in your terminal:
```
python manage.py makemigration
```
And django will create the migration file based on your model.py.

Cool right?

The best part?

If you have any errors in your models setup, such as you forgot to add `max_length` for your `CharField`, the `makemigration` command will return errors pointing to exactly where the issue is.

All good? Now you just need to run migrate to change your database:
```
python manage.py migrate
```


## Changing your model
Can you imagine how easy it is to change your models in django?

### Rails
In ruby you will need to create a migration file in the terminal like so:
```
rails g migration AddAuthorToBooks
```
Which will generate a migration file with an `add_column` to our books table. And don't forget to 

```
rails db:migrate
```

### Django

Just add it to your models.py!

go to your model class method and add it like this:
```
# models.py
# [...]
class Books(models.Model):
    # [...]
    author = CharField(Max_length=100)
```
Now make the migrations file. Django will go through your entire models.py and track out all the changes that needs to be made to the database and created the change migration based on what's changed.
```
python manage.py makemigration
```

Wait. I cannot make the migration file, and I am getting errors? 

The error probably looks like this:

```
You are trying to add a non-nullable field 'author' to book without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option:
```

I thought this is easy? That's too many words!

Well it is easy, because django doesn't want you to break your app and you couldn't figure out why. Reading it carefully, django wants to prevent you from running into situation where your app breaks because you cannot run methods on `null`.

Option 1: allows you to set a value for all of the old existing records;
Option 2a: allows you go back and change the models.py by adding a default value; or
Option 2b: change the models.py by setting `null=True`(if it make sense for your app).

You can now run make migration again and migrate:
```
python manage.py makemigration
python manage.py migrate
```

### I never had to do that with Rails

Well... yes, Rails doesn't ask you about what to do with the existing database record and you might run into issues with your app, at that point, then you will try to figure how to clean the data. Or maybe the error will never happen, but isn't it better to be safe than sorry?

So how do you do that in rails?

You can run `rails c` and update all the entries by:
```
Book.where(author: nil).update_all(author: "N/A")
```

Or you can create a rails task (Probably a better option in production and you can do multiple changes if there is a big change to the database):
```
rails generate task update_existing_authors
```
This will generate a .rake file in your `lib/task`
Open the file and define what you want to do, such as:
```
# lib/tasks/update_existing_authors.rake
namespace :db do
  desc "Update existing authors for books"
  task :update_existing_authors => :environment do
    Book.where(author: nil).update_all(author: "add your author")
  end
end
```
Run rake task in your terminal:
```
rake db:update_existing_authors
```

### So Django is better?

I don't think so, they do thing differently and they each have their pros and cons. 

#### Designing the database
What I like about Django is that you can take you time designing your models directly in your code editor. You can edit each model's attributes, their type, and spell check([Code Spell Check](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) on VSCode is very handy) before finally deciding in creating the migration file. 

In rails, its better to make sure you are designing your database on another tool, and only create those migration file when you are ready. _And don't forget to spell check_!

#### Changing the database
Changing the database is as simple as changing your class variables in django and running `makemigration` and the `set default` prompt for giving a one time default is very nice also.

On the other hand, Rails doesn't let you change your databasae so easily which creates a sense of security in keeping the integrity of your database.

#### Model methods
Lastly, your model.rb is super clean, and all you model specific methods are separate by each file nicely. Each model.rb is for one model and you can find what you need super easily. And how clean it is allow you to focus on coding, and not searching.

As for django regarding this, all you model methods are nested in the same models.py file, which can get very heavy. Methods are easy to write because all the variables are right in front of you.
But as your app grows, this file because hard to manage.

The solution? Perhaps I will save this for another post.