Debugging Setting up a Django Project
Normally when I start a new Django project I’ll use the PyCharm setup wizard, but recently I wanted to try out VS Code for a Django project and was super stumped when I would get a message like this:
ERROR:root:code for hash md5 was not found.
Traceback (most recent call last):
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 147, in <module>
globals()[__func_name] = __get_hash(__func_name)
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 97, in __get_builtin_constructor
raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type md5
ERROR:root:code for hash sha1 was not found.
Traceback (most recent call last):
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 147, in <module>
globals()[__func_name] = __get_hash(__func_name)
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 97, in __get_builtin_constructor
raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type sha1
ERROR:root:code for hash sha224 was not found.
Traceback (most recent call last):
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 147, in <module>
globals()[__func_name] = __get_hash(__func_name)
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 97, in __get_builtin_constructor
raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type sha224
ERROR:root:code for hash sha256 was not found.
Traceback (most recent call last):
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 147, in <module>
globals()[__func_name] = __get_hash(__func_name)
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 97, in __get_builtin_constructor
raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type sha256
ERROR:root:code for hash sha384 was not found.
Traceback (most recent call last):
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 147, in <module>
globals()[__func_name] = __get_hash(__func_name)
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 97, in __get_builtin_constructor
raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type sha384
ERROR:root:code for hash sha512 was not found.
Traceback (most recent call last):
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 147, in <module>
globals()[__func_name] = __get_hash(__func_name)
File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hashlib.py", line 97, in __get_builtin_constructor
raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type sha512
Here are the steps I was using to get started
From a directory I wanted to create the project I would set up my virtual environment
python3 -m venv venv
And then activate it
source venv/bin/activate
Next, I would install Django
pip install django
Next, using the startproject command per the docs I would
django-admin startproject my_great_project .
And get the error message above 🤦🏻♂️
The strangest part about the error message is that it references Python2.7 everywhere … which is odd because I’m in a Python3 virtual environment.
I did a pip list and got:
Package Version
---------- -------
asgiref 3.3.4
Django 3.2.4
pip 21.1.2
pytz 2021.1
setuptools 49.2.1
sqlparse 0.4.1
OK … so everything is in my virtual environment. Let’s drop into the REPL and see what’s going on

Well, that looks to be OK.
Next, I checked the contents of my directory using tree -L 2
├── manage.py
├── my_great_project
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── venv
├── bin
├── include
├── lib
└── pyvenv.cfg
Yep … that looks good too.
OK, let’s go look at the installed packages for Python 2.7 then. On macOS they’re installed at
/usr/local/lib/python2.7/site-packages
Looking in there and I see that Django is installed.
OK, let’s use pip to uninstall Django from Python2.7, except that pip gives essentially the same result as running the django-admin command.
OK, let’s just remove it manually. After a bit of googling I found this Stackoverflow answer on how to remove the offending package (which is what I assumed would be the answer, but better to check, right?)
After removing the Django install from Python 2.7 and running django-admin --version I get

So I googled that error message and found another answers on Stackoverflow which lead me to look at the manage.py file. When I cat the file I get:
# manage.py
#!/usr/bin/env python
import os
import sys
...
That first line SHOULD be finding the Python executable in my virtual environment, but it’s not.
Next I googled the error message django-admin code for hash sha384 was not found
Which lead to this Stackoverflow answer. I checked to see if Python2 was installed with brew using
brew leaves | grep python
which returned python@2
Based on the answer above, the solution was to uninstall the Python2 that was installed by brew. Now, although Python2 has retired, I was leery of uninstalling it on my system without first verifying that I could remove the brew version without impacting the system version which is needed by macOS.
Using brew info python@2 I determined where brew installed Python2 and compared it to where Python2 is installed by macOS and they are indeed different
Output of brew info python@2
...
/usr/local/Cellar/python@2/2.7.15_1 (7,515 files, 122.4MB) *
Built from source on 2018-08-05 at 15:18:23
...
Output of which python
/usr/bin/python
OK, now we can remove the version of Python2 installed by brew
brew uninstall python@2
Now with all of that cleaned up, lets try again. From a clean project directory:
python3 -m venv venv
source venv/bin/activate
pip install django
django-admin --version
The last command returned
zsh: /usr/local/bin/django-admin: bad interpreter: /usr/local/opt/python@2/bin/python2.7: no such file or directory
3.2.4
OK, I can get the version number and it mostly works, but can I create a new project?
django-admin startproject my_great_project .
Which returns
zsh: /usr/local/bin/django-admin: bad interpreter: /usr/local/opt/python@2/bin/python2.7: no such file or directory
BUT, the project was installed
├── db.sqlite3
├── manage.py
├── my_great_project
│ ├── __init__.py
│ ├── __pycache__
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── venv
├── bin
├── include
├── lib
└── pyvenv.cfg
And I was able to run it
python manage.py runserver

