Kecko.comhttp://kecko.com/feeds/atom/2013-08-29T13:52:40+00:00Say *what* again, I dare ya, I double-dare ya!Django: Unknown command: 'test'2013-08-29T13:52:40+00:00scoopseven/author/scoopseven/http://kecko.com/django-unknown-command-test/<p>Got this error running tests on a new project and couldn't figure out what the problem was. Found a similar problem with someone using <a href="http://stackoverflow.com/questions/14693086/django-jenkins-manage-py-cant-find-imported-commands">Jenkins on SO</a> who found the real error by running:</p>
<blockquote>
<p>python manage.py help</p>
</blockquote>
<p>Turns out I had a missing import in my settings file that immediately revealed itself by running the help command.</p>Export Zinna - Import Mezzanine2013-03-04T16:09:04+00:00scoopseven/author/scoopseven/http://kecko.com/export-zinna-import-mezzanine/<p>I've looked for a decent django blog platform for quite a while before finding Mezzanine a couple of months ago. I finally switched over my stack to Ubuntu upgraded to Django 1.4 and started running Mezzanine. So far, so good.</p>
<p>If anyone is looking for a quick and dirty migration script to move from Zinnia to Mezzanine, here it is in straight SQL:</p>
<pre class="line" id="file-gistfile1-sql-LC1"># Categories<br>insert into mezzanine_db.blog_blogcategory (id, site_id, title, slug)<br>select id, '1', title, slug from zinnia_db.zinnia_category;<br><br># Entries/Posts<br>insert into mezzanine_db.blog_blogpost (id, site_id, title, slug, description, gen_description, status, publish_date, in_sitemap, content, user_id, allow_comments)<br>select id, '1', title, slug, excerpt, '1', '2', creation_date, '1', content, '1', '0' from zinnia_db.zinnia_entry;<br><br># Category->Post Relationships<br>insert into mezzanine_db.blog_blogpost_categories (id, blogpost_id, blogcategory_id)<br>select id, entry_id, category_id from zinnia_db.zinnia_entry_categories;</pre>
<p>As long as you migrate the existing ids, this works perfectly. <a href="https://gist.github.com/scoopseven/5080445">There's also a gist</a>, in case anyone wants to fork it.</p>Python/Django Tips n' Tricks Cheatsheet2012-02-15T10:14:08+00:00scoopseven/author/scoopseven/http://kecko.com/pythondjango-tips-n-tricks-cheatsheet/<p><strong>Converting a unicode string to a list of strings</strong><br />http://stackoverflow.com/questions/5001385/unicode-to-python-object-conversion<br />n = [e.encode('utf-8') for e in s.strip('[]').split(',')]</p><p><strong>Converting a list of longs to a list of ints</strong>new_list = [int(e) for e in queryset]</p>Template Tag Variables2012-01-05T17:28:52+00:00scoopseven/author/scoopseven/http://kecko.com/template-tag-variables/<p>If you've ever needed to save a variable spot in a Django template to be rendered later, there's special tags that allow you to do this:</p><pre>{% templatetag openvariable %}somevariable{% templatetag closevariable %}</pre><p>When this code is rendered by Django, you'll be left with a nice:</p><pre>{{somevariable}}</pre><p>in your rendered template.</p>Finding First or Last Item in a Python List2011-05-06T13:48:37+00:00scoopseven/author/scoopseven/http://kecko.com/finding-first-or-last-item-python-list/<p>
I had a small piece of code I was using to parse a search string in Python for Sphinx.  When you pass "verizon | mobile | at&t" to Sphinx (in boolean mode) it happily returns results.  However, if you pass "verizon | mobile | at&t | " it throws an "unexpected $end near ''" error.  So I needed to not add the extra pipe/or for the last element in my search string.  Using split() to turn the string into a list and then using the [-1] index, you're able to determine if you're on the last element and not add the extraneous "or."</p>
<pre>wordlist = strip_stopwords(search['anywords']).split()
for word in wordlist:
searchstring += word
if word != wordlist[-1]:
searchstring += " | "
</pre>
Sphinx Mode in Python / SphinxSearch Class2011-05-06T09:00:06+00:00scoopseven/author/scoopseven/http://kecko.com/sphinx-mode-python-sphinxsearch-class/<p>In order to get Sphinx to work in boolean mode in Python/Django, you need to pass the "mode" argument as it's plain text value to the SphinxSearch class.</p><pre> search = SphinxSearch(
index = 'my_index another_index',
mode = 'SPH_MATCH_BOOLEAN',
maxmatches = '1000000'
)</pre><p>If you specify mode as it's numeric equivalent (mode = 3, for boolean) Sphinx will throw a "getattr(): attribute name must be string" error (hint, hint).  If you specify "mode = '3'", Sphinx defaults to "SPH_MATCH_ALL," without throwing an error; not too helpful.</p>Rendering a Value as Text in a Django ModelForm2011-04-20T15:50:24+00:00scoopseven/author/scoopseven/http://kecko.com/rendering-value-text-django-modelform/<p>If you need to render a Django ModelFormField as text, that is, the value of that form field as text, you can do so by referring to the bound instance for the ModelForm, like so:</p><pre>{{myform.instance.name}}</pre><p>It's <a href="http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-clean-method">documented here</a> and I found the <a href="http://stackoverflow.com/questions/1134085/rendering-a-value-as-text-instead-of-field-inside-a-django-form">solution on Stackoverlow</a> (big surprise) although it wasn't the top rated/accepted solution (I don't think the question specified ModelForm).</p>Linux Cheatsheet / Commonly Used Commands2011-04-18T14:46:08+00:00scoopseven/author/scoopseven/http://kecko.com/linux-cheatsheet-commonly-used-commands/<p>These are some Linux commands that I find myself searching for on a consistent basis.  These commands are used primarily on Arch Linux distros.</p>
<p><strong id="internal-source-marker_0.5871403720229864">Find all files modified within a a certain time period on linux (eg. last 90 minutes)</strong><br />find /path/of/directory/ -mmin -90</p><p><strong>Get a count of files in all directories</strong><br />for dir in $( find . -type d -print ); do files=$( find $dir -maxdepth 1 -type f | wc -l ); echo "$dir,$files"; done > /root/filelist.txt</p>
<p><strong>Grep a directory for a string</strong><br />grep -r -i somestring /srv/jb/deploy/mediapost.war</p>
<p><strong>Find out who/where processes started from</strong><br />netstat -anp | sort -u<br />also: tcpdump port 80 or tcpdump not port 25 is useful for current connections</p>
<p><strong>Find files larger than 25M</strong><br />find / -type f -size +25M -exec ls -lh {} \;</p>
<p><strong>Size of a directory:</strong><br />du -sL <directoryname></p>
<p><strong>Add a user: </strong><br />adduser bendover </p>
<p><strong>Add existing user to an existing group:</strong><br />usermod -a -G ftp tony</p>
<p><strong>get all users on a server:</strong><br />awk -F: '{print $1}' /etc/passwd</p>
<p><strong>SCP:</strong><br />scp root@host:/var/filename.gz /var<br />scp /var/filename.sql.gz root@host:/var/filename.sql.gz<br />scp /var/filename.sql root@host:/var/filename.sql</p>
<p><strong>Remove all files in current directory with find:</strong><br />find -name 'filename-*' -exec rm {} \;</p>
<p><strong>Gzip entire directory:</strong><br />tar -zcvf /var/filename.tar.gz /folder<br />tar -zcvf /var/filename.tar.gz folder</p>
<p>If you wish to restore your archive then you need to use following command (it will extract all files in current directory):<br />$ tar -zxvf /var/filename.tar.gz </p>
<p><strong>chown symbolic link</strong><br />chown -h myuser:mygroup mysymbolic</p><p><strong>link django admin media to be served on a site</strong><br />ln -s /usr/lib/python2.6/site-packages/django/contrib/admin/media /srv/yoursite/admin-media</p>Zinnia, My Django Blog2011-04-05T13:41:44+00:00scoopseven/author/scoopseven/http://kecko.com/zinnia-my-django-blog/<p>UPDATE: 4/7/11 !!! IMPORTANT !!! Read the comments between Julien and I below before installing or deciding to install Zinnia.  It's far easier than I lay out in this post.  I'm leaving here for reference of what not to do :) --Mark</p><p>After writing so much lately about Django and Python I felt silly doing so on a hosted WordPress blog.  So for no good reason, I started investigating Django blogging engines. I decided to go with Zinnia.  It's an app, which means I can include it in other projects I have already started or going.  The documentation is fairly complete (or seemed to be) and it's still supported / in development. The main missing ingredient is multi-blog support, which is possibly in the works.</p><p>If you've decided on using a Django blog and Zinnia is your choice, I'll let you in on a couple secrets that may save you some time during installation and conversion from WordPress, if that's where you're coming from.  </p><p>There are <a href="http://django-blog-zinnia.com/documentation/install/#getting-the-code">three ways to install Zinnia</a>, all which will load all of the dependencies for you.  When I did this on my Apple Macbook (for development/testing purposes) I ran the pip install, copied the Zinnia project code from /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_blog_zinnia-0.8-py2.6.egg/zinnia (where it installed), placed that code in my project and p<a href="http://django-blog-zinnia.com/documentation/install/#applications">ut the proper lines in my settings.py</a> file. All of that was pretty seamless. When I updated templates (to change the look) I saw the changes immediately on my local python runserver. </p><p>I repeated this process on my production Arch Linux machine, the application acted differently.  When I updated my live server with the updated templates, I didn't see any of the design changes.  Restarted apache, still nothing. So I ran the zinnia pip install again, restarted apache and whaddyaknow, there were my changes.  On the production machine, it seems like Django/Python ignores the "zinnia" installed app in settings.py and runs the code/templates from the site-packages/django_blog_zinnia-0.8-py2.6.egg/zinnia folder. Since I didn't want to have code in there and have my project live in two places, I deleted the site-packages/django_blog_zinnia-0.8-py2.6.egg/zinnia folder and make a symbolic link to the zinnia folder in my project. </p><code><p>ln -s /path/to/your/project /usr/lib/python2.6/site-packages/django_blog_zinnia-0.8-py2.6.egg/zinnia</p></code><p>Now my project lives in one place and Zinnia works as it should. Yay!</p><p>Another thing that impressed me about Zinnia is that it includes <a href="http://django-blog-zinnia.com/documentation/wordpress_2_zinnia/">tools for converting to and from WordPress</a>. When I exported my WordPress xml file, ran the script and started getting errors:</p><code><p>xml.parsers.expat.ExpatError: unbound prefix</p></code><p>I was starting to think I'd made the wrong decision going with Zinnia. This time though, the problem was on Python/WordPress. WordPress exports with this xmlns information in the rss tag:</p><code><p><rss version="2.0"<br />xmlns:excerpt="http://wordpress.org/export/1.0/excerpt/"<br />xmlns:content="http://purl.org/rss/1.0/modules/content/"<br />xmlns:wfw="http://wellformedweb.org/CommentAPI/"<br />xmlns:dc="http://purl.org/dc/elements/1.1/"<br />xmlns:wp="http://wordpress.org/export/1.0/">  </p></code><p>If you add this line:</p><code><p>xmlns:atom="http://www.w3.org/2005/Atom"</p></code><p>The error magically goes away.  I found that <a href="http://stackoverflow.com/questions/3249799/python-feedparser-not-using-atom-wordpress-namespace">solution on StackOverflow</a>.  It wasn't a horrible process once I found the couple of gotcha's, so don't be afraid to ditch WordPress!</p>Empty / Default Option for ModelChoiceField in Django2011-04-01T20:44:15+00:00scoopseven/author/scoopseven/http://kecko.com/empty-default-option-for-modelchoicefield-in-django/UPDATE (8/4/2011):
Where have you been all my life, empty_label? Of course, Django has a much cleaner non-javascript solution:
<code>def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['field1'].empty_label = 'Select Something'
    self.fields['field2'].empty_label = 'Select Something Else'
