Django Form Invalid, Despite No Errors

I was using Django CBV FormView. The form was being flagged as invalid but when I inspected the form inside the form_invalid() method using the PyCharm debugger, there were no errors. When I traced deeper into the Django code, I found this line that is returned by the is_valid() method.:

return self.is_bound and not self.errors

It turned out my form was not bound. But why would that be???

The problem was I over-rode the get_form_kwargs() method and forgot to call super(). The POST data is one of the kwargs passed to the form. If you don’t call super(), the post data does not make it into the form kwargs. Hence the form remains unbound.

Advertisements

SSH Connection Using Pgadmin4 on Ubuntu 16.04

Pgadmin4 has a GUI for connecting to a remote DB. Seems pretty straight forward. And then you get this error:

module ‘paramiko’ has no attribute ‘Ed25519Key’

After some googling you find this Stack Overflow post. Looks like you need to install paramiko 2.4. If you follow the instructions in SO, you end up with a failed install due to missing dependencies. Turns out there is no pre-built distribution of paramiko 2.4 for Ubuntu 16.04.

If you move on the the SO answer that suggests editing /usr/lib/python3/dist-packages/sshtunnel.py. I tried that. It was easy. Only two lines needed to be removed. However after that, I kept getting errors like ‘Could not establish session to SSH gateway’ and ‘Could not connect to gateway’.

Eventually I solved the problem by creating an ssh tunnel from the Ubuntu command line and then connecting to the tunnel in pgadmin.

 

 

Django: Putting Form Values in the URL Query String

I used to avoid using URLs with long query strings. This was partially due to an essay I read by a Big Shot about how URLs should be beautiful. Not sure I agree any more.

My use case is the user enters some filter parameters, a database query is run and a report is generated. Putting the filter parameters in the query string allows users to return to the page at another time or to share the link.

Here is the code:

from django.views.generic.edit import FormView
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.utils.http import urlencode


class MyFormView(FormView):
    def form_valid(self, form):
        base_url = reverse('filter_tickets_result')

        # Post process some fields
        if form.cleaned_data['job']:
            form.cleaned_data['job'] = form.cleaned_data['job'].id
        qs = urlencode(form.cleaned_data)
        return HttpResponseRedirect(base_url + '?' + qs)

Note, I am using the Django version of urlencode. This avoids issues with Python 2.X and 3.X.

Reading Public Google Calendars using Python

There are many ways to access google calendars using python. You probably have already stumbled on the “Quick Start” page in the Google docs. This uses Oauth to authenticate requests and requires a human to approve the access.

But if you are reading from a public calendar, is all the necessary? No. You still need a developer key so that Google can keep track of your quota. But that is all you need.

Here is the solution from Stack Overflow. The trick is to use the developerKey keyword in the “build” function:

dev_Key = "Insert your dev key here"
service = build('calendar', 'v3', developerKey=dev_Key)

Django StaticLiveServerTestCase Gotchas

I was trying to do some Django (1.11) tests using StaticLiveServerTestCase and Selenium, but for all pages, I was getting an HTTP 500 error. There was no obvious way to debug this. Eventually I discovered this:

StaticLiveServerTestCase sets DEBUG=False before running

To debug the StaticLiveServerTestCase I set DEBUG=False and ran the development server. This also produced the HTTP 500 error and generated an email that explained that the problem was:

Exception Value: The file 'images/favicon/favicon.ico' could not be found with <pipeline.storage.PipelineCachedStorage object at 0x7f82db7f2250>.

For my settings files, I have a base settings file and then a separate settings file for each location (e.g. dev, staging, production). The location settings file imports the base settings file and then adds and over-rides settings as needed.

No matter how you generate your dev settings file, in the end you want:

PIPELINE = {'PIPELINE_ENABLED': False}
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'

Note: after you make those changes, if you run the dev server with DEBUG=False, your static files will not be served. But if you run StaticLiveServerTestCase with DEBUG=False the static files will be served. This is because StaticLiveServerTestCase has a static file server built into it.

 

Django Site Works Most Places, Except the IPhone

I had a Django 1.11 site running with nginx and gunicorn. It worked on several devices, including my Ubuntu desktop, a Mac laptop, and an IPad. But it did not work on my Iphone.

On my IPhone, I got a “network connection failed” error.

On my server, there was no record of my Iphone page request in the nginx access log and there wa no record in the nginx error log either.

The clue was in the /var/log/nginx/error.log. This file had a ton of lines like:

2019/03/03 13:42:46 [alert] 4820#0: worker process 18707 exited on signal 11 (core dumped)

To fix it, I made a bunch of changes to my nginx config file. I am not sure which line was causing the crash. But it is working now.