Success! I’ve still got that last bug to deal with, but that’s a story for a different day!
Short Note
My initial fix, and my initial draft for this article, was to use the old adage, turn it off and turn it back on. In this case, the implementation would be the deactivate and then re activate the virtual environment and that’s what I’d been doing.
As I was writing up this article I was hugely influenced by the work of Julie Evans and kept asking, “but why?”. She’s been writing a lot of awesome, amazing things, and has several zines for purchase that I would highly recommend.
She’s also generated a few debugging ‘games’ that are a lot of fun.
Anyway, thanks Julie for pushing me to figure out the why for this issue.
Post Script
I figured out the error message above and figured, well, I might as well update the post! I thought it had to do with zsh, but no, it was just more of the same.
The issue was that Django had been installed in the base Python2 (which I knew). All I had to do was to uninstall it with pip.
pip uninstall django
The trick was that pip wasn't working out for me ... it was generating errors. So I had to run the command
python -m pip uninstall django
I had to run this AFTER I put the Django folder back into /usr/local/lib/python2.7/site-packages (if you'll recall from above, I removed it from the folder)
After that clean up was done, everything worked out as expected! I just had to keep digging!
My First Python Package
A few months ago I was inspired by Simon Willison and his project Datasette and it’s related ecosystem to write a Python Package for it.
I use toggl to track my time at work and I thought this would be a great opportunity use that data with Datasette and see if I couldn’t answer some interesting questions, or at the very least, do some neat data discovery.
The purpose of this package is to:
Create a SQLite database containing data from your toggl account
I followed the tutorial for committing a package to PyPi and did the first few pushes manually. Then, using a GitHub action from one of Simon’s Datasette projects, I was able to automate it when I make a release on GitHub!
Since the initial commit on March 7 (my birthday BTW) I’ve had 10 releases, with the most recent one coming yesterday which removed an issue with one of the tables reporting back an API key which, if published on the internet could be a bad thing ... so hooray for security enhancements!
Anyway, it was a fun project, and got me more interested in authoring Python packages. I’m hoping to do a few more related to Datasette (although I’m not sure what to write honestly!).
Be sure to check out the package on PyPi.org and the source code on GitHub.
Writing a Raffle Script
Due to the COVID Pandemic, many things are ... different. One thing that needed to be different this year was the way that students at my daughters middle school got to spend their ‘Hero Points’.
Hero Points are points earned for good behavior. In a typical year the students would get to spend them at the student store, but with all of the closures, this wasn’t possible. For the students in my daughter’s 8th grade this was a big deal as they’re going on to High School next year, so we can just roll them over to next year!
Instead of having the kids ‘spend’ their Hero Points the PTO offered up the solution of a raffle based on the number of Hero Points they had. But they weren’t sure how to do it.
I jumped at the chance to write something like this up (especially after all of my works on the PyBites CodeChalleng.es platform) and so my wife volunteered me 😁
In order to really get my head wrapped around the problem, I wanted to treat my solution like a real world analog. For example, in a real work raffle, when you get your tickets, there are two tickets with the same number. One that you get to hold onto, and one that goes into a bowl (or other vessel) that is randomly drawn from.
How many tickets?
Each student had some number of Hero Points. The PTO decided that 10 Hero Points would equal 1 Raffle ticket. Further, it was decided that we would ALWAYS round up. This means that 1 Hero Point would equal 1 Raffle Ticket, but that 9 Hero Points would also equal 1 Raffle Ticket.
Create tickets
I decided to use a namedtuple to store the Raffle Tickets. Specifically, I store the student name, ticket numbers they drew, and the number of tickets they have
Raffle_Tickets = namedtuple('Raffle_Tickets', ['name', 'ticket_numbers', 'tickets'])
The list of student names and total Hero Points was stored in an Excel File (.xlsx) so I decided to use the Pandas Package to import it and manipulate it into a dataframe. The structure of the excel file is: Student Name, Grade, Available Points.
df = pd.read_excel (r'/Users/ryan/Documents/python-files/8th Hero Points.xlsx')
After a bit of review it turned out that there were a couple of students with NEGATIVE Hero Points. I’m not really sure how that happened, but I was not properly accounting for that originally, so I had to update my dataframe.
The code below filters the dataframe to only return students with positive ‘Available Points’ and then reindex. Finally, it calculates the number of Raffle tickets by dividing by 10 and rounding up using Python’s ceil function. It puts all of this into a list called tickets. We append our tickets list to the original dataframe.
df = df[df['Available Points'] >0]
df.reset_index(inplace=True, drop=True)
tickets = []
for i in df['Available Points'] / 10:
tickets.append(ceil(i))
df['Tickets'] = tickets
Our dataframe now looks like this: Student Name, Grade, Available Points, Tickets.
Next, we need to figure out the Raffle ticket numbers. To do that I count the total number of Tickets available. I’m also using some extra features of the range function which allows me to set the start number of the Raffle.1
total_number_of_tickets = sum(df['Tickets'])
ticket_number_start = 1000000
ticket_number_list = []
for i in range(ticket_number_start, ticket_number_start+total_number_of_tickets):
ticket_number_list.append(i)
Once we have the list of ticket numbers I want to make a copy of it … remember there are two tickets, one that goes in the bowl and one that the student ‘gets’. Extending the metaphor of having two different, but related, tickets, I decided to use the deepcopy function on the ticket_number_list to create a list called assigned_ticket_number_list.
For more on deepcopy versus (shallow) copy see the documentation
assigned_ticket_number_list = deepcopy(ticket_number_list)
Finally, I reindex the dataframe just to add a bit more randomness to the list
df = df.reindex(np.random.permutation(df.index))
Assign Tickets
Next we’ll assign the tickets randomly to the students.
raffle_list = []
for student in range(df.shape[0]):
student_ticket_list = []
for i in range(df.loc[student].Tickets):
assigned_ticket_number = randint(0, len(assigned_ticket_number_list)-1)
student_ticket_list.append(assigned_ticket_number_list[assigned_ticket_number])
assigned_ticket_number_list.pop(assigned_ticket_number)
raffle_list.append(Raffle_Tickets(df.loc[student].Name, student_ticket_list, len(student_ticket_list)))
OK … the code above looks pretty dense, but basically all we’re doing is looping through the students to determine the number of tickets they each have. Once we have that we loop through the available ticket numbers and randomly assign it to the student. At the end we add a namedtuple object called Raffle_Tickets that we defined above to the raffle_list to store the student’s name, their ticket numbers, and the number of tickets that they received.
Draw Tickets
Now we want to ‘draw’ the tickets from the ‘bowl’. We want to select 25 winners, but we also don’t want to have any student win more than once. Honestly, the ’25 winning tickets with 25 distinct winners’ was the hardest part to get through.
selected_tickets = []
for i in range(25):
selected_ticket_number_index = randint(0, len(ticket_number_list) - 1)
selected_ticket_number = ticket_number_list[selected_ticket_number_index]
for r in raffle_list:
if selected_ticket_number in r.ticket_numbers:
ticket_number_list = [x for x in ticket_number_list if x not in r.ticket_numbers]
selected_tickets.append(selected_ticket_number)
We see above that we’ll select 25 items from the ‘bowl’ of tickets. We select the tickets one at a time. For each ticket we determine what set of tickets that selected ticket is in. Once we know that, we then remove all tickets associated with that winning ticket so that we can guarantee 25 unique winners.
Find the Winners
We now have 25 tickets with 25 winners. Now we just need to get their names!
winners_list=[]
for r in raffle_list:
for t in r.ticket_numbers:
student_winning_list = []
if t in selected_tickets:
student_winning_list.append(t)
winners_list.append((Raffle_Tickets(r.name, student_winning_list, len(student_winning_list))))
Again, we construct a list of namedtuple Raffle\_Tickets only this time it’s just the winners.
Output winners
Whew! Now that we have the results we want to write them to a file.
with open('/Users/ryan/PyBites/Raffle/winners_new.txt', 'w+') as f:
for winner in winners_list:
tickets = ticket_count(winner.name)
percent_chance_of_winning = tickets / total_number_of_tickets * 100
percent_chance_of_winning_string = "{:.2f}".format(percent_chance_of_winning)
f.write(f'{winner.name} with winning ticket {winner.ticket_numbers[0]}. They had {tickets} tickets and a {percent_chance_of_winning_string}% chance of winning.\n')
One of the reasons that I stored the number of tickets above was so that we could see what the chance was of a student winning given the number of tickets they started with.
For each student we output to a line to a file with the student’s name, the winning tickets number, the number of tickets they started with and their chance of winning (the ratio of tickets the student had to the total number of starting tickets)
Conclusion
This was a fun project for me because it was needed for a real world application, allowed me to use MANY of the concepts I learned at PyBites CodeChalleng.es AND helped my daughter’s school.
- Why am I doing this, versus just stating a
0? Mostly because I wanted the Raffle Ticket numbers to look like real Raffle Ticket Numbers. How many times have you seen a raffle ticket with number 0 on it? ↩︎
Issues with psycopg2 … again
In a previous post I had written about an issue I’d had with upgrading, installing, or just generally maintaining the python package psycopg2 (link).
I ran into that issue again today, and thought to myself, “Hey, I’ve had this problem before AND wrote something up about it. Let me go see what I did last time.”
I searched my site for psycopg2 and tried the solution, but I got the same forking error.
OK … let’s turn to the experts on the internet.
After a while I came across this article on StackOverflow but this specific answer helped get me up and running.
A side effect of all of this is that I upgraded from Python 3.7.5 to Python 3.8.1. I also updated all of my brew packages, and basically did a lot of cleaning up that I had neglected.
Not how I expected to spend my morning, but productive nonetheless.
My First Django Project
I've been writing code for about 15 years (on and off) and Python for about 4 or 5 years. With Python it's mostly small scripts and such. I’ve never considered myself a ‘real programmer’ (Python or otherwise).
About a year ago, I decided to change that (for Python at the very least) when I set out to do 100 Days Of Web in Python from Talk Python To Me. Part of that course were two sections taught by Bob regarding Django. I had tried learn Flask before and found it ... overwhelming to say the least.
Sure, you could get a ‘hello world’ app in 5 lines of code, but then what? If you wanted to do just about anything it required ‘something’ else.
I had tried Django before, but wasn't able to get over the 'hump' of deploying. Watching the Django section in the course made it just click for me. Finally, a tool to help me make AND deploy something! But what?
The Django App I wanted to create
A small project I had done previously was to write a short script for my Raspberry Pi to tell me when LA Dodger (Baseball) games were on (it also has beloved Dodger Announcer Vin Scully say his catch phrase, “It’s time for Dodger baseball!!!”).
I love the Dodgers. But I also love baseball. I love baseball so much I have on my bucket list a trip to visit all 30 MLB stadia. Given my love of baseball, and my new found fondness of Django, I thought I could write something to keep track of visited stadia. I mean, how hard could it really be?
What does it do?
My Django Site uses the MLB API to search for games and allows a user to indicate a game seen in person. This allows them to track which stadia you've been to. My site is composed of 4 apps:
- Users
- Content
- API
- Stadium Tracker
The API is written using Django Rest Framework (DRF) and is super simple to implement. It’s also really easy to changes to your models if you need to.
The Users app was inspired by Will S Vincent ( a member of the Django Software Foundation, author, and podcaster). He (and others) recommend creating a custom user model to more easily extend the User model later on. Almost all of what’s in my Users App is directly taken from his recommendations.
The Content App was created to allow me to update the home page, and about page (and any other content based page) using the database instead of updating html in a template.
The last App, and the reason for the site itself, is the Stadium Tracker! I created a search tool that allows a user to find a game on a specific day between two teams. Once found, the user can add that game to ‘Games Seen’. This will then update the list of games seen for that user AND mark the location of the game as a stadium visited. The best part is that because the game is from the MLB API I can do some interesting things:
- I can get the actual stadium from visited which allows the user to indicate historic (i.e. retired) stadia
- I can get details of the game (final score, hits, runs, errors, stories from MLB, etc) and display them on a details page.
That's great and all, but what does it look like?
The Search Tool

Stadia Listing
National League West

American League West

What’s next?
I had created a roadmap at one point and was able to get through some (but not all) of those items. Items left to do:
- Get Test coverage to at least 80% across the app (currently sits at 70%)
- Allow users to be based on social networks (right now I’m looking at Twitter, and Instagram) probably with the Django Allauth Package
- Add ability to for minor league team search and stadium tracking (this is already part of the MLB API, I just never implemented it)
- Allow user to search for range of dates for teams
- Update the theme ... it’s the default MUI CSS which is nice, but I’d rather it was something a little bit different
- Convert Swagger implementation from
django-rest-swaggertodrf-yasg
Final Thoughts
Writing this app did several things for me.
First, it removed some of the tutorial paralysis that I felt. Until I wrote this I didn’t think I was a web programmer (and I still don’t really), and therefore had no business writing a web app.
Second, it taught me how to use git more effectively. This directly lead to me contributing to Django itself (in a very small way via updates to documentation). It also allowed me to feel comfortable enough to write my first post on this very blog.
Finally, it introduced me to the wonderful ecosystem around Django. There is so much to learn, but the great thing is that EVERYONE is learning something. There isn’t anyone that knows it all which makes it easier to ask questions! And helps me in feeling more confident to answer questions when asked.
The site is deployed on Heroku and can be seen here. The code for the site can be seen here.
This article was also posted on the PyBit.es Blog
Using Python to Check for File Changes in Excel
The Problem
Data exchange in healthcare is ... harder than it needs to be. Not all partners in the healthcare arena understand and use technology to its fullest benefit.
Take for example several health plans which want data reported to them for CMS (Centers for Medicare and Medicaid Services) regulations. They will ask their 'delegated' groups to fill out an excel file. As in, they expect you will actually fill out an excel file, either by manually entering the data OR by potentially copying and pasting your data into their excel file.
They will also, quite frequently, change their mind on what they want AND the order in which they want the data to appear in their excel file. But there's no change log to tell you what (if anything has changed). All that you will get is an email which states, "Here's the new template to be used for report XYZ" ... even if this 'new' report is the same as the last one that was sent.
Some solutions might be to use versioning software (like Git) but all they will do is tell you that there is a difference, not what the difference is. For example, when looking at a simple excel file added to git and using git diff you see:
diff --git a/Book3.xlsx b/Book3.xlsx
index 05a8b41..e96cdb5 100644
Binary files a/Book3.xlsx and b/Book3.xlsx differ
This has been a giant pain in the butt for a while, but with the recent shelter-in-place directives, I have a bit more time on the weekends to solve these kinds of problems.
The Solution
Why Python of Course!
Only two libraries are needed to make the comparison: (1) os, (2) pandas
The basic idea is to:
- Load the files
- use pandas to compare the files
- write out the differences, if they exist
Load the Files
The code below loads the necessary libraries, and then loads the excel files into 2 pandas dataframes. One thing that my team has to watch out for are tab names that have leading spaces that aren't easy to see inside of excel. This can cause all sorts of nightmares from a troubleshooting perspective.
import os
import pandas as pd
file_original = os.path.join(\\path\\to\\original\\file, original_file.xlsx)
file_new = os.path.join(\\path\\to\\new\\file, new_file.xlsx)
sheet_name_original = name_of_sheet_in_original_file
sheet_name_new = name_of_sheet_in_new_file
df1 = pd.read_excel(file_original, sheet_name_original)
df2 = pd.read_excel(file_new, sheet_name_new)
Use Pandas to compare
This is just a one liner, but is super powerful. Pandas DataFrames have a method to see if two frames are the same. So easy!
data_frame_same = df1.equals(df2)
Write out the differences if they exist:
First we specify where we're going to write out the differences to. We use w+ because we'll be writing out to a file AND potentially appending, depending on differences that are found. The f.truncate(0) will clear out the file so that we get just the differences on this run. If we don't do this then we'll just append to the file over and over again ... and that can get confusing.
f.open(\\path\\to\\file\\to\\write\\differences.txt, 'w+')
f.truncate(0)
Next, we check to see if there are any differences and if they are, we write a simple message to our text file from above:
if data_frame_same:
f.write('No differences detected')
If differences are found, then we loop through the lines of the file, finding the differences and and writing them to our file:
else:
f.write('*** WARNING *** Differences Found\n\n')
for c in range(max(len(df1.columns), len(df2.columns))):
try:
header1 = df1.columns[c].strip().lower().replace('\n', '')
header2 = df2.columns[c].strip().lower().replace('\n', '')
if header1 == header2:
f.write(f'Headers are the same: {header1}\n')
else:
f.write(f'Difference Found: {header1} -> {header2}\n')
except:
pass
f.close()
The code above finds the largest column header list (the file may have had a new column added) and uses a try/except to let us get the max of that to loop over.
Next, we check for differences between header1 and header2. If they are the same, we just write that out, if they aren't, we indicate that header1 was transformed to header2
A sample of the output when the column headers have changed is below:
*** WARNING *** Differences Found
Headers are the same: beneficiary first name
...
Difference Found: person who made the request -> who made the request?
...
Future Enhancements
In just using it a couple of times I've already spotted a couple of spots for enhancements:
- Use
inputto allow the user to enter the names/locations of the files - Read the tab names and allow user to select from command line
Conclusion
I'm looking forward to implementing the enhancements mentioned above to make this even more user friendly. In the mean time, it'll get the job done and allow someone on my team to work on something more interesting then comparing excel files to try (and hopefully find) differences.
Mischief Managed
A few weeks back I decided to try and update my Python version with Homebrew. I had already been through an issue where the an update like this was going to cause an issue, but I also knew what the fix was.
With this knowledge in hand I happily performed the update. To my surprise, 2 things happened:
- The update seemed to have me go from Python 3.7.6 to 3.7.3
- When trying to reestablish my
Virtual Environmenttwo packages wouldn’t installed:psycopg2anddjango-heroku
Now, the update/backdate isn’t the end of the world. Quite honestly, next weekend I’m going to just ditch homebrew and go with the standard download from Python.org because I’m hoping that this non-sense won’t be an issue anymore
The second issue was a bit more irritating though. I spent several hours trying to figure out what the problem was, only to find out, there wasn’t one really.
The ‘fix’ to the issue was to
- Open PyCharm
- Go to Setting
- Go to ‘Project Interpreter’
- Click the ‘+’ to add a package
- Look for the package that wouldn’t install
- Click ‘Install Package’
- Viola ... mischief managed
The next time this happens I’m just buying a new computer
Fixing a PyCharm issue when updating Python made via HomeBrew
I’ve written before about how easy it is to update your version of Python using homebrew. And it totally is easy.
The thing that isn’t super clear is that when you do update Python via Homebrew, it seems to break your virtual environments in PyCharm. 🤦♂️
I did a bit of searching to find this nice post on the JetBrains forum which indicated
unfortunately it's a known issue: https://youtrack.jetbrains.com/issue/PY-27251 . Please close Pycharm and remove jdk.table.xml file from \~/Library/Preferences/.PyCharm2018.1/options directory, then start Pycharm again.
OK. I removed the file, but then you have to rebuild the virtual environments because that file is what stores PyCharms knowledge of those virtual environments.
In order to get you back to where you need to be, do the following (after removing the jdk.table.xml file:
- pip-freeze > requirements.txt
- Remove old virtual environment
rm -r venv - Create a new Virtual Environemtn with PyCharm
- Go to Preferences
- Project > Project Interpreter
- Show All
- Click ‘+’ button
pip install -r requirements.txt- Restart PyCharm
- You're back
This is a giant PITA but thankfully it didn’t take too much to find the issue, nor to fix it. With that being said, I totally shouldn’t have to do this. But I’m writing it down so that once Python 3.8 is available I’ll be able to remember what I did to fix going from Python 3.7.1 to 3.7.5.
Updating the models for my Django Rest Framework API
I’ve been working on a Django project which would allow users to track games that they’ve seen and, therefore, see what stadia they have visited.
This is all being done at a site i set up called StadiaTracker.com. Initially when constructing my model I kept it relatively simple. I had one model that had two fields. The two fields tied the User from my CustomUser Model to a Game ID that I retrieve from an API that MLB provides.
I thought this simple approach would be the best approach. In addition to having a Django App I set up a Django Rest Framework (DRF) API. My initial plan was to have a DRF backend with a Vue (or React) front end. (I still want to do that, but I really wanted to try and finish a project before proceeding down that path).
After some development and testing I quickly realized that the page loads for the app were suffering because of the number of API calls to MLB that were being made.
I created a new model to tie the user id (still from the CustomUser model I’d created) to the game id, but in addition I’d get and store the following information:
- Home Team Name
- Home Team Score
- Home Team Hits
- Home Team Errors
- Away Team Name
- Away Team Score
- Away Team Hits
- Away Team Errors
- Game Recap Headline
- Game Recap Summary
- Game Date / Time
By storing all of this my views could render more quickly because they didn’t have to go to the MLB API to get the information.
Of course, once I did this I realized that the work I had done on the DRF API would also need to be updated.
Initially I kept putting off the refactoring that was going to have to be done. Finally, I just sat down and did it. And you know what, within 10 minutes I was done.
I only had to change 3 files:
- serializers.py
- urls.py
- views.py
For the searializers.py and views.py all I had to do was add the new model and then copy and paste what I had done for the previous model.
For the urls.py it was just a simple matter of updating the the DRF path and detail path to use the new views I had just created.
It was so amazingly simple I could barely believe it. This thing I had put off for a couple of weeks because I was afraid it was going to be really hard, just wasn't.
My Experience with the 100 Days of Web in Python
As soon as I discovered the Talk Python to me Podcast, I discovered the Talk Python to me courses. Through my job I have a basically free subscription to PluralSight so I wasn’t sure that I needed to pay for the courses when I was effectively getting courses in Python for free.
After taking a couple ( well, truth be told, all ) of the Python courses at PluralSight, I decided, what the heck, the courses at Talk Python looked interesting, Michael Kennedy has a good instructor’s voice and is genuinely excited about Python, and if it didn’t work out, it didn’t work out.
I’m so glad I did, and I’m so glad I went through the 100 Days of Web in Python course.
On May 2, 2019 I saw that the course had been released and I tweeted
This x 1000000! Thank you so much \@TalkPython. I can’t wait to get started!
I started on the course on May 4, 2019 and completed it August 11, 2019. Full details on the course are here.
Of the 28 concepts that were reviewed over the course, my favorites things were learning Django and Django Rest Framework and Pelican. Holy crap, those parts were just so much fun for me. Part of my interest in Django and DRF comes from William S Vincent’s books and Podcast Django Chat, but having actual videos to watch to get me through some of the things that have been conceptually tougher for me was a godsend.
The other part that I really liked was actual deployment to a server. I had tried (about 16 months ago) to deploy a Django app to Digital Ocean and it was an unmitigated disaster. No static files no matter what I did. I eventually gave up.
In this course I really learned how to deploy to both Heroku and a Linux box on Digital Ocean, and so now I feel much more confident that the app I’m working on (more on that below) will actually see the light of day on something other than a dev machine!
The one thing that I started to build (and am continuing to work on) is an app with a DRF backend and a Vue.js front end that allows a user to track which Baseball stadia they’ve been to. So far I have an API set up via DRF (hosted at Heroku) and sketches of what to do in Vue.js. There's also a Django front end (but it’s not the solution I really want to use).
Writing code for 100 days is hard. Like really hard. For nearly 20 of those days I was on a family vacation in the Mid Western part of the US, but I made time for both the coding, and my family. My family was super supportive of my goal which was helpful, but the content in the course was really interesting and challenging and made me want to do it every day, which was also super helpful.
On day 85 I got a video from Bob that helped get me through the last 2 weeks. It was encouraging, and helpful which is just what I needed. So thank you Bob.
At the end I also got a nice congratulatory video from Julian, which was surprising to say the least, especially because he called out some of the things that I tweeted that I enjoyed about the class, addressed me by name, and just genuinely made me feel good about my accomplishment!
OK. I just wrapped up the 100 Days of Code with Python and the web. Now what?
I took a week off to recuperate and am now ready to ‘get back to it’.
After all, I’ve got baseball stadia to track in my app!
Talk Python to me Podcast
Why I like the Talk Python Podcast
When I started listening to it
Listening to the back catalog (nearly all of it)
Page 2 / 6