</code>
UPDATE (4/5/2011):
When you do what I suggested in the original post, the default shows up, as expected, but it turns out you lose all of Django's automatic ability to deal with the ModelForm, so you have to do all of the form processing manually. Blah. A much better solution is to use jQuery:
<code>// django doesn't let us override the default value for ModelFormField: http://code.djangoproject.com/ticket/13769
// cheat with jQuery and setup the default options
$("#id_firmtype option:eq(0)").replaceWith("<option>Select a Firm Type</option>");
$("#id_jobfunction option:eq(0)").replaceWith("<option>Select a Job Function</option>");
$("#id_firmtype option:eq(0)").attr("selected", "selected");
$("#id_jobfunction option:eq(0)").attr("selected", "selected");</code>
ORIGINAL POST:
In <a href="http://scoopseven.wordpress.com/2011/03/14/django-choicefield-empty-option-for-selectdropdown/">an earlier post</a> we figured out how to add a default option to a Django ChoiceField within a form (forms.Form). The same task is slightly different when we're dealing with a ModelChoiceField within an ModelForm (forms.ModelForm). This is a three-step process. First, in the ModelForm, we have to change the field to a ChoiceField manually:
<code>myformfield = forms.ChoiceField(choices=[ (x.id, x.description) for x in MyModel.objects.all()])</code>
Then, you need to override the init function in your ModelForm (and you can modify the label too, if it pleases you) to insert a value that you can choose as the default when you instantiate the form:
<code>def __init__(self, *args, **kwargs):
    super(MyModelForm, self).__init__(*args, **kwargs)
    if not self.fields['myformfield'].choices[0][0] == '':
        self.fields['myformfield'].choices.insert(0, (0,'Choose an Option') )
    self.fields['myformfield'].label = "This is fun"</code>
