DEV Community

Discussion on: 5 reasons why people are choosing Masonite over Django

Collapse
 
spookylukey profile image
Luke Plant

Could you explain why the pattern of not defining database fields on the model itself, but loading them via inspection? I know that Rails does it that way, so some people must prefer it, but I simply cannot imagine wanting that. It seems to have lots of disadvantages.

For example:

  • You're going to need to open a DB tool to know what attributes are available. So without a running app, you can't do the most basic checks on something - or you have to read through and mentally execute the entire migration stack to understand what the current state of the DB schema is, rather than having it all defined in Python.

  • For relationships you need to define it in code (according to this - orator-orm.com/docs/0.9/orm.html#r... ) so the DB fields stuff only goes so far, and know it is split between two places.

  • Computed properties (e.g. a full_name convenience property that combines first_name and surname) are going to be in code, but DB fields in the DB. If you come across my_model_instance.full_name, you won't know whether it is defined in the DB or in Python, so you won't know where to look first.

  • If you want to define additional field info that can't be defined in DB schema (e.g. validation or something like that), there is nowhere for that.

So I'm genuinely curious why this design would be considered an advantage. I always thought that the Rails design was just a quirk of how DHH like to develop.

Collapse
 
josephmancuso profile image
Joseph Mancuso

Good questions. All valid. Laravel does it as well so it usually is the preference at least in both rails and PHP ecosystems. Python seems to have gone the way of how Django does models.

You're going to need to open a DB tool to know what attributes are available. So without a running app, you can't do the most basic checks on something - or you have to read through and mentally execute the entire migration stack to understand what the current state of the DB schema is, rather than having it all defined in Python.

This is correct and this has always been quite a pain point for these types of systems. One of the ways we get around that in Masonite is we have a craft command called craft model:docstring table_name which will generate something like this:

"""Model Definition (generated with love by Masonite)

id: integer default: None
name: string(255) default: None
email: string(255) default: None
password: string(255) default: None
remember_token: string(255) default: None
created_at: datetime(6) default: CURRENT_TIMESTAMP(6)
updated_at: datetime(6) default: CURRENT_TIMESTAMP(6)
customer_id: string(255) default: None
plan_id: string(255) default: None
is_active: integer default: None
verified_at: datetime default: None
"""
Enter fullscreen mode Exit fullscreen mode

you can then slap that on the docstring on your model so you know the details of what is in the table. Just a way to get around that issue.

As for mentally executing the migration stack, I'm not 100% sure what you mean. There is always a migrations table in these types of systems that manage the migrations that have ran and have not run so its usually just a simple command and it will spit back out the state of the database in terms of migrations.

For relationships you need to define it in code (according to this - orator-orm.com/docs/0.9/orm.html#r... ) so the DB fields stuff only goes so far and know it is split between two places.

not really sure what you mean by this one. You don't define relationships on the database level. You can define constraints like foreign key constraints if that is what you mean. But that is a constraint and not necessarily a relationship. If that is what you mean, even if you define a constraint you still need to specify the relationship in code. Getting an entity and its relationships has to do with the query you send to the database.

Django relationships I believe are accessed a little more implicit inside the core codebase but either way, they are defined in code. In order to map a relationship, you need to compile a specific query related to the column of the table either using an implicit or explicit join.

But yeah, either way, you define relationships at the codebase level. You would want to anyway because you can better tweak the relationship. Maybe you only want to limit it to 10 results or order by descending or only show where active is 1.

Computed properties (e.g. a full_name convenience property that combines first_name and surname) are going to be in code, but DB fields in the DB. If you come across my_model_instance.full_name, you won't know whether it is defined in the DB or in Python, so you won't know where to look first.

If you always check the model first you hit 2 birds with 1 stone, if it's not on the model then it's in the table. I wouldn't consider this a bad thing. Whether it's on the model or in the database you still check the model. Plus its easier to check the model than the database usually so yeah. Just check the model. If it's not on the model then its not a computed property and its instead a column on the database.

If you want to define additional field info that can't be defined in DB schema (e.g. validation or something like that), there is nowhere for that.

Why not? Firstly, many of these types of ORM's have hooks that you can tie into like saving or creating. Validation can be done here perfectly fine. Also, validation doesn't have to be at the model level. I can just as easily validate incoming data before I do anything with models. I do this at the controller / business logic to validate all incoming data pretty easily.

So I'm genuinely curious why this design would be considered an advantage. I always thought that the Rails design was just a quirk of how DHH like to develop.

I don't think its a quirk since it's actually a pretty validated design. Laravel itself has been doing it extremely successfully and after using both Django and Laravel (I used Django style first) I much prefer the Laravel style (which is the same Orator and this style above).

I think one of the biggest advantages is a lot of the time on projects, especially in corporations, you are using an existing database. This is the perfect advantage for this type of ORM because with something like Django you need to recreate the entire schema in Python anyway. Yes, there have since been tools to aid in this like database inspection tools to create Python schemas for you but that seems more like an afterthought to me.

I think you should use both systems and experience it for yourself. If you prefer the Django or SQLalchemy way more than more power to you. People have preferences and I fully understand that and that is ok.