10 ms·
Django and Postgres for the Busy Rails Developer
- deleted 2y ago[deleted]
- Supernaut 2y agoAs 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 2y agoWe 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 2y agoI'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 2y agoYes, 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 2y agoZulip does this: https://github.com/zulip/zulip/blob/main/zerver/models/__init__.py https://github.com/zulip/zulip/blob/main/zerver/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.
- curiousgal 2y agoWhy are they using the as?
- dsego 2y agoYou have dozens of apps (modules) each having its own models.py with a handful of models.
- pmontra 2y agoI'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 2y agoPython 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 2y agoMajority 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 2y agoRuby, 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.
- 2y ago
- wfleming 2y ago> 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".
- czhu12 2y agoI 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 2y agoFYI, 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)
- dlx 2y agoAny recommended ones? Like the parent, I have to reach for Python for AI / ML work and would love to use Rails as the web frontend instead of Django.
- RangerScience 2y agoFor that, I’d just use Rails, and the connect AI/ML tools over an api or (riskier) direct to the DB. The stuff I looked at ages ago was for literally embedding Python code in Ruby code. I never used any of it either, so I don’t have any recommendations. Edit: Actually, rather than have Python connect to the Rails DB, have Rails also connect to the Python DB (note that this can be on the same db server, etc). Rails can then handle all the “I’m a product” stuff (user accounts, etc) and then read the Python data for the rest. Would that work?
- kitsune_ 2y agoI 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 2y agoThe 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 2y agoRails 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.
- RangerScience 2y ago> your domain objects and your persistence Hmm. Thinking over my career... Maybe I don't know what you mean by "domain objects", "separation", and "persistence", but when I think over the stuff I've worked on in my career, and the problems I've seen in codebases... Yeah, I think I'm with them on this - your domain objects and your persistence should pretty much be the same thing. There's gonna be a few exceptions (and, ofc, you can do a shit job building the models), but I expect those to be short-lived and small. Otherwise, you shouldn't have domain _objects_ doing all that, you should have functions operating on data, and the data is pretty much always going to be either (1) some incoming hash or (2) some database record; then you group the functions into handy modules for humans. And then they're not domain _objects_. Do you have a good example of a "domain object" that you think really _should_ be heavily separated from persistence? PS - The one time that comes to mind that might fit, the data I wanted to persist was essentially logging data on the operation that was performed on other data. PPS - N+1 queries are kinda trivial to resolve in most cases in Rails? There's core ORM functionality for it. PPPS - Yeah, don't put your confirmation mail logic in the model callback, that's a bad plan. Fake edit: Like, you either have data you want to persist, or you have data you're transforming. If you're transforming it, it's temporary, and either I don't understand what a "domain object" is, or I think you'd make a mistake to make your temporary data into a domain object.
- brap 2y agoWith 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 2y agoLaravel and Django don't count?
- Kerrick 2y agoThose are definitely successful by popularity metrics. Adonis (node), Loco (rust), and Phoenix (elixir) are successful by productivity metrics, too.
- brap 2y agoThere are several comments ITT that explain how far behing Django is. As for Laravel, I personally don't know anyone starting a project in PHP in 2024 unless there's a strong legacy reason to do it
- Tainnor 2y agoEveryone who got tired of Ruby and Rails during its hype years has since moved on to various other technologies, now most of the people who are still working on Rails are the people who agree with its design choices, which explains the amount of praise it gets. IMHO the major upsides of Rails were subsequently adopted by almost all major frameworks in other languages. It may not be sexy or make HN front page a lot, but Spring Boot definitely "caught on", for example.
- davidkwast 2y agoWell. I use GeoDjango with PostGIS. Django supports it natively. And django-rest-framework takes it to another level. Python has the best machine learning and AI support too. It is very easy to mix geographic libs with data science tools. To build a simple CRUD software with vanilla SQL you really don't need Django and Python. But I challenge any one to try a GIS full stack without Django and Python. Just look for GDAL, pyproj, shapelly, fiona and MapLibre/Mapbox. And it really powerful to combine with HTMX or Vuejs for reactive SPAs
- sroerick 2y agoI second this 100%
- ltbarcly3 2y agoDjango is a framework made of several components: - ORM: bizarre and can't generate lots of common SQL you will want to generate. Weird joins via counting underscores. Horrible errors that don't make sense. Lots of builtin functions have never worked and they won't fix them. (ROUND has never worked!) - Template language: Slow and borderline unusable. are 50 pages of recursive nonsense tracebacks that doesn't tell you anything usable. - Web app (controller) framework: Terrible and inflexible Each of these components is a piece of shit. Don't use Django. I suggest: - ORM: Sqlalchemy: probably one of the best ORMs in any language, good performance and very flexible. It won't get in your way much. - Templates: jinja2: basically identical to django templates but faster and usable tracebacks are perfect - Web app: Flask or werkzeug, but there are lots of good options here. Django is the worst.
- andybak 2y agoAs someone that's inherited Flask projects that attempted to match Django levels of functionality, I couldn't disagree more.
- ltbarcly3 2y ago"Level of functionality" what does that mean? I've been at this a while: https://news.ycombinator.com/item?id=1490415 https://news.ycombinator.com/item?id=1490415
- andybak 2y ago> I've been at this a while I'm not sure how much it adds to the discussion but so have I. Although I've taken a step back from doing web dev directly in the last few years, I have been a Django dev since about 2006. But before we get into that kind of silly comparison let me put it another way. There are plenty of people more experience than both of us, that hold Django in high-regard. I know developers tend to hold strong opinions about their tools and that's all fine - but you are rather hyperbolic about several matters that seem to be closer to personal preferences than they are absolute truths.
- sroerick 2y agoI’ve spent a lot of time with Django, and not a lot of time with rails. For me, if I was doing minimalist CRUD and wanted to ship to mobile or a lot of users, I’d reach for Rails. Hotwire and Turbo seem great, and the ecosystem just seems better and more developed for customer facing stuff. Most of my work has been internal tooling with an emphasis on data analytics or geospatial. Having python libs run natively is a big win for data analysis, and as another commenter posted, geodjango is very tough to beat for usability for geospatial work. For this I still maintain Django is pretty unbeatable. I am happy to be corrected in both domains though, again, not much rails experience here beyond a couple toy projects.
- block_dagger 2y agoI think Rails would be better off with TOML vs YML but otherwise I think Rails is better. Disclaimer: I’ve built dozens of Rails apps but never a full Django app. I dislike significant whitespace.
- deleted 2y ago[deleted]