Finally, when you instantiate the form, choose that default value you inserted in your init def:
<code>my_form = MyModelForm(prefix='somevalue', initial={'myformfield':0})</code>
I've seen several different suggestions, but this is the only way that I could get this to function properly.
Print CGI / META /QUERY_STRING in Django Template2011-04-01T15:17:28+00:00scoopseven/author/scoopseven/http://kecko.com/print-cgi-meta-query_string-in-django-template/Differentiating how to display or access variables/structures/dictionaries in Django templates (as opposed to views) can get frustrating. All I was trying to do was print the query string in a template. That's. It. Why couldn't I just do:
<code>{{request.META['QUERY_STRING']}}</code>
Oh yea, because you can't access a dictionary with that notation in templates... FTW! Here's the correct (and hard to find solution).
<code>{{request.META.QUERY_STRING}}</code>
This correctly outputs the whole query string in your template.Unpacking a Tuple in a Django Template2011-04-01T14:38:23+00:00scoopseven/author/scoopseven/http://kecko.com/unpacking-a-tuple-in-a-django-template/You've passed in a tuple to your template and now you're trying to access the separate indexes/items in a loop. Here's the tuple:
<code>REGIONS = ( (1, 'East'), (2, 'West'), (3, 'South') )</code>
And this is how you'd unpack/decode it in your Django template:
<code>for id, region in REGIONS:
print 'id: %s, region: %s' %(id, region)</code>
If only everything was that easy.Multiple Form Fields with the Same Name / Form Field Value as a List in Django2011-03-31T04:38:30+00:00scoopseven/author/scoopseven/http://kecko.com/multiple-form-fields-with-the-same-name-form-field-value-as-a-list-in-django/I encountered a scenario where I have a list that I needed to pass over in a form, something like:
<code><input type="hidden" name="ids" value="1,2,3,4,5"></code>
I figured in my views.py, I would just loop over the items (it's a list, right) and process the ids. Instead, Django did something I found very peculiar. When I iterated over the form field:
<code>for id in request.POST['ids']:
print id</code>
printed "1" "," "2" "," etc. Not exactly what I was looking for. Instead of trying to fudge around with this, I found a much better solution where I just had 5 form fields, all named id:
<code><input type="hidden" name="id" value="1">
<input type="hidden" name="id" value="2">
<input type="hidden" name="id" value="3">
etc.</code>
Then, in my view:
<code>ids = request.POST.getlist('id')
for id in ids:
print id
</code>
properly printed "1" "2" "3", etc. I could see how this might be really useful dealing with checkboxes or radio buttons as well.
Display Tuple Value for Choices Field in Django2011-03-23T13:50:00+00:00scoopseven/author/scoopseven/http://kecko.com/display-tuple-value-for-choices-field-in-django/I know, this is an odd name for a post. I'm trying to explain this:
<blockquote>For every field that has choices set, the object will have a get_FOO_display() method, where FOO is the name of the field. This method returns the "human-readable" value of the field.</blockquote>
When you define a field on a model and set it to a CHOICES field, like this:
<code>gender = models.CharField(max_length=1, choices=GENDER_CHOICES)</code>
where GENDER_CHOICES is a tuple, the data that's stored in that field is a reference (often an integer) that doesn't represent the actual value of the field. So when you need to display the actual value, rather than the key that's stored in the field, you need to do this.
<code>Model.get_FOO_display()</code>
where FOO is your field name.
<a href="http://docs.djangoproject.com/en/1.2/ref/models/instances/#django.db.models.Model.get_FOO_display">Here's the official documentation.</a>
Sort Python Dictionaries by Key or Value2011-03-15T13:15:59+00:00scoopseven/author/scoopseven/http://kecko.com/sort-python-dictionaries-by-key-or-value/Dictionaries have no __order__ so when you're need to sort one, you're out of luck, right? Not so! Found <a href="http://www.python.org/dev/peps/pep-0265/">this goodness</a> with instructions on sorting/ordering Python dictionaries by key or value. I needed to sort a dictionary of regions alphabetically to populate a ChoiceField/select/dropdown box.
<blockquote>from operator import itemgetter
regions = sorted(region_dict.iteritems(), key=itemgetter(1))
</blockquote>
Before sort:
<blockquote>
{3: 'West', 4: 'East', 5: 'South', 6: 'Mid-West'}
</blockquote>
After sort:
<blockquote>
[(4, 'East'), (6, 'Mid-West'), (5, 'South'), (3, 'West')]
</blockquote>Django ChoiceField Empty Option for Select/Dropdown2011-03-14T15:27:22+00:00scoopseven/author/scoopseven/http://kecko.com/django-choicefield-empty-option-for-selectdropdown/If you're looking to add a empty_label to your ChoiceField, like you can for ModelChoiceField (empty_label="All"), you're going to have to override __init__ on your form. This solution I found on <a href="http://stackoverflow.com/questions/1765757/choicefield-doesnt-display-an-empty-label-when-using-a-tuple-am-i-doing-someth">StackOverflow</a> works well.
<code>COMPETITION_TYPE_CHOICES = (
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
)</code>
<code>class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)</code>
<code> def __init__(self, *args, **kwargs):
super(CompetitionSearchForm, self).__init__(*args, **kwargs)
if not self.fields['type'].choices[0][0] == '':
self.fields['type'].choices.insert(0, ('','---------' ) )</code>Comparing Python Date and Datetime / Django2011-03-11T16:44:19+00:00scoopseven/author/scoopseven/http://kecko.com/comparing-python-date-and-datetime-django/I'm always doing this, so some of you must be too. I'll compare a date field in with a datetime object in Python/DJango like this:
<blockquote><code>if self.start_date < datetime.datetime.now():</code></blockquote>
and I'll get:
<blockquote>type object 'datetime.datetime' has no attribute 'datetime'</blockquote>
Grrrr, this is super-annoying. Of course, it's a simple fix.
<blockquote><code>if self.start_date < date.today():</code></blockquote>
Yaaaaayyyyy!
Django 1.2.4 / get_current_site2010-12-28T19:01:59+00:00scoopseven/author/scoopseven/http://kecko.com/django-124-get_current_site/Problems upgrading to Django 1.2.4 by downloading the package manually and running the install?
<code>Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/servers/basehttp.py",
line 280, in run
self.result = application(self.environ, self.start_response)
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/servers/basehttp.py",
line 674, in __call__
return self.application(environ, start_response)
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/handlers/wsgi.py",
line 230, in __call__
self.load_middleware()
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/handlers/base.py",
line 42, in load_middleware
raise exceptions.ImproperlyConfigured('Error importing middleware
%s: "%s"' % (mw_module, e))
ImproperlyConfigured: Error importing middleware events.middleware:
"cannot import name get_current_site"</code>
I searched the django source for 1.2.3 and there's no references to
"get_current_site", so it's something new in 1.2.4. Here's the
description of what it does from the Django site
(http://docs.djangoproject.com/en/1.2/ref/contrib/sites/):
<blockquote>Changed in Django Development version.
For code which relies on getting the current domain but cannot be certain that the sites framework will be installed for any given project, there is a utility function get_current_site() that takes a request object as an argument and returns either a Site instance (if the sites framework is installed) or a RequestSite instance (if it is
not). This allows loose coupling with the sites framework and provides a usable fallback for cases where it is not installed.</blockquote>
To fix the problem, stop any runserver you have going and reinstall
django from pip:
sudo pip install http://www.djangoproject.com/download/1.2.4/tarball/
Restart your project and it'll work fine. Installing from pip must do
something that we neglected to do installing manually.Installing MySQLdb for Python / Django 2009-12-03T21:47:27+00:00scoopseven/author/scoopseven/http://kecko.com/installing-mysqldb-for-python-django/Problems installing MySQLdb? Me too! I'm installing using MySQL 5 / Django 1.1 / Python 2.4 on CentOS 5.4 linux.
First, make sure all of the dependencies are installed and up-to-date
<code>yum install python-devel
yum install mysql-devel
yum install zlib-devel
yum install openssl-devel
yum install gcc</code>
Then, download MySQLdb. Be careful here, when you do a search on Google or are pointed to the site it's usually sending people to the Zope installer. The actual files you're looking for can be downloaded from the link below, in the mysql-python folder, I'm using version 1.2.2.
<code>http://sourceforge.net/projects/mysql-python/files/
tar -xzvf MySQL-python-1.2.2.tar.gz
cd MySQL-python-1.2.2
python setup.py build
python setup.py install</code>
To test:
<code>python
>>> import MySQLdb</code>
Comment or email if you found this useful.
Django / PythonPath2009-07-08T03:25:24+00:00scoopseven/author/scoopseven/http://kecko.com/django-pythonpath/The post below was taken directly from <a href="http://www.ventanazul.com/webzine/articles/pythonpath-configuring-apache-django-mod-python">www.ventanazul.com</a>. I republished only because this solved a problem that was a real PITA for me and wasn't spelled out too clearly in the Django documentation. If you're having a problem with Django / Apache / mod_python / PythonPath / sys.path / Could not import module things, give it a try.
<strong>The importance of PYTHONPATH</strong>
According to the official documentation this is what you need on your Apache's site configuration to setup Django:
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonOption django.root /mysite
PythonPath "['/path/to/project'] + sys.path"
PythonDebug On
</Location>
Obviously PythonDebug On should not appear, or should be set to Off, on a production environment.
The lines above assume that your Django project is called mysite and the site is on http://example.com/mysite. And even if the documentation mentions how to handle PYTHONPATH via mod_python I didn't have a clear picture of the whole thing after running my first failed tests.
I decided to setup a site dedicated just to my Django project, you can use name based or IP based virtual hosts on Apache, and I want to access it from the root: http://example.com/. Also, I store all my Python related stuff in /home/alexis/python-work hence the project will be at /home/alexis/python-work/project and its only application below it: /home/alexis/python-work/project/app.
I know there are better ways to organize reusable applications on Django, as James Bennett suggests, but for my project a traditional project/app structure was enough. Anyway, the following ideas can be applied to any setup. Let's see all the lines I use on Apache to setup a Django site:
<VirtualHost 192.168.0.180>
ServerName example.com
ServerAdmin alexis@example.com
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE project.settings
PythonDebug On
PythonPath "['/home/alexis/python-work', '/home/alexis/python-work/project'] + sys.path"
</Location>
</VirtualHost>
The IP on VirtualHost, 192.168.0.180, is the private one I'll be using for this site. I've also added 192.168.0.180 example.com in /etc/hosts to avoid changes on the DNS server, something you should do on production.
project.settings refers to the settings.py file inside the /home/alexis/python-work/project directory.
I've also removed PythonOption django.root /mysite because this site sits on root, Location "/", and there's no need to specify a subdirectory.
<strong>And the most important part:
PythonPath "['/home/alexis/python-work', '/home/alexis/python-work/project'] + sys.path"</strong>
This is how you add paths to PYTHONPATH via mod_python. Notice we have two paths, one for the parent directory and another for the project, both are needed to get all your imports right. Django's documentation highlights this:
Remember: the parent directories of anything you import directly must be on the Python path.
After adding these changes you should restart Apache, or possibly just reload, and be able to access your Django site at http://example.com/.