Django For Simplest Thing

Time to do some Simplest Thing development.

Technology architecture I'm aiming for:

Mar09'2012now

Need to upgrade my Python to 2.7.2 (because Heroku document says I need 2.7x). (Python On Mac)

Ugh, now my PikiPiki won't run - urgh I know I've run into this in the past...

  • root page is fine (that's not running Piki at all, but just the static stub server delivering index.html), but hitting actual PikiPiki script gives me a SaveAs dialog. Use C Url, find that it's trying to pass me the content of the piki script {{{
  • Connected to localhost (127.0.0.1) port 8000 (#0)

GET /piki?BillSeitz HTTP/1.1 User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 Open S S L/0.9.8l zlib/1.2.3 Host: localhost:8000 Accept: /

  • HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: SimpleHTTP/0.6 Python/2.7.2 < Date: Fri, 09 Mar 2012 16:39:57 GMT < Content-type: application/octet-stream < Content-Length: 17641 < Last-Modified: Fri, 15 Apr 2011 20:38:51 GMT < #!/usr/bin/python

"""Quick-quick implementation of Wiki Wiki Web in Python """ (rest of piki file) }}}

  • after some goofing around, suspect the issue is that I'm just using piki in the URL instead of piki.py or that the script file itself is named piki instead of piki.py

    • nope, now it just delivers the script content without the SaveAs process.
    • more precisely, I have 2 copies of the file, one named piki and one piki.py
    • if I just run python piki.py or python piki from command-line, it actually returns the rendered HTML of FrontPage!
    • if I ask for /piki.py?BillSeitz
      • by browser I get the plaintext of the script
      • by curl -v <http://localhost:8000/piki.py?BillSeitz> I get {{{
  • Connected to localhost (127.0.0.1) port 8000 (#0)

GET /piki.py?BillSeitz HTTP/1.1 User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 Open S S L/0.9.8l zlib/1.2.3 Host: localhost:8000 Accept: /

  • HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: SimpleHTTP/0.6 Python/2.7.2 < Date: Fri, 09 Mar 2012 18:18:48 GMT < Content-type: text/plain < Content-Length: 17657 }}}

    • if I ask for /piki?BillSeitz (which is what used to work)
      • by browser I get the SaveAs dialog
      • by curl I get {{{
  • Connected to localhost (127.0.0.1) port 8000 (#0)

GET /piki?BillSeitz HTTP/1.1 User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 Open S S L/0.9.8l zlib/1.2.3 Host: localhost:8000 Accept: /

  • HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: SimpleHTTP/0.6 Python/2.7.2 < Date: Fri, 09 Mar 2012 18:22:11 GMT < Content-type: application/octet-stream < Content-Length: 17654 < Last-Modified: Fri, 09 Mar 2012 18:14:20 GMT }}}
    • rip out 99% of the piki.py to experiment with bare bones. Hitting either URL with C Url gives body of script, only difference is the Content-type, just like with fancier case. In neither case is the script getting executed.
  • figure out that if I can change pcgi.py line to handler_class.cgi_directories = ['/'] then it works!
  • unfortunately SCRIPT_NAME is now coming as //piki which causes absolute-reference issues. Tweak that function to strip slashes then add back a single one. Now all good! (Not that I know what actually caused the change in behavior.)

Create VirtualEnv - argh, it's using Python 2.6 instead of 2.7.

  • changed $PATH in bash_profile
  • next have to re-install virtualenv, etc. Still pointing at wrong place {{{ $ virtualenv st --distribute New python executable in st/bin/python Error [Errno 2] No such file or directory while executing command install_name_tool -change /System/Library/Fram.../Versions/2.6/Python @executable_path/../.Python st/bin/python Could not call install_name_tool -- you must have Apple's development tools installed Traceback (most recent call last): File "/usr/local/bin/virtualenv", line 8, in load_entry_point('virtualenv==1.7.1.2', 'console_scripts', 'virtualenv')() File "/Library/Python/2.6/site-packages/virtualenv.py", line 928, in main never_download=options.never_download) }}}
    • sys.path shows all 2.7 stuff
  • (Mar10'2012) hmm, or maybe the real issue is the lack of install_name_tool. Per this I'm installing just the command-line-tools part of X Code, hoping I don't have to install the whole thing.
    • of course there's no download of that piece available from Apple for my 10.6.x MacOs X.
    • so I'm downloading the full X Code 3.2.6 for Snow Leopard.
    • 2GB download, 10GB of disk space installed. Now successful.
  • create virtualenv st, activate it. Install yolk into it.

Now on to some actual Django handling

  • tutorial uses project mysite and then app polls with model classes Poll and Choice
  • pip install django using docs https://docs.djangoproject.com/en/1.3/
  • verify that I have django v1.3.1
  • freeze pip freeze > requirements.txt
  • django-admin.py startproject mf - I'm still at the /djcode/ level, so it creates mf directory beside st.
  • (went back and tweaked the pcgi.py for PikiPiki to use port 8001 since Django will default to 8000.)
  • go into directory, do python manage.py runserver seems good, hit URL, definitely good. Kill server
  • edit settings.py - add myself to ADMINS list, enter various DATABASES params for sqlite3 per my Sept15'2010 Django notes. Uncomment the admin INSTALLED_APPS while I'm at it.
  • do python manage.py syncdb it creates tables, prompts me for Super User info, all good.
  • do python manage.py startapp family to make app
  • next: models

Some meta-notes on models

  • here's the built-in model for users
  • I recall people recommending to me in the past to avoid exposing integer IDs to users/spiders. So should I aim to use UUID as ID?
    • reading a variety of things like this tell me not to do that, but rather have a field like user_uuid as a secondary index.
    • django-extensions provides for a UUID field-type, which is more efficient than using long-char to store it.
    • here's how to effectively add fields to the User model.
  • defining many-to-many relationships
  • defining "choices" (selection-list) for a field's value. (Have to decide whether to associate text values with a key.)
    • suspect I'm going to have different subtypes of 'tasks' in a single table, each subtype having its own set of valid 'status' values - there are good notes on doing this in the form.

Creating database schema from models

  • edit family/models.py
  • edit settings.py to add family to list of INSTALLED_APPS
  • do python manage.py sql family, get {{{ (in) class Family(models.Model): users = models.ManyToManyField(User) Name Error: name 'User' is not defined }}}
    • use command-line to enter SQLite, confirm that auth_user table exits (with my super-user record in it). Various examples seem to refer to this as class User.
    • ah, adding from django.contrib.auth.models import User up top solved this
    • notice that all the tables will get family_ as a prefix. Is this what's supposed to happen, or is this a sign I'm running manage.py from the wrong directory or something? Yes this is normal behavior. So do python manage.py syncdb.

Trying admin interface

But in resolving a stupid mistake above, got alert that showed me I'm running Python 2.6 in here instead of 2.7!

  • so, within virtualenv, just run python and see 2.6.1 in the response block.
  • some links: 1 here here
  • but decide I'm actually going to ignore this, since what really matters is that 2.7 is what gets installed on Heroku, not on my dev machine.

Mar12'2012

Use admin interface to enter some reference data (status codes, since will be dependent on task-type can't just use choices)

Use admin interface to start entering some real master data (master Goals and tasks to pick from)

  • find that by default ForeignKey field values can't be left as null
    • here's how to set Model to allow null
    • have to use South to migrate data
      • screwed up that setup process somehow. Finally fixed by using reset south method. Then got change made/migrated. (Also had to set default values for fields that I was changing to allow null, even though there were no actual records in that table.)
    • (Mar13) can browse admin again, no data lost, all good.
  • can add some tasks now
  • tweak __unicode__() methods in a couple models to make admin record-lists more useful
  • next steps
    • add some more reference projects/tasks
    • add a few Resources
    • start on user interface

Adding more tasks

  • hmm, listing seems to show many records having a value that I thought I left null - is that the real data, or an issue with the unicode method? Need to sniff data directly.
    • cleaned up some data with command-line, but weirdness is definitely in admin-unicode listing, not the data.
    • ah, if you refer to a ForeignKey in your unicode method, it gives you the entire unicode output of the linked record - that could get weird if you have a big hierarchy of records...

Done with some Tasks and Resources (Mar15).

Update some wireframes, esp of the user "dashboard".

Starting making a non-admin View following tutorial3, something isn't working.

So go back to tutorial2 on Admin Views.

Tweak field order/grouping for admin view of Tasks. Nice. (Mar25)

  • find how to display a related-record-field in an admin list view
  • never play with the admin templates or fancier views

Start on non-admin views (Apr03)

  • enter 2 lines into urls.py like url(r'^tasks/$', 'tasks.views.index'), and equiv for 'tasks.views.detail'
  • hit url /tasks, get 500 status ViewDoesNotExist at /tasks; Could not import tasks.views. Error was: No module named tasks.views
  • hmm, could this be related to templates location? Go back to tutorial-2 to look at that bit.
    • create directory /djcode/mf/mytemplates/
    • edit settings.py setting TEMPLATE_DIRS to ~/documents/djcode/mf/mytemplates
    • copy base_site.html from /django/contrib/admin/templates/admin to .../mytemplates/admin/
    • hit /admin/ url, not get ViewDoesNotExist error specific to tasks.views again!
  • another possible source of my confusion: polls in tutorial could refer to app or to 1 of its models!
  • so I add a couple url routes for family and hit url /family - now I get the Tried index in module family.views. Error was: 'module' object has no attribute 'index' error expected from the tutorial.
    • of course, because family is both my app and 1 of my models, things are still confusing!
      • Actually, it's clear from the later bits of tutorial-3 that this is definitely the app name being referenced. What's confusing is how to handle urls and views from multiple models within an app.
      • And, scanning forward, discover that all this view work gets dumped with "generic views functions" in tutorial-4, but then after that you find out that in Django 1.3 they've changed to class-based generic views, for which there is no tutorial. Sigh.
    • separate issue: do I want my urls to start with family, families, or familys? I guess I'll go with family.
    • build index.html and detail.html views, all works fine so far
    • but can't get a listing-view from a model not tied by foreign-key to a single Family record. And no examples in the tutorial to help.
    • Some non-tutorial info on queries is based around a WebLog app with app=blog and models of Blog, Author, Entry. But don't see that model carried over into Views, so it's not helpful.
    • The info on class-based Views uses yet another model: app=books, models of Publisher, Book.
      • then shows way of using ListView in urls.com and making a *_list.html template to render it.
        • also note that using extends "base.html" means needing a base.html wrapper template up beside the app directory at the top of the templates directory.
        • if this was a foreign-key related table, then I could display this sort of detail-list within the parent/related record using DetailView. Will get to that...
      • now extend task_list.html template to link to the single-task detail view.... how?
        • tried wrapping item with task.get_absolute_url but that returned an empty string... ah, would need to define that method in the model
        • try <a href="{% url task task.id %}"> - got Caught No Reverse Match while rendering: Reverse for 'task' with arguments '(1,)' and keyword arguments '{}' not found.

Apr17: I'm getting tired of figuring out a framework. I want a mini/lite framework/library. I like writing SQL methods and stepping through dictionaries, etc. call me crazy. Gloria W says Pyramid "is the framework for people who hate Django", so I'll see if that feels better. Pyramid For Simplest Thing...


Edited:    |       |    Search Twitter for discussion