[HN Gopher] Django and Postgres for the Busy Rails Developer
       ___________________________________________________________________
        
       Django and Postgres for the Busy Rails Developer
        
       Author : plaur782
       Score  : 103 points
       Date   : 2024-12-11 14:56 UTC (8 hours ago)
        
 (HTM) web link (andyatkinson.com)
 (TXT) w3m dump (andyatkinson.com)
        
       | Supernaut wrote:
       | As a longtime Rails developer who has experimented with Python
       | but knew little about Django, I read this article with interest.
       | Something that jumped out at me was the author's description of
       | the "models.py file, which contains all the application models
       | (multiple models in a single file)". I did some quick research
       | and I gather that this approach isn't maintained as you move
       | beyond the scale of a toy application. I kind of think he's doing
       | Django a disservice with his current wording there, as my
       | immediate reaction was that it sounded nightmarish!
        
         | pmontra wrote:
         | We have a models file that imports models from other files, to
         | keep them in the same directory tree. Anyway one could import
         | models from any location of the project. Every app the Django
         | project is made from can have its own urls, models, migrations.
        
         | 9dev wrote:
         | I'm not originally a Python guy, but when I'm forced to work
         | with Django, what I do for models and settings and such is just
         | creating a barrel module, that is--instead of models.py, have
         | models/__init__.py that imports (and thus re-exports)
         | everything from every file in the models folder. Then I can
         | have a single model per file, as it should be.
         | 
         | I'll never understand the conventions of Python land, but at
         | least the language is flexible enough to do it properly.
        
           | bena wrote:
           | Yes, that's the way to do it.
           | 
           | Python is fairly accepting with modules being either
           | directories or files.
           | 
           | Going the dir/__init__.py route also allows you to do a bit
           | of encapsulation as you can not export things.
           | 
           | Of course, someone could import from your file directly
           | still. But, yeah, there is no reason to keep _all_ of your
           | models in a single file.
        
           | adithyareddy wrote:
           | Zulip does this: https://github.com/zulip/zulip/blob/main/zer
           | ver/models/__ini...
           | 
           | Zulip in general is a great example of a large open source
           | Django app that's been maintained and actively developed for
           | a long time. I use it as a reference quite a lot.
        
         | dsego wrote:
         | You have dozens of apps (modules) each having its own models.py
         | with a handful of models.
        
       | pmontra wrote:
       | I'm working on a Rails and on a Django project for two different
       | customers and I've been doing that for years now. I'd pick Rails
       | over Django any time for every single feature.
       | 
       | The absolute worst Django feature is the templating language. It
       | seems to be designed to slow down developers to the like of old
       | time Java web apps, almost mandatory templatetags et all.
       | 
       | The query language is moderately bad, quite verbose
       | (Model.objects every time) for no good reason.
       | 
       | The lack of common project structure means that every project is
       | different.
       | 
       | There is no Capistrano to deploy. I wrote something like that
       | myself and we have been using it for maybe 7 years.
       | 
       | I'm sure I could go on for a while if I keep thinking about it,
       | but you got the gist of it.
       | 
       | On the Rails side, sometimes I'd like to have a talk with some of
       | the previous developers of the Rails app, which hid some
       | important functionality in a before save callback in a different
       | module for no particular reason, but one can be too clever with
       | Python too. However the language (Python) is quite dull, which
       | can be a good or a bad thing. It's very subjective. It's a Ruby
       | gone bad at design time to me.
        
         | kamikazeturtles wrote:
         | Python is used for much more than just web dev and Django,
         | whereas Ruby seams to only be synonymous with Ruby on Rails.
         | 
         | Do you think Rails is still worth using when investing in
         | learning Python and Django has a much higher roi?
        
           | karolist wrote:
           | Majority of learning surface will come from framework and not
           | the language, if you need Python elsewhere just learn that as
           | well, but this shouldn't move framework choice much.
        
             | Tronno wrote:
             | Ruby, and Rails in particular, has a lackluster dev
             | experience with any editor that isn't RubyMine. That's been
             | a huge obstacle for me personally.
        
               | Joe_Cool wrote:
               | Although a bit annoying to install I am still using the
               | rails plugin for NetBeans.
               | 
               | I just never switched to Aptana or Rubymine and now I
               | don't wanna.
        
               | Lio wrote:
               | Each to their own I guess.
               | 
               | Personally I like the ruby-lsp and TPope's Rails plugin
               | in NeoVim.
               | 
               | I dislike heavy weight IDEs, I never find the juice is
               | worth the squeeze.
        
               | weaksauce wrote:
               | ruby-lsp and rails-lsp from shopify is pretty good right
               | now and getting better by the day. the vscode extension
               | handles it well too.
        
             | infamia wrote:
             | > Majority of learning surface will come from framework and
             | not the language
             | 
             | Once you get past the beginner level in Django, you're
             | going to pick up a ton of Python knowledge (standard dunder
             | methods, MRO, standard lib, data type's im/mutability,
             | package ecosystem, etc.) and muscle memory along the way.
             | Django (for the most part) is just plain old Python data
             | structures, classes, and functions that a decent Django dev
             | will apart, reuse, override, repurpose, and add on to as
             | they do more interesting things. Python is boring (in a
             | good way), however it has _a lot_ of surface area (std lib
             | is massive) and intricacies that a Django dev will pick up
             | along the way to becoming an intermediate /advanced dev. It
             | would take someone coming in fresh to Python quite a while
             | to catch up. Naturally, if the same person knew several
             | languages, the ramp up would be quite a bit quicker.
        
           | criddell wrote:
           | It sounds like you've already made your choice and it's a
           | good one. Go with Python and make great stuff.
           | 
           | Rails has been around two decades, Ruby three. Both will
           | still be there down the road when you decide to try it out. A
           | lot of what you learn in your Python work will translate in
           | some way to Ruby & Rails.
        
           | RangerScience wrote:
           | Yes. You learn unique, transferable things from every
           | language and framework; usually, techniques and perspectives,
           | but also confidence and theory.
           | 
           | I'd also contest your statement that learning Python and
           | Django have a "much higher ROI" - but, I don't actually want
           | to get into it.
        
         | giancarlostoro wrote:
         | Funny you mention templating, its one key thing I'd change
         | about Django, that... and maybe scaffolding, I'd crank it up
         | drastically more.
         | 
         | My ideal enhancement to Django would be something like how
         | Microsoft made Razor into Blazor... A template engine that can
         | run purely on the back-end or purely on the front-end,
         | replacing any need to ever use JavaScript, you stick to your
         | native programming tongue if you will.
        
           | davepeck wrote:
           | I think of Django's templating system as a great tool for a
           | previous era. I'm hopeful that PEP 750 [1] gets accepted and
           | a modern ecosystem of template engines emerges in Python-
           | land. For the moment, I tend to use in-python builders like
           | htpy [2] when I want back-end Python code to generate some
           | HTML.
           | 
           | [1] https://pep-previews--
           | 4124.org.readthedocs.build/pep-0750/
           | 
           | [2] https://htpy.dev
        
         | ic_fly2 wrote:
         | The whole appeal of Django is that you can just swap in a
         | different templating engine / syntax if you prefer.
         | 
         | And you can add a DB and let there be managed by some other
         | system.
         | 
         | Same goes for extending manage.py
         | 
         | I've worked on Django projects big and small and generally the
         | speed are which we could deliver even on strange edge cases
         | impressed.
        
           | mostlysimilar wrote:
           | You can do that with Rails too. The difference is that Rails
           | defaults are very good.
        
             | aerhardt wrote:
             | The Rails dev says that Rails defaults are very good and so
             | says the Django dev about the Django defaults.
             | 
             | The Django ORM is loved by tens, maybe hundreds of
             | thousands of Python devs globally, and while I could raise
             | concerns about it (for example, the async experimental
             | capabilities fucking suck, and the core dev team is
             | extremely slow to innovate on them on the basis that that's
             | not "the Django way"), I've never heard anyone but a Rails
             | dev complain that it's "too verbose".
             | 
             | People love it so much that they'll do atrocities like
             | import it into Jupyter notebooks or simple scripts that
             | should otherwise have no business in bringing in those type
             | of dependencies. I should know because when I've felt
             | creative and a bit naughty about doing those types of
             | things I've found out - to my unmeasurable disappointment -
             | that there were many other trailblazers before me to write
             | gists, Medium articles, and almost everything every type of
             | format short of an entire O'Reilly book on how to do it.
        
               | deaddodo wrote:
               | > I've never heard anyone but a Rails dev complain that
               | it's "too verbose".
               | 
               | Maybe not too verbose, but there's a large population of
               | python devs that find SQLAlchemy (+ Alembic) the much
               | better option.
        
               | kshahkshah wrote:
               | That's curious to me honestly. I really prefer the
               | ergonomics of Django's ORM compared to when I've had to
               | use SQLAlchemy+Alembic in the past. I find alembic
               | incredibly confusing and poorly documented. Not that
               | documentation matters as much nowadays with AI
        
               | adammarples wrote:
               | Actually the dango dev is saying that the whole appeal of
               | dango is that you can swap the defaults out easily, kind
               | of the opposite
        
         | techscruggs wrote:
         | A bit off topic, but whenever Rails and templating get brought
         | up, I have to plug my absolute favorite project out there:
         | Phlex https://beta.phlex.fun/. It's like ViewComponents, but
         | swap out the ERB for pure Ruby. It has been a joy to develop
         | with.
         | 
         | With the addition of Phlex::Kit, it has made building out a
         | component library pretty easy too. RubyUI
         | https://github.com/ruby-ui/ruby_ui does a great job of showing
         | off how to do this.
        
           | petepete wrote:
           | Funnily enough I write most of my view components without a
           | template these days, unless there's a load of markup.
           | 
           | I keep meaning to take a look at Phlex.
        
           | pmontra wrote:
           | Those kind of things used to be a lose lose proposition back
           | at the time of haml (?) and all the yaml like templating
           | languages. That was more than 10 years ago. The reason was
           | that any designer that could actually do html was able to
           | write an erb page, maybe except loops and logic, but they
           | could understand them if a developer added them into the page
           | later. On the other side with one of those languages, and
           | more with phlex, only a developer could write the views so we
           | were back to the 90s with photoshop layouts.
           | 
           | Furthermore your can't copy and paste examples. Think about
           | Bootstrap components. You have to really write everything
           | from scratch.
        
         | whalesalad wrote:
         | Rails is 10x better than Django in every way and it isn't even
         | close.
        
         | pmontra wrote:
         | I add one item to my own list: Django admin, being backed by
         | default into the framework is a good thing. Rails has
         | ActiveAdmin but it's a separate gem and it requires more work
         | to integrate. Furthermore, being extra work is something that
         | some customers don't want to pay for. With Django, it's always
         | there.
        
         | dethos wrote:
         | I've worked for many years with both frameworks. I have the
         | opposite view, since I prefer the Django ecosystem and Python.
         | 
         | Rails has nice things, but overall, I prefer Django's approach
         | and the language it uses.
        
         | mlboss wrote:
         | For an alternative django templating, I would recommend htpy.
         | https://htpy.dev/
        
         | mrsilencedogood wrote:
         | I've used rails for years, and have used old versions of django
         | at one company, and used python extensively for non-web
         | purposes.
         | 
         | I think my take is that there's no middle-ground between Rails
         | and some of the newer Java-based frameworks.
         | 
         | Either I'm doing a side project or startup, and I need to go as
         | FAST as possible, type systems and similar be damned, or I'm OK
         | with not going as fast as possible and we're going to go slower
         | but deliver something very solid.
         | 
         | Python/django still had me spending a bunch of time on stuff
         | that rails will either generate, scaffold, or hide from you
         | completely. While still not being nearly as safe or performant
         | as anything in the Java world. Note I'm mostly thinking about
         | more modern frameworks like Javalin, not necessarily Spring's
         | entire ecosystem/way-of-life.
        
           | theflyinghorse wrote:
           | I was not aware of Javeline being used in the same way that
           | RoR/django/Laravel would be used. Javeline provides
           | primitives to build a backend/API layer only no?
        
         | paulddraper wrote:
         | Rails is so good it succeeded despite Ruby.
         | 
         | Django's main benefits are
         | 
         | 1. Admin interface 2. Python
        
           | kshahkshah wrote:
           | Unfortunately for Rubyists (myself included) those are huge
           | benefits though nowadays. It's much easier to find Python
           | developers.
           | 
           | Having an out-of-the-box admin interface means business
           | people can operationalize and workaround short comings of the
           | software today, not tomorrow. I think functional admin
           | interfaces can often be the difference between a successful
           | company and one which is constantly operating off of
           | spreadsheets in the background and never fully commits to
           | their software.
        
       | wfleming wrote:
       | > Migrations in Django > > The Django approach has noteworthy
       | differences and a slightly different workflow
       | 
       | My explanation of Django's approach to migrations would involve a
       | lot more expletives. It is by far my least favorite thing about
       | the framework.
       | 
       | - Fields are not-null by default, the opposite of SQL itself
       | 
       | - Field declarations use argument names that _sound_ like the SQL
       | equivalents (default, on delete cascade /restrict), but they're
       | fully enforced in python and don't make it into the SQL schema at
       | all by default. I get that not every DB supports these features,
       | and there are sometimes good reasons for doing something like a
       | delete cascade in process (if you need to implement custom on-
       | delete logic or something), but the DSL shouldn't read like SQL
       | if it's not going to change the SQL schema. The default value
       | thing combined with not-null by default is particularly easy to
       | get bitten by adding a new field with default if you deploy
       | migrations separately from deploying code (which you must do to
       | avoid downtime): if you add a new field with a default value
       | believing it's safe, you will probably get crashes in the
       | interval between applying the migration & the new code deploying
       | because you've got not-null column without a default value in the
       | schema. They did finally add db_default recently, thankfully, but
       | it took years!
       | 
       | - Django migrations cannot be understood in isolation, the sql a
       | generated migration containing something like an AlterField
       | operation will run depends on what _earlier_ migrations say. You
       | have to check with the sqlmigrate command and /or actually read
       | earlier migrations to be sure you understand what the migration
       | will do. Compared to Rails, where each migration can be read and
       | understood in isolation (though you may still need to understand
       | how a Rails migration DSL will translate to actual SQL of
       | course). This also has a performance impact making Django
       | migrations slower because Django has an in-memory model of what
       | the schema should be at each migration point, so running a
       | migration is not just "load the file and run the commands", it's
       | "determine the schema that should exist after running this
       | migration, diff that with the schema we think exists before this
       | point, magically generate SQL for that diff, then run that".
       | 
       | - The makemigrations command to auto-generate pending migrations
       | is very aggressive and will detect things as "changed" that don't
       | impact the schema. If you changed some help text on a field, or a
       | localization string, or the aforementioned only-in-python default
       | value, makemigrations will see that as requiring a migration that
       | does nothing. Leads to lots of cruft.
       | 
       | - Related to both of the above points, AlterField's auto-
       | generated SQL can be dangerous and bad. Particularly, I've seen
       | cases where very minor changes to a ForeignKey (like changing
       | from nullable to not-nullable, or even not-schema-impacting
       | changes like above) would, by default, have dropped the foreign
       | key constraint & index, and then re-created them. Completely
       | unnecessary and potentially dangerous since it could be locking a
       | large table. I'm not positive, but in some cases I think these
       | have been generated purely because of a django upgrade leading to
       | it deciding the names of the indexes/constraints need to be
       | changed for some reason.
       | 
       | - AlterField will _also_ tend to stomp all over any tweaks you
       | manually made to the schema to work around all these issues. If
       | you manually wrote a SQL statement in an earlier migration to add
       | a default value to a column, and then that column 's definition
       | gets tweaked months or years later the generated AlterField is
       | gonna remove your default value. At a technical level this isn't
       | surprising when you understand how Django is modeling the schema
       | internally & generating the SQL changes, but it's definitely a
       | bad user experience downstream of a lot of these design
       | decisions.
       | 
       | Generally the field declaration/migrations system in Django feels
       | to me designed to lead people down a garden path towards bad and
       | dangerous behavior. If I had my druthers I'd enforce a policy in
       | our Django app of "never run makemigrations, all migrations must
       | be manually written SQL".
        
         | infamia wrote:
         | > The default value thing combined with not-null by default
         | 
         | It is interesting... I strongly feel the opposite after
         | debugging far too many SQL queries where someone checked for an
         | empty string but forgot to check for NULL. NULL by default is a
         | SQL footgun IMO.
        
           | wfleming wrote:
           | I prefer null as a clear "no value" marker to handle rather
           | than special-casing handling of an empty string vs other
           | strings, and if "empty string" isn't considered valid that
           | should be validation logic and that should never get stored
           | in the database. But it's certainly a matter of opinion and
           | either can work as long as you're consistent.
           | 
           | The point about Django's choices about default and not-null
           | though is that it can easily lead to crashes while you're
           | adding fields. If you add a string field with default="" and
           | don't specify null=False, the generated schema will be a non-
           | null field without a default value in SQL, but Django will
           | backfill "" into all existing rows. To avoid downtime, you
           | need to deploy migrations & apply them, then deploy the
           | models.py/other code changes. But if anyone tries to write a
           | new row before the new code finishes deploying after applying
           | the migration, it will crash.
        
         | alephxyz wrote:
         | > Generally the field declaration/migrations system in Django
         | feels to me designed to lead people down a garden path towards
         | bad and dangerous behavior. If I had my druthers I'd enforce a
         | policy in our Django app of "never run makemigrations, all
         | migrations must be manually written SQL".
         | 
         | `makemigrations --dry-run` is helpful to see if your manual
         | migrations are complete but besides that I agree
        
       | czhu12 wrote:
       | I worked significantly in both Django and Rails, and I found the
       | most magical part of rails is its ORM (ActiveRecord). I find both
       | SQLAlchemy and DjangoORM both more awkward and less natural to
       | use, both for the query side and the relationship definition
       | side.
       | 
       | Once the data is loaded into memory, everything else is just
       | syntax.
       | 
       | At this point, I only reach for python as a web application if I
       | need to build something that has AI / ML features. Rails apps
       | I've built in the past that needed to call a local model resulted
       | in having to create a python inference microservice, which kinda
       | sucks.
        
         | RangerScience wrote:
         | FYI, there's a few projects out there for interoperability
         | between Ruby and Python - stuff like putting one language in
         | another.
         | 
         | Also, Jupyter and Zeppelin notebooks allow for
         | interoperability, although I don't know how.
         | 
         | (Oh, lastly, if there's a JVM implementation of Python you
         | could probably use alongside JRuby)
        
       | kitsune_ wrote:
       | I have yet to see a software project where ActiveRecordish ORMs
       | did not end up making the modelling of business processes and
       | translation of use cases into code overly messy and complicated,
       | Rails or Django.
        
         | RangerScience wrote:
         | The Rails apps I've worked with where there was an ORM mess
         | (which yeah... is all of them) it's extremely clear that the
         | mess is the normal "too fast" software development mess. Sure,
         | it's worse because it's the ORM (and/or sharp knives), but it's
         | also always been the case that I can clean it up with _better_
         | use of Actuve Record.
         | 
         | Also, I've worked with some pretty gnarly pure-SQL systems that
         | had essentially the same kinds of problems.
         | 
         | It's all just variations on "saving hours of planning with
         | months of work" kind of things.
        
           | Tainnor wrote:
           | Rails and especially DHH particularly encourage not having
           | any sort of separation between your domain objects and your
           | persistence (and even your views), which is why N+1 queries
           | are so goddamn common and why people are going to put
           | confirmation mail logic in model callbacks etc.
        
         | devjab wrote:
         | I can't speak for rails's ActiveRecord but I don't think
         | DjangoORM is worse than any other ORM in that regard. It's
         | probably one of my favorite ORMs. I don't think I'll ever
         | really use it again but that includes every other ORM.
        
           | kitsune_ wrote:
           | I mean there is a clear difference in how ORMs that use the
           | data mapper pattern like Hibernate or Entity Framework etc.
           | ultimately allow for a cleaner overall application
           | architecture vis-a-vis ActiveRecord (the pattern) which
           | usually ends up leaking throughout the entire application.
        
             | devjab wrote:
             | I think we agree. I don't think there is that much
             | difference between ORM patterns (and I'm sorry I
             | misunderstood you) because they all eventually become more
             | trouble than they are worth in larger and more serious
             | projects. I agree that you can probably go further with
             | data mapper pattern ORMs, like EF, but I'm not sure I think
             | the same is true for something like DjangoORM vs
             | SQLAlchemy. On the flip-side a lot of projects will do fine
             | with any ORM and never run into issues over their
             | lifecycles.
             | 
             | Though in a world of SQLC (and similar) I'm not sure what
             | ORMs are really solving for anyone anymore.
        
       | brap wrote:
       | With all of this praise Rails is getting, even still in 2024,
       | it's mind boggling how there was never a successful Rails
       | alternative in one of today's popular web programming languages.
       | Nothing ever caught on.
        
         | joshlemer wrote:
         | Laravel and Django don't count?
        
       ___________________________________________________________________
       (page generated 2024-12-11 23:00 UTC)