• Django

    ,

    Python

    🐘 Django Migration Operations aka how to rename Models

    Renaming a table in Django seems more complex than it is. Last week, a client asked me how much pain it might be to rename a Django model from Party to Customer. We already used the model’s verbose_name, so it has been referencing the new name for months.

    Renaming the model should be as easy as renaming the model while updating any foreign key and many-to-many field references in other models and then running Django’s make migrations sub-command to see where we are at.

    The main issue with this approach is that Django will attempt to create a new table first, update model references, and then drop the old table.

    Unfortunately, Django will either fail mid-way through this migration and roll the changes back or even worse, it may complete the migration only for you to discover that your new table is empty.

    Deleting data is not what we want to happen.

    As it turns out, Django supports a RenameModel migration option, but it did not prompt me to ask if we wanted to rename Party to Customer.

    I am also more example-driven, and the Django docs don’t have an example of how to use RenameModel. Thankfully, this migration operation is about as straightforward as one can imagine: class RenameModel(old_model_name, new_model_name)

    I re-used the existing migration file that Django created for me. I dropped the CreateModel and DeleteModel operations, added a RenameField operation, and kept the RenameField operations which resulted in the following migration:

    from django.db import migrations
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('resources', '0002_alter_party_in_the_usa'),
        ]
    
        operations = [
            migrations.RenameModel('Party', 'Customer'),
            migrations.RenameField('Customer', 'party_number', 'customer_number'),
            migrations.RenameField('AnotherModel', 'party', 'customer'),
        ]
    

    The story’s moral is that you should always check and verify that your Django migrations will perform as you expect before running them in production. Thankfully, we did, even though glossing over them is easy.

    I also encourage you to dive deep into the areas of the Django docs where there aren’t examples. Many areas of the docs may need examples or even more expanded docs, and they are easy to gloss over or get intimidated by.

    You don’t have to be afraid to create and update your migrations by hand. After all, Django migrations are Python code designed to give you a jumpstart. You can and should modify the code to meet your needs. Migration Operations have a clean API once you dig below the surface and understand what options you have to work with.

    Monday July 15, 2024
  • Vivaldi

    🔥 Why I deleted Firefox from my machines this weekend

    I no longer trust or believe in Mozilla, so I deleted Firefox from my machines this weekend.

    ➜ brew remove firefox
    ==> Uninstalling Cask firefox
    ==> Backing App 'Firefox.app' up to '/opt/homebrew/Caskroom/firefox/112.0.1/Firefox.app'
    ==> Removing App '/Applications/Firefox.app'
    ==> Unlinking Binary '/opt/homebrew/bin/firefox'
    ==> Purging files for version 112.0.1 of Cask firefox
    ~ on ☁️   took 4s
    

    There was no one decision, but Firefox version 128’s Privacy-Preserving Attribution update was the final straw.

    The default browser you use is a personal decision, and I have always kept Firefox around. It was my default for over a decade until I gave up and switched to Google Chrome. At that point, Firefox became bloated and buggy like the Mozilla browser before it, and I found myself at that intersection again.

    Last year, I switched to Vivaldi as my default browser and only kept Chrome around for a few organizations. Eventually, I’ll delete Chrome, too, but that’s more symbolic of removing Google from my life.

    What annoys me the most is that Mozilla was supposed to be the company that knows better, but their leadership keeps reminding us of who they are.

    Removing Firefox pains me because I believe in alternative browsers that aren’t controlled by one company. I have friends who have worked for Mozilla in the past and present.

    Had Mozilla pledged to cut the bullshit and give me a Firefox Pro option to support them, I would have been one of the first to sign up. However, I don’t trust Mozilla when they aren’t focused on being the best web browser in the industry. I’d rather avoid their antics until they give me a reason to trust them again.

    PS: Maybe Servo is a better alternative from Mozilla, but for now, Vivaldi is my best Chrome-like, and it’s not run by Google until something better emerges.

    Sunday July 14, 2024
  • Python

    🦆 DuckDB may be the tool you didn't know you were missing

    🤔 I haven’t fully figured out DuckDB yet, but it’s worth trying out if you are a Python dev who likes to work on data projects or gets frequently tasked with data import projects.

    DuckDB is a fast database engine that lets you read CSV, Parquet, and JSON files and query them using SQL. Instead of importing data into your database, DuckDB enables you to write SQL and run it against these file types.

    I have a YouTube to frontmatter project that can read a YouTube playlist and write out each video to a markdown file. I modified the export script to save the raw JSON output to disk.

    I used DuckDB to read a bunch of JSON files using the following script:

    import duckdb
    
    def main():
        result = duckdb.sql("SELECT id,snippet FROM read_json('data/*.json')").fetchall()
    
        for row in result:
            id, snippet = row
            print(f"{id=}")
            print(snippet["channelTitle"])
            print(snippet["title"])
            print(snippet["publishedAt"])
            print(snippet["description"])
            print()
    
    
    if __name__ == "__main__":
        main()
    

    This script accomplishes several things:

    • It reads over 650 JSON files in about one second.
    • It uses SQL to query the JSON data directly.
    • It extracts specific fields (id and snippet) from each JSON file.

    Performance and Ease of Use

    The speed at which DuckDB processes these files is remarkable. In traditional setups, reading and parsing this many JSON files could take significantly longer and require more complex code.

    When to Use DuckDB

    DuckDB shines in scenarios where you need to:

    • Quickly analyze data in files without a formal import process.
    • Perform SQL queries on semi-structured data (like JSON)
    • Process large datasets efficiently on a single machine.

    Conclusion

    DuckDB is worth trying out in your data projects. If you have a lot of data and you need help with what to do with it, being able to write SQL against hundreds of files is powerful and flexible.

    Saturday July 13, 2024
  • 🚜 macOS Bartender app to Ice app

    I upgraded my Macs to macOS Sonoma a few weeks ago. While everything has been uneventful, the Bartender app pinged me one too many times about upgrading to Bartender 5, which has several Sonoma-only features.

    Last year, I looked forward to upgrading Bartender until their recent botched communication and messaging regarding the purchase of the app.

    Oliver Andrich’s Week 23: An Almost Perfect Week was the nudge I needed to go ahead and switch over to Ice, which is an open-source menu bar manager for macOS.

    The upgrade took less than a minute, and the app worked the same way Bartender did for me. I changed the menu icon to an ellipsis to match what I had the Bartender app set to, and everything worked.

    Previously

    Friday July 12, 2024
  • Gaming

    🎮 8BitDo Golden/Silver Limited Edition controllers

    My favorite third-party video game hardware company, 8BitDo, announced its 11th-anniversary limited edition controllers, SN30 Pro - Golden/Silver Limited Edition.

    I have over half a dozen 8BitDo controllers (and even a keyboard), my favorites, and what we pick up when my family wants to game on our Switch or iPad.

    I wanted the SN30 form factor but have yet to order one. I don’t know if a metal, wired controller will fit into my library, but they tempt me.

    Thursday July 11, 2024
  • Office Hours

    📅 Office Hours for July 12th

    Office Hours returns this Friday, July 12th, 2024, from 2:30 pm to 4:30 pm Central Time.

    ℹ️ Anyone can join office hours. Many join because they work remotely, miss seeing faces, and miss the random conversations when a small group hangs out.

    ℹ️ Our office hours are a collaborative space where we can discuss our ongoing projects, catch up, and work together to wrap up our week on a productive note.

    💼 I will be working on all the things this week.

    🙏 As always, everyone is welcome to join, whether you’re a regular attendee or joining for the first time.

    ✅ If you need any additional details, feel free to send me a message or check out the gist from our previous sessions, where you’ll find the Zoom link ⚠️

    I look forward to seeing everyone.

    Wednesday July 10, 2024
  • 🔓 Sharing is Caring: How a Simple Sudo Question Led to Better Solutions

    One of the fun discoveries of blogging is finding your article in search results while trying to solve a problem.

    A few weeks ago, I upgraded my Macs to macOS to Sonoma, but I hadn’t yet re-enabled passwordless authentication via sudo. If this were a server in the cloud, I would approach it differently, but on my laptop, it’s a different story, and I can skip re-typing my password.

    I stumbled on my TIL: Enable sudo without a password on MacOS post from 2022 when I was searching for a quick fix.

    I also posted on Mastodon about this, which led to Anthony’s helpful suggestion that I could instead use Touch ID which I liked a lot.

    I wish I could use Touch ID, but I often use SSH and Remote Desktop. Touch ID will only work if my finger is there. It’s still an excellent suggestion for anyone seeking a more secure way to assume sudo access.

    Dan Ryan pointed me to a better solution than my existing workaround, which doesn’t get overwritten every major macOS update.

    Helpful suggestions like these are why I like to think out loud and share these thoughts on Mastodon.

    Tuesday July 9, 2024
  • Weeknotes

    📓 Weeknotes for Week 27: July 1 to 7

    The last week was a blur between the holiday, travel, and cramming a lot of work. My notes this week are more glossed over than most

    Family

    We drove to Illinois (near Chicago) to see family this week. We had family from both coasts who we don’t see very often, and it was the first time much of the family met my youngest, Nora. It takes us 8 to 8.5 hours to drive there, and people are always amazed at how good my kids are at traveling these distances. They both love the extra screen time and are easy to travel with. We can hand each one an iPad, and they are set for hours, given enough snacks and a rest stop every few hours.

    Work

    It was a short two-day week, but I got a bonus third day of work between fitting a few hours in the car and half a day on Friday. This was nice because we are wrapping up an existing client project while ramping up on another project.

    This has also made me realize that Django has many shopping cart projects, but they all seem to be outdated. We struggled to find a project we could use, which made me realize that the Django community is sorely missing a good shopping cart and checkout experience that works.

    Community Work

    Djangonaut Space: All three Djangonaut Space Team Neptune members have made meaningful contributions early in the process, and now I’m feeling the pressure to detail and share some more advanced projects so they can have tasks for the duration of the project.

    Django Code of Conduct WG: We have prioritized keeping up as we get new members used to contributing. This week, was a busy week.

    Side projects

    Django News Newsletter: We shipped issue #240.

    Django News Jobs: We have had code to aggregate some other Django job boards, and this week, we started allowing those to come through.

    Writing

    This week, I was back on track, and I wrote and published something every day. It was my first day of giving myself a buffer so that I am always writing tomorrow’s post, which took the edge and pressure off. I am still writing every day, but with the holiday, it was nice knowing I didn’t have to fit it in on our last day in Chicago, which ended up being a really long, full day with family.

    2024-07-07🧰 More fun with Django Extensions using shell_plus and graph_models Yesterday, I wrote about Django Extensions show_urls management command because it’s useful. I …

    2024-07-06Django Extensions is useful even if you only use show_urls Yes, Django Extensions package is worth installing, especially for its show_urls command, which can …

    2024-07-05📅 No Office Hours on July 5th, but… No Office Hours this week (July 5th), but we will return next Friday, July 12th, 2024, 2:30 pm to …

    2024-07-04🎆 🤖 Happy AIndependence Day To everyone in the United States, Happy Independence Day and Happy AIndependence Day to everyone …

    2024-07-03🗳️ PSF Elections how I am voting This was written while driving to Chicago (technically from the passenger seat). Still, a few people …

    2024-07-02💬 On the PSF Bylaw changes The Python Software Foundation has three bylaw changes up for a vote in this year’s election. …

    2024-07-01📓 Weeknotes for Week 26: June 24 to 30 Family I took two days off for a funeral and some other family stuff. I saw cousins and other …

    Entertainment

    📺 Sweet Tooth - I really liked this series.

    📺 Presumed Innocent - I watched the first five episodes, and it’s okay.

    📺 The Last Thing He Told Me - I just started this series on Sunday night and am unsure if I’ll finish it.

    Next week

    It’s my first whole week back in a while. I’m looking forward to catching up and mowing my yard while listening to podcasts. I need to catch up on house stuff, including running my homemade above-ground sprinkler system. (Chill; we live near the Kansas River.)

    Monday July 8, 2024
  • Django

    🧰 More fun with Django Extensions using `shell_plus` and `graph_models`

    Yesterday, I wrote about Django Extensions show_urls management command because it’s useful. I have Mastodon posted/tooted about it [previously](https://mastodon.social/@webology/110271223054909764, but I didn’t expect it to possibly lead to it being added to Django, and yet here we are. My favorite byproduct of blogging is when someone talks about something they like, and someone asks, “What if” or “Why doesn’t?” and then they get inspired to look into it and contribute. This post might have led to one new contribution to Django. 🎉

    Several people shared that they also liked Django Extensions shell_plus and graph_models management commands.

    I don’t use shell_plus often, but I bake it into my Just workflows for clients who do. I tend to forget about it, and I spend so much time using pytest.set_trace() and testing.

    If you haven’t used graph_models, I use it in most of my client projects. I generate SVG files with it and add them to an ERD section of their docs, which helps discuss models and onboard new developers. It’s a nice-to-have feature and is a small lift with a huge payoff. This code is also easy to copy and paste from project to project.

    Sunday July 7, 2024
  • Django

    ,

    Python

    Django Extensions is useful even if you only use show_urls

    Yes, Django Extensions package is worth installing, especially for its show_urls command, which can be very useful for debugging and understanding your project’s URL configurations.

    Here’s a short example of how to use it because I sometimes want to include a link to the Django Admin in a menu for staff users, and I am trying to remember what name I need to reference to link to it.

    First, you will need to install it via:

    pip install django-extensions
    
    # or if you prefer using uv like me:
    uv pip install django-extensions
    

    Next, you’ll want to add django_extensions to your INSTALLED_APPS in your settings.py file:

    INSTALLED_APPS = [
        ...
        "django_extensions",
    ]
    

    Finally, to urn the show_urls management command you may do some by running your manage.py script and passing it the following option:

    $ python -m manage show_urls
    

    Which will give this output:

    $ python -m manage show_urls | grep admin
    ...
    /admin/	django.contrib.admin.sites.index	admin:index
    /admin/<app_label>/	django.contrib.admin.sites.app_index	admin:app_list
    /admin/<url>	django.contrib.admin.sites.catch_all_view
    # and a whole lot more...
    

    In this case, I was looking for admin:index which I can now add to my HTML document this menu link/snippet:

    ... 
    <a href="{% url 'admin:index' %}">Django Admin</a>
    ... 
    

    What I like about this approach is that I can now hide or rotate the url pattern I’m using to get to my admin website, and yet Django will always link to the correct one.

    Saturday July 6, 2024
  • Office Hours

    📅 No Office Hours on July 5th, but...

    No Office Hours this week (July 5th), but we will return next Friday, July 12th, 2024, 2:30 pm to 4:30 pm and for what I hope is the rest of the summer. See my Office Hours Summer Schedule for details.

    If you are a conference or event organizer or want to be one, this month’s Conference Chats might still be running while you read this. Meeting details, including the Discord invite, are on the website.

    Friday July 5, 2024
  • 🎆 🤖 Happy AIndependence Day

    To everyone in the United States, Happy Independence Day and Happy AIndependence Day to everyone else.

    In the spirit of staying ahead of the game and ensuring our online security, I came across this article by Cloudflare, Declare your AIndependence: block AI bots, scrapers and crawlers with a single click.

    I’m already using Cloudflare on several domains, and I enabled the AI Scrapers and Crawlers blocking features on Django Packages, Django News Jobs, and several websites I managed.

    If you wrote a scraper for Django Packages and are impacted by this change, contact me, and let’s talk. We have an API, a better solution than spidering the website.

    Thursday July 4, 2024
  • 🗳️ PSF Elections how I am voting

    This was written while driving to Chicago (technically from the passenger seat). Still, a few people contacted me and asked me how I vote for PSF directors, so I wanted to share.

    If you can vote in the PSF election, please do so before Tuesday, July 16th, 2024, 2:00 p.m. UTC. For more details, check out their blog post, The 2024 PSF Board Election is Open! (The blog post lists the date incorrectly as ending on a Friday.)

    I served on the PSF board for five years, from 2018 to 2023, and here is what I am looking for when I research who to vote for this year.

    It’s a harder-than-normal slate of candidates because only three open seats are available, compared to four in the last few years. More candidates are new to me this year than most years.

    We also have some solid candidates running, which makes it even harder.

    Existing directors

    For existing directors, I look at:

    • How long have they served on the board?
    • What positions/roles did they serve while on the board?
    • What has the PSF accomplished during its term?
    • What was their meeting attendance like?
    • I read their previous candidate statements to see if the PSF accomplished what they said they wanted.
    • How did they treat the PSF’s staff in meetings, at events, and behind the scenes?

    All candidates

    For everyone, including existing directors, I read their candidate statements, and then I look at:

    • What do they value?
    • What their company and community affiliations are.
    • Understands and is committed to our Code of Conduct to promote a healthy community.
    • What workgroups did they participate in?
    • What are they committed to working on and changing in their next term?

    What I’m prioritizing

    I prioritize diverse candidates and representation. This includes geographical representation.

    I prioritize candidates who do not work for Big Tech / FAANG companies. These companies often give raises and promotions to employees who make it on open-source boards. It’s a KPI goal for some Dev Rels and I’m not here to help any Big Tech companies. Thankfully, I have served with many selfless directors, despite them working for Big Tech companies. Still, you have a right to know when you vote for someone if their position will check off one of their KPIs.

    I prioritize the Python community’s needs over individual needs.

    I prioritize candidates with a track record of getting things done over only showing up to be seen. (Yes, this is a thing.)

    I prioritize practical communication skills. If you write over the heads of the community, then you could be more effective at communicating.

    I’m looking for reform.

    Overall, I am looking for reform. A few public mishaps by the board have damaged the community’s trust in the organization.

    I want to see reform across those impacted workgroups, and I will prioritize candidates who show awareness of this. I considered listing them here, but “what I’m prioritizing” when I vote is not up for public debate. I might write more on this later.

    If you are running

    If you are running for the board, thank you for putting yourself out there.

    Wednesday July 3, 2024
  • 💬 On the PSF Bylaw changes

    The Python Software Foundation has three bylaw changes up for a vote in this year’s election. I support all there.

    Here is their post, For your consideration: Proposed bylaws changes to improve our membership experience and a follow-up post FAQ for Proposed Changes to PSF Bylaws that addresses questions that came up.

    Change 1: Merging Contributing and Managing member classes

    The existing two classes need to be clarified and updated. We want contributors, and code is only one of many ways to contribute to a healthy community.

    ✅ I’m all for this. I support this change.

    Change 2: Simplifying the voter affirmation process by treating past voting activity as intent to continue voting

    Before the voting affirmation process was enforced, meeting the 30% quorum mark was an issue.

    Last year, over 70% of our members voted, and I suspect we can land somewhere in the middle, letting people continue to vote if they did the previous year and still staying above 50% of our active membership voting.

    ✅ I support this change.

    Change 3: Allow for removal of Fellows by a Board vote in response to Code of Conduct violations, removing the need for a vote of the membership

    No one in the Python community is above Python’s Code of Conduct.

    While I disagree that the board cannot already remove a Fellow, it’s better to bring it to the community for a vote.

    ✅ As a Python Fellow, past board member, and Code of Conduct WG member, I support this change.

    Tuesday July 2, 2024
  • Weeknotes

    📓 Weeknotes for Week 26: June 24 to 30

    Family

    I took two days off for a funeral and some other family stuff. I saw cousins and other relatives who I only see at funerals, which is starting to feel like a habit.

    Work

    I was mentally blocked on a project, or at least the part I was putting off returning to. Something finally clicked over the weekend, and I worked through it. I hate working the weekends, which our company frowns upon. I didn’t expect to be out two days this week, and I’m out for the holiday most of the next week, so I tried to get caught up and ahead.

    Community Work

    Djangonaut Space: Week 2 kicked off, and I had to push our weekly standup back a week due to the funeral. No idea, but our Djangonauts are doing good work and working through their first issues.

    Side projects

    Django News Newsletter: We shipped issue #239.

    Django News Jobs: I had a weird issue that forced me to downgrade Python 3.12 to 3.11 to fix something internally that broke Pydantic. I’ll switch back in a few weeks, but I’m still annoyed by it.

    Overall, I just treaded water this week.

    Writing

    I shifted my writing schedule around this weekend so that I am a day ahead. I want to get four or five days ahead so that I have a nice publishing schedule to work with. I still plan on writing daily, but I like having more wiggle room.

    2024-06-30🐳 Using Just and Compose for interactive Django and Python debugging sessions When I wrote REST APIs, I spent weeks and months writing tests and debugging without looking at the …

    2024-06-29🐘 Docker Postgres Autoupgrades Upgrading Postgres in Docker environments can be daunting, but keeping your database up-to-date is …

    2024-06-28🐘 A Just recipe to backup and restore a Postgres database I have used this casey/just recipe to help backup and restore my Postgres databases from my Docker …

    2024-06-27📅 Office Hours for June 28th It’s been a week, but I’m hosting Office Hours this Friday at 2:30 pm. I was on the …

    2024-06-25🐳 Managing Docker Compose Profiles with Just: Switching Between Default and Celery Configurations For a recent client project, we wanted to toggle between various Docker Compose profiles to run the …

    2024-06-24🚜 Mastodon Bookmark exporter to Markdown/Frontmatter I wrote a Mastodon Bookmark exporter tool over the weekend and decided to polish it up and release …

    Entertainment

    📺 Presumed Innocent

    📺 Baby Reindeer

    📺 Dark Matter

    📺 The Acolyte - We got caught up, and OMG, it’s good.

    📺 The Flash (2023) - I couldn’t care less for the Flash, but I really enjoyed seeing Michael Keaton’s Batman again.

    Next week

    We are spending our holiday in Illinois to see family. It’ll be the first time my youngest has met several family members flying in for the holiday.

    Monday July 1, 2024
  • Python

    ,

    Justfiles

    ,

    Docker

    🐳 Using Just and Compose for interactive Django and Python debugging sessions

    When I wrote REST APIs, I spent weeks and months writing tests and debugging without looking at the front end. It’s all JSON, after all.

    For most of my projects, I will open two or three tabs. I’m running Docker Compose in tab one to see the logs as I work. I’ll use the following casey/just recipe to save some keystrokes and to standardize what running my project looks like:

    # tab 1
    $ just up 
    

    In my second tab, I’ll open a shell that is inside my main web or app container so that I can interact with the environment, run migrations, and run tests.

    We can nitpick the meaning of “console” here, but I tend to have another just recipe for “shell” which will open a Django shell using shell_plus or something more interactive:

    # tab 2
    $ just console
    

    In my third tab, I’ll run a shell session for creating git branches, switching git branches, stashing git changes, and running my linter, which I prefer to run by hand.

    # tab 3
    $ echo "I'm boring"
    

    Over the last year or two, the web has returned to doing more frontend work with Django and less with REST. Using ipdb, in my view, to figure out what’s going on has been really helpful. Trying to get ipdb to “just work” takes a few steps in my normal workflow.

    # tab 1 (probably)
    
    # start everything
    $ just start
    
    # stop our web container
    $ just stop web
    
    # start our web container with "--service-ports" 
    # just start-web-with-debug
    

    The only real magic here is using Docker’s --service-ports, which opens ports so we may connect to the open ipdb session when we open one in our view code.

    My main justfile for all of these recipes/workflows looks very similar to this:

    # justfile
    set dotenv-load := false
    
    @build *ARGS:
        docker compose build {{ ARGS }}
    
    # opens a console
    @console:
        docker compose run --rm --no-deps utility/bin/bash
    
    @down:
        docker compose down
    
    @start *ARGS:
        just up --detach {{ ARGS }}
    
    @start-web-with-debug:
        docker compose run --service-ports --rm web python -m manage runserver 0.0.0.0:8000
    
    @stop *ARGS:
        docker compose down {{ ARGS }}
    
    @up *ARGS:
        docker compose up {{ ARGS }}
    

    If you work on multiple projects, I encourage you to find patterns you can scale across them. Using Just, Make, shell scripts or even Python lightens the cognitive load when switching between them.

    Sunday June 30, 2024
  • Docker

    ,

    Postgres

    🐘 Docker Postgres Autoupgrades

    Upgrading Postgres in Docker environments can be daunting, but keeping your database up-to-date is essential for performance, security, and access to new features. While there are numerous guides on manually upgrading Postgres, the process can often be complex and error-prone. Fortunately, the pgautoupgrade Docker image simplifies this process, automating the upgrade dance for us.

    The Challenge of Upgrading Postgres

    For many developers, upgrading Postgres involves several manual steps: backing up data, migrating schemas, ensuring compatibility, and testing thoroughly. Mistakes during these steps can lead to downtime or data loss, making the upgrade process a nerve-wracking experience.

    The pgautoupgrade Docker image is designed to handle the upgrade process seamlessly. Using it in place of the base Postgres image allows you to automate the upgrade steps, reducing the risk of errors and saving valuable time.

    How to Use pgautoupgrade

    While you can use the pgautoupgrade directly with Docker, I prefer it as my default development image.

    I set my compose.yml config with pgautoupgrade similar to this config:

    # compose.yml
    services:
      db:
        image: "pgautoupgrade/pgautoupgrade:latest"
        volumes:
          - postgres_data:/var/lib/postgresql/data/
    # ...
    

    Instead of using the latest version of Postgres, pgautoupgrade can be set to a specific version. This is nice if you want to match whichever version of Postgres you use in production or if you have extensions that might not be ready to move.

    # compose.yml
    services:
      db:
        image: "pgautoupgrade/pgautoupgrade:16-alpine"
        volumes:
          - postgres_data:/var/lib/postgresql/data/
    # ...
    

    Overall, I’m happy with pgautoupgrade. Please note that using pgautoupgrade does not mean you should not make data backups.

    See my last article, 🐘 A Just recipe to back and restore a Postgres database to learn some tips on how to automate using pg_dump and pg_restore.

    Saturday June 29, 2024
  • Justfiles

    ,

    Docker

    ,

    Postgres

    🐘 A Just recipe to backup and restore a Postgres database

    I have used this casey/just recipe to help backup and restore my Postgres databases from my Docker containers.

    I work with a few machines, and it’s an excellent way to create a database dump from one machine and then restore it from another machine. I sometimes use it to test data migrations because restoring a database dump takes a few seconds.

    I have been migrating from Docker to OrbStack, and the only real pain point is moving data from one volume to another. I sometimes need to switch between the two, so I have recipes set to back up and restore my database from one context to another.

    # justfile
    
    DATABASE_URL := env_var_or_default('DATABASE_URL', 'postgres://postgres@db/postgres')
    
    # dump database to file
    @pg_dump file='db.dump':
        docker compose run \
            --no-deps \
            --rm \
            db \
            pg_dump \
                --dbname "{{ DATABASE_URL }}" \
                --file /code/{{ file }} \
                --format=c \
                --verbose
    
    # restore database dump from file
    @pg_restore file='db.dump':
        docker compose run \
            --no-deps \
            --rm \
            db \
            pg_restore \
                --clean \
                --dbname "{{ DATABASE_URL }}" \
                --if-exists \
                --no-owner \
                --verbose \
                /code/{{ file }}
    

    Shoutout to Josh Thomas for help on this recipe since we both iterated on this for several projects.

    Friday June 28, 2024
  • Office Hours

    📅 Office Hours for June 28th

    It’s been a week, but I’m hosting Office Hours this Friday at 2:30 pm.

    I was on the fence because I was out Wednesday and Thursday for a funeral while juggling other family/life events. I was also looking forward to it, and some weekend work is unavoidable, no matter how productive my Friday is. So let’s do this!

    This will be our last Office Hours until July 12th

    Thursday June 27, 2024
  • Justfiles

    ,

    Docker

    🐳 Managing Docker Compose Profiles with Just: Switching Between Default and Celery Configurations

    For a recent client project, we wanted to toggle between various Docker Compose profiles to run the project with or without Celery.

    Using Compose’s profiles option, we can label services that we may not want to start by default a label. This might look something like this:

    services:
    
      beat:
        profiles:
          - celery
        ...
    
      celery:
        profiles:
          - celery
        ...
    
    
      web:
        ...
    

    We use a casey/just justfile for some of our common workflows, and I realized I could set a COMPOSE_PROFILES environment variable to switch between running a “default” profile and a “celery” profile.

    Using just’s env_var_or_default feature, we can set both an ENV variable and a default value to fall back on for our project.

    # justfie 
    
    export COMPOSE_PROFILES := env_var_or_default('COMPOSE_PROFILES', 'default')
    
    @up *ARGS:
        docker compose up {{ ARGS }}
    
    # ... the rest of your justfile...
    
    

    To start our service without Celery, I would run:

    $ just up
    

    ` To start our service with Celery, I would run:

    $ export COMPOSE_PROFILES=celery
    $ just up
    

    Our COMPOSE_PROFILES environment variable will get passed into our just up recipe, and if we don’t include one, it will have a default value of default, which will skip running the Celery service.

    Tuesday June 25, 2024
  • Python

    🚜 Mastodon Bookmark exporter to Markdown/Frontmatter

    I wrote a Mastodon Bookmark exporter tool over the weekend and decided to polish it up and release it tonight.

    I wrote the tool to help me sort out Mastodon posts that I might bookmark to follow up on or write about. I bookmark posts on the go or even from bed, and when I have time, I will pull them back up.

    The Mastodon Bookmark exporter tool reads your Mastodon bookmarks and exports the latest posts to a markdown/frontmatter file.

    I’m releasing the project as a gist under the PolyForm Noncommercial License for personal reasons. If you have licensing questions, contact me directly or through www.revsys.com for commercial inquiries, and we can work something out.

    Monday June 24, 2024
  • Weeknotes

    Weeknotes for Week 25: June 17 to 23

    Last week, my side of the family drove out to Colorado Springs, Colorado, and we rented a house for the week. The trip was great; seeing family was good, and watching the kids spend time with family they don’t get to see very often was the highlight for me. The mountains were great, but I don’t want to ride a train from 8k to 14k feet of altitude soon.

    Family

    The last of my biological aunts and uncles passed away two nights before we left Colorado. We had some other unexpected news, and I hope we have better news after the funeral this week.

    Work

    I took the whole week off, so the only work this week was community work.

    Community Work

    Djangonaut Space: Week 1 kicked off, and we had our first team meeting. The meeting went well, and I have a follow-up meeting on Monday with one Djangonaut who couldn’t make it.

    General Python: I had a ton of messages from Python friends this week asking for advice on upcoming bylaws changes. I wrote up a few drafts, and I might get around to publishing one or the other.

    Side projects

    Django News Newsletter: We shipped issue #238.

    Django Packages: More small updates and more on this sooner.

    I wrote a tool to export my Mastodon bookmarks. I tend to revisit these every day, and I wanted a way to create checklists for them and save them. I might find good content from the newsletter or posts I want to follow up on once I have more time.

    Writing

    I wrote every day but only published for three days, including today. I wrote several drafts, but I mostly spent time with my family.

    2024-06-19💜 Follow Black Python Devs on Juneteenth If you haven’t heard about Black Python Devs, Juneteenth is an excellent day to learn about …

    2024-06-17Djangonaut Space has begun This is my first time helping out with Djangonaut Space as a Navigator for the Django Packages…

    Entertainment

    📺 Leave the World Behind - I rewatched half of this movie with my mother and sister.

    📺 Hellboy - I didn’t realize I had missed this one. I liked it even if I don’t know much about the Hellboy story outside the other movies.

    Next week

    I am returning to work a day earlier than planned, but it will be a long, short week.

    Sunday June 23, 2024
  • 💜 Follow Black Python Devs on Juneteenth

    If you haven’t heard about Black Python Devs, Juneteenth is an excellent day to learn about this organization and how to support it.

    If you haven’t heard about Black Python Devs, here is a quick overview:

    Black Python Devs was created by its founder Jay Miller after seeing a trend of the same handful of Black developers speaking at major conferences, taking leadership positions, and dealing with the same challenges towards burnout.

    blackpythondevs.com/about/

    I also want to share the goals of Black Python Devs:

    Our goal is to become the largest community of Black Python Developers in the world and establish our community as a source for diverse leaders in the greater Python community.

    We aim to:

    • Establish guidance, mentorship, and career support for Black Pythonistas around the world.
    • Create opportunities for the Python community to invest in local communities of Black Python Devs members
    • Increase participation of Black Python Devs members in existing Python community programs, events, and initiatives.

    Follow them today

    Juneteenth is also a wonderful day to follow them on Mastodon (248 followers) or on Xwitter (606 followers).

    I would love to check these numbers tomorrow and see a non-zero increase in followers.

    You can also financially support Black Python Devs through the GNOME Foundation by scrolling down to the Support Black Python Devs section of the website.

    Disclosure

    I am a Black Python Devs Leadership Advisor who has watched and supported this organization grow even before I was asked to join. This team is near and dear to my heart, and I invite you to follow them and help spread the message.

    Wednesday June 19, 2024
  • Djangonaut Space

    Djangonaut Space has begun

    This is my first time helping out with Djangonaut Space as a Navigator for the Django Packages project.

    Last week was week zero, making this week one and the first week my team gets to meet as a group.

    Coordinating meeting times is always hard when everyone is from a different timezone, and this was no exception. Thankfully, we found a 30-minute block that works for everyone.

    Everyone on my team contributed something positive immediately after the meeting invite, including a few project contributions. All in week zero!

    Overall, I’m looking forward to it. I feel under and over-prepared, but I keep getting reassured to take it slow. So, I have some new issues to tag and fill in details before we meet on Wednesday, but we have started, and that’s exciting.

    Monday June 17, 2024
  • 🤖 AI companies are becoming bad neighbors

    This week, we learned that Perplexity AI Is Lying about Their User Agent. I have long suspected that many AI crawlers ignore Robots.txt, which has led me to write a block by User-Agent middleware. This has also led services like omg.lol to start Blocking Bad Bots by default.

    We can’t even trust that User Agents are respected, so we might need to double down on prompt injections as a possible workaround, since AI services are particularly vulnerable. Perplexity AI is susceptible to prompt injection

    Ethics be damned; this is another example of tech asking forgiveness, not permission.

    Until proven otherwise, AI companies are becoming the bad neighbors of the Internet. They block your driveway, let their dogs poop in our yard without picking it up, use your trashcans without asking, and ask you to get faster Internet after you discover they were still using your guest network after that one time they asked to use it because of an emergency.

    Sunday June 16, 2024