Saturday, July 27, 2013
I updated the script with feedback I got from the blog and reddit and fixed tab completion to work correctly on a mac by default.
Friday, July 26, 2013
Tuesday, July 23, 2013
Its a little rough I admit, and I welcome any feedback for improvements. As a result, I'm now able to run commands like the following anywhere once I have my virtual environment loaded.
(spock)jbisbee@tacquito:~/src/spock$ manage dbshell Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 95 Server version: 5.5.31-0ubuntu0.12.04.2 (Ubuntu) Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
Edit: I've gotten some feedback and I realize I didn't sell the real reason behind dynamically setting the DJANGO_SETTINGS_MODULE variable. I use Django at work and we have moved from the generic one file settings.py to a settings directory which looks something like this
settings/ base.py dev.py # imports from base.py test.py # imports from base.py production.py # imports from base.py jbisbee.py # imports from dev.py
This way you can have cascading Django settings with overrides at multiple levels. This bash function I wrote finds the settings directory and will set DJANGO_SETTINGS_MODULE to the user's specific dev settings (or dev if the user can't be found)
Disclaimer: If you manage your Django project's settings differently let me know. I'd love to make the determine_django_module_settings more flexible and patches are more than welcome!
Saturday, July 13, 2013
created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True)
The problem I ran into was that I wanted to keep the legacy timestamp from the old database when I loaded the record for the first time then have the auto_now kick in. The problem is that auto_now is very stupid (as it should be) and doesn't understand the concept of insert or update and whether your new record is coming in with pre-populated DateTimeField attribute. It gladly throws away any value away and always replaces the value with the current time. I didn't notice it on first import but soon realized auto_now wouldn't meet my needs.
After a quick search, I found this Stack Overflow question that had the perfect fix for my problem. It suggested implementing my own save that would allow me to pass in values for created or modified but would fall back to the current time. I changed the code a bit because I didn't need a created timestamp for my model, but this should give you an idea.
Note: you have to remove any additional values from kwargs before passing to the parent class or super.save will complain that created and modified aren't valid arguments.
import datetime class User(models.Model): created = models.DateTimeField(editable=False) modified = models.DateTimeField() def save(self, *args, **kwargs): # original Code: called datetime.datetime.today() # multiple places. Modified kwargs # # created = kwargs.pop('created', None) # if created: # self.created = created # elif not self.id: # self.created = datetime.datetime.today() # # modified = kwargs.pop('modified', None) # if modified: # self.modified = modified # else: # self.modified = datetime.datetime.today() # Edit #1: Changed example to more efficient # version from blog comments. # single today() # # today = datetime.datetime.today() # # if not self.id # self.created = kwargs.pop('created', today) # elif kwargs.get('created', None) # self.created = kwargs.pop('created') # # self.modified = kwargs.pop('modified', today) # Edit #2: no longer pass arguments via save # was orignially how I wanted to solve # the problem and how I felt auto_now # should have worked. Thanks to # indosauros from reddit. :) # # On inital creation of the object # only set today if values are not # already populated. auto_now* # wipes them out regardless today = datetime.datetime.today() if not self.id: if not self.created: self.created = today if not self.modified: self.modified = today else: self.modified = today super(User, self).save(*args, **kwargs)
If you see any glaring python or style related issues, please let me know. I'm still finding my way pythonwise and would love any best practices feedback.
Monday, July 8, 2013
Edit: Turns out utf8 and utf8_general_ci is not the full utf8 implmentation in mysql. See this blog post for an in-depth explaination on how they're different (has to do with 4 byte utf8 characters being thrown out by mysql)
Edit #2: From reddit, credomane stated that character-set-handshake caused him troubles. With existing applications. I'm going to do a bit more research, but here is his response to sharing this blog entry on r/mysql
You might want to consider removing character-set-client-handshake or at least mention it could cause troubles with some programs that use mysql. Changing it to false or skipping the handshake makes MySQL behave like MySQL 4.0 according to the mysql docs. When I was looking over your blog post yesterday and checking the mysql docs that seemed like a bad idea to deny the client the ability to change to a character set it prefers/designed for.
I went through the whole process of taking mysql offline, backing up my databases, altering/converting the tables, updating the mysql config and bringing mysql back online. At first everything seemed fine then I started to notice a lot of 500 errors appearing in my apache2 access logs and some things not working. Mainly applications sitting behind apache2's mod_wsgi. After spending several hours restoring databases and redoing everything database by database I eventually found I could convert all my databases just fine. Know I know the problem isn't in the database conversions but with my config changes.
character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ciCaused no problems what so ever but as soon as I addedcharacter-set-client-handshake = FALSEI started having problems again. Investigating the problem applications show that they desire utf8_unicode_ci but since the mysql server says utf8mb4_unicode_ci only, they abort the mysql connection when they can't get the charset they wanted to prevent any possible corruption.
collation-server = utf8_general_ci init-connect='SET NAMES utf8' character-set-server = utf8character-set-client-handshake = FALSE character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
Mysql reference: character_set_server, character-set-client-handshake, collation-server,
Special thanks to johns-appendix from my reddit post to r/programming for pointing out that I had the wrong encoding. I welcome the down votes as I learned something. :)
Thursday, July 4, 2013
About 8 months ago I went to Amazon.com to rent a streaming movie and saw an ad for the The Nest Learning Thermostat, saying it was one of the hottest selling items on Amazon. I was a bit skeptical because I figured a thermostat is a thermostat right, and asked myself, "why is this thing so popular?"
Well it turns out that the magic is in the merging of technologies. The Nest combines
- A Thermostat
- A motion sensor
- Data from the internet
- Great interface (like the interface on an iPod)
The real magic is in the motion sensor. The biggest problem with optimizing a thermostat is you have to sit down and program the schedule you want it to follow. The Nest takes care of that for you. About a week after I installed it, I was walking down my hallway and the Nest lit up and stated it had, "learned my schedule" and would optimize my cooling. I was a bit taken aback but it makes perfect sense. The best part is that the default behavior is after it goes into "away" mode it doesn't turn back on until it senses motion again.
The Nest also does something else very subtly, it motivates you slowly turn up your target temperature to earn a "green leaf". I live in Florida and used to run my thermostat at a steady 77 degrees. Now with the Nest, I've bumped that up to 80 and supplemented with fans and surprisingly haven't noticed much of a difference in temperature. What I have noticed is a drastic change in my power bill.
Disclaimer: I work during the day and have no one at home that would set off the motion sensor to turn the air back on. If you do have someone at home all day or you're one of the awesome people who actually program their thermostat, then most likely you won't see savings as large as mine. Also I live in south Florida were air conditioning is king and we only run the heat one or two times a year :)
Wednesday, July 3, 2013
I then briefly considered creating a bash function that would determine manage.py's location on every invocation but figured that was silly and decided I might as leverage virtualenv's virtual environment and as Ron Popiel says, "You set it and forget it!"
It only took a minute of poking to find the postactivate hook file within my ~/.virtualenvs directory. Below is the fruit of my labor.
#!/bin/bash # ~/.virtualenvs/postactive # This hook is run after every virtualenv is activated. VIRTUAL_ENV_NAME=$(basename $VIRTUAL_ENV) SRC_DIR="$HOME/src" if [ -d "$SRC_DIR/$VIRTUAL_ENV_NAME" ] then MANAGE_PY=$(find "$SRC_DIR/$VIRTUAL_ENV_NAME" -name "manage.py" -type f) if [ -e "$MANAGE_PY" ] then alias django="python $MANAGE_PY" else unalias django fi else unalias django fi
The end result is that I have a new django alias that will work anywhere and act as though I typed python manage.py
jbisbee@beni:~$ workon django-tutorial (django-tutorial)jbisbee@beni:~$ alias | grep django alias django='python /Users/jbisbee/src/django-tutorial/mysite/manage.py' (django-tutorial)jbisbee@beni:~$
Disclaimer: I'm making a big assumption here that the virtualenv name you're using is identical to the name of the project you're working on. It's a pretty big assumption so I apologize if it does't work right out of the box for you.