From 5edfe34bcf9d0d3e4cb5aa0d5f8aecdc77bde225 Mon Sep 17 00:00:00 2001
From: Asheesh Laroia <asheesh@asheesh.org>
Date: Mon, 5 Dec 2011 17:47:24 -0500
Subject: [PATCH 2/4] Add Launchpad form and adjust views accordingly

---
 mysite/customs/bugimporters/__init__.py            |    7 +
 mysite/customs/forms.py                            |   14 +
 ...uerymodel_url__del_field_launchpadquerymodel.py |  259 ++++++++++++++++++++
 mysite/customs/models.py                           |   20 +-
 mysite/customs/templates/customs/edit_tracker.html |    2 +
 mysite/customs/tests.py                            |   29 +++
 mysite/customs/views.py                            |   10 +-
 7 files changed, 331 insertions(+), 10 deletions(-)
 create mode 100644 mysite/customs/migrations/0031_auto__del_field_launchpadquerymodel_url__del_field_launchpadquerymodel.py

diff --git a/mysite/customs/bugimporters/__init__.py b/mysite/customs/bugimporters/__init__.py
index ad57802..0672a06 100644
--- a/mysite/customs/bugimporters/__init__.py
+++ b/mysite/customs/bugimporters/__init__.py
@@ -45,4 +45,11 @@ all_trackers = {
             'urlmodel': mysite.customs.models.TracQueryModel,
             'urlform': mysite.customs.forms.TracQueryForm,
             },
+        'launchpad': {
+            'namestr': 'Launchpad',
+            'model': mysite.customs.models.LaunchpadTrackerModel,
+            'form':  mysite.customs.forms.LaunchpadTrackerForm,
+            'urlmodel': mysite.customs.models.LaunchpadQueryModel,
+            'urlform': mysite.customs.forms.LaunchpadQueryForm,
+            },
         }
diff --git a/mysite/customs/forms.py b/mysite/customs/forms.py
index aaa8788..7ba3bf9 100644
--- a/mysite/customs/forms.py
+++ b/mysite/customs/forms.py
@@ -23,6 +23,7 @@ class TrackerTypesForm(django.forms.Form):
     TRACKER_TYPES = (
             ('bugzilla', 'Bugzilla'),
             ('google', 'Google Code'),
+            ('launchpad', 'Launchpad'),
             ('roundup', 'Roundup'),
             ('trac', 'Trac'),
             )
@@ -69,3 +70,16 @@ class RoundupQueryForm(django.forms.ModelForm):
     class Meta:
         model = mysite.customs.models.RoundupQueryModel
         exclude = ('tracker', 'last_polled',)
+
+class LaunchpadTrackerForm(TrackerFormThatHidesCreatedForProject):
+    max_connections = django.forms.IntegerField(
+        widget=django.forms.HiddenInput(), initial=8)
+    custom_parser = django.forms.CharField(
+        widget=django.forms.HiddenInput(), required=False)
+    class Meta:
+        model = mysite.customs.models.LaunchpadTrackerModel
+
+class LaunchpadQueryForm(django.forms.ModelForm):
+    class Meta:
+        model = mysite.customs.models.LaunchpadQueryModel
+        exclude = ('tracker', 'last_polled',)
diff --git a/mysite/customs/migrations/0031_auto__del_field_launchpadquerymodel_url__del_field_launchpadquerymodel.py b/mysite/customs/migrations/0031_auto__del_field_launchpadquerymodel_url__del_field_launchpadquerymodel.py
new file mode 100644
index 0000000..5ca05dd
--- /dev/null
+++ b/mysite/customs/migrations/0031_auto__del_field_launchpadquerymodel_url__del_field_launchpadquerymodel.py
@@ -0,0 +1,259 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Deleting field 'LaunchpadQueryModel.url'
+        db.delete_column('customs_launchpadquerymodel', 'url')
+
+        # Deleting field 'LaunchpadQueryModel.description'
+        db.delete_column('customs_launchpadquerymodel', 'description')
+
+
+    def backwards(self, orm):
+        
+        # Adding field 'LaunchpadQueryModel.url'
+        db.add_column('customs_launchpadquerymodel', 'url', self.gf('django.db.models.fields.URLField')(default='', max_length=400), keep_default=False)
+
+        # Adding field 'LaunchpadQueryModel.description'
+        db.add_column('customs_launchpadquerymodel', 'description', self.gf('django.db.models.fields.CharField')(default='', max_length=200, blank=True), keep_default=False)
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'customs.bugzillaquerymodel': {
+            'Meta': {'object_name': 'BugzillaQueryModel', '_ormbases': ['customs.TrackerQueryModel']},
+            'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'query_type': ('django.db.models.fields.CharField', [], {'default': "'xml'", 'max_length': '20'}),
+            'tracker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.BugzillaTrackerModel']"}),
+            'trackerquerymodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerQueryModel']", 'unique': 'True', 'primary_key': 'True'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '400'})
+        },
+        'customs.bugzillatrackermodel': {
+            'Meta': {'object_name': 'BugzillaTrackerModel', '_ormbases': ['customs.TrackerModel']},
+            'as_appears_in_distribution': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'base_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'}),
+            'bitesized_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'bitesized_type': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
+            'bug_project_name_format': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'documentation_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'documentation_type': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
+            'query_url_type': ('django.db.models.fields.CharField', [], {'default': "'xml'", 'max_length': '20'}),
+            'tracker_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'trackermodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.googlequerymodel': {
+            'Meta': {'object_name': 'GoogleQueryModel', '_ormbases': ['customs.TrackerQueryModel']},
+            'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'label': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'tracker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.GoogleTrackerModel']"}),
+            'trackerquerymodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerQueryModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.googletrackermodel': {
+            'Meta': {'object_name': 'GoogleTrackerModel', '_ormbases': ['customs.TrackerModel']},
+            'bitesized_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'bitesized_type': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
+            'documentation_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'documentation_type': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
+            'google_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'tracker_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'trackermodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.launchpadquerymodel': {
+            'Meta': {'object_name': 'LaunchpadQueryModel', '_ormbases': ['customs.TrackerQueryModel']},
+            'tracker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.LaunchpadTrackerModel']"}),
+            'trackerquerymodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerQueryModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.launchpadtrackermodel': {
+            'Meta': {'object_name': 'LaunchpadTrackerModel', '_ormbases': ['customs.TrackerModel']},
+            'launchpad_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'tracker_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'trackermodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.recentmessagefromcia': {
+            'Meta': {'object_name': 'RecentMessageFromCIA'},
+            'branch': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'committer_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'message': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'module': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'project_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'time_received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'version': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'customs.roundupquerymodel': {
+            'Meta': {'object_name': 'RoundupQueryModel', '_ormbases': ['customs.TrackerQueryModel']},
+            'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'tracker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.RoundupTrackerModel']"}),
+            'trackerquerymodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerQueryModel']", 'unique': 'True', 'primary_key': 'True'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '400'})
+        },
+        'customs.rounduptrackermodel': {
+            'Meta': {'object_name': 'RoundupTrackerModel', '_ormbases': ['customs.TrackerModel']},
+            'as_appears_in_distribution': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'base_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'}),
+            'bitesized_field': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}),
+            'bitesized_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'closed_status': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'documentation_field': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}),
+            'documentation_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'tracker_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'trackermodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.tracbugtimes': {
+            'Meta': {'object_name': 'TracBugTimes'},
+            'canonical_bug_link': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'}),
+            'date_reported': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1970, 1, 1, 0, 0)'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_touched': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1970, 1, 1, 0, 0)'}),
+            'latest_timeline_status': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '15', 'blank': 'True'}),
+            'timeline': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.TracTimeline']"})
+        },
+        'customs.trackermodel': {
+            'Meta': {'object_name': 'TrackerModel'},
+            'created_for_project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['search.Project']", 'null': 'True'}),
+            'custom_parser': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'max_connections': ('django.db.models.fields.IntegerField', [], {'default': '8', 'blank': 'True'})
+        },
+        'customs.trackerquerymodel': {
+            'Meta': {'object_name': 'TrackerQueryModel'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_polled': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1970, 1, 1, 0, 0)'})
+        },
+        'customs.tracquerymodel': {
+            'Meta': {'object_name': 'TracQueryModel', '_ormbases': ['customs.TrackerQueryModel']},
+            'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'tracker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.TracTrackerModel']"}),
+            'trackerquerymodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerQueryModel']", 'unique': 'True', 'primary_key': 'True'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '400'})
+        },
+        'customs.tractimeline': {
+            'Meta': {'object_name': 'TracTimeline'},
+            'base_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_polled': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1970, 1, 1, 0, 0)'})
+        },
+        'customs.tractrackermodel': {
+            'Meta': {'object_name': 'TracTrackerModel', '_ormbases': ['customs.TrackerModel']},
+            'as_appears_in_distribution': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'base_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200'}),
+            'bitesized_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'bitesized_type': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
+            'bug_project_name_format': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'documentation_text': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'documentation_type': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
+            'old_trac': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'tracker_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'trackermodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['customs.TrackerModel']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        'customs.webresponse': {
+            'Meta': {'object_name': 'WebResponse'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'response_headers': ('django.db.models.fields.TextField', [], {}),
+            'status': ('django.db.models.fields.IntegerField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {}),
+            'url': ('django.db.models.fields.TextField', [], {})
+        },
+        'profile.dataimportattempt': {
+            'Meta': {'object_name': 'DataImportAttempt'},
+            'completed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}),
+            'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['profile.Person']"}),
+            'query': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'source': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+            'web_response': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['customs.WebResponse']", 'null': 'True'})
+        },
+        'profile.person': {
+            'Meta': {'object_name': 'Person'},
+            'bio': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'blacklisted_repository_committers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['profile.RepositoryCommitter']", 'symmetrical': 'False'}),
+            'contact_blurb': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'dont_guess_my_location': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'email_me_weekly_re_projects': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'expand_next_steps': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'gotten_name_from_ohloh': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'homepage_url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'irc_nick': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
+            'last_polled': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1970, 1, 1, 0, 0)'}),
+            'location_confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'location_display_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'photo': ('django.db.models.fields.files.ImageField', [], {'default': "''", 'max_length': '100'}),
+            'photo_thumbnail': ('django.db.models.fields.files.ImageField', [], {'default': "''", 'max_length': '100', 'null': 'True'}),
+            'photo_thumbnail_20px_wide': ('django.db.models.fields.files.ImageField', [], {'default': "''", 'max_length': '100', 'null': 'True'}),
+            'photo_thumbnail_30px_wide': ('django.db.models.fields.files.ImageField', [], {'default': "''", 'max_length': '100', 'null': 'True'}),
+            'show_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+        },
+        'profile.repositorycommitter': {
+            'Meta': {'unique_together': "(('project', 'data_import_attempt'),)", 'object_name': 'RepositoryCommitter'},
+            'data_import_attempt': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['profile.DataImportAttempt']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['search.Project']"})
+        },
+        'search.project': {
+            'Meta': {'object_name': 'Project'},
+            'cached_contributor_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True'}),
+            'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_icon_was_fetched_from_ohloh': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'display_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200'}),
+            'homepage': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'icon_for_profile': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'null': 'True'}),
+            'icon_for_search_result': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'null': 'True'}),
+            'icon_raw': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'icon_smaller_for_badge': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'null': 'True'}),
+            'icon_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'language': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
+            'logo_contains_name': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
+            'people_who_wanna_help': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'projects_i_wanna_help'", 'symmetrical': 'False', 'to': "orm['profile.Person']"})
+        }
+    }
+
+    complete_apps = ['customs']
diff --git a/mysite/customs/models.py b/mysite/customs/models.py
index ddd4421..3723f4d 100644
--- a/mysite/customs/models.py
+++ b/mysite/customs/models.py
@@ -362,18 +362,22 @@ class LaunchpadTrackerModel(TrackerModel):
 
 class LaunchpadQueryModel(TrackerQueryModel):
     '''This model stores query URLs for LaunchpadTracker objects.'''
-    url = models.URLField(max_length=400,
-                          blank=False, null=False)
-    description = models.CharField(max_length=200, blank=True, default='')
     tracker = models.ForeignKey(LaunchpadTrackerModel)
 
     def get_query_url(self):
-        pr = urlparse.urlparse(self.url)
-        qs = urlparse.parse_qsl(pr.query)
-        qs.append(('created_since', self.last_polled.isoformat()))
+        qs = [
+            ('ws.op', 'searchTasks'),
+            ('created_since', self.last_polled.isoformat())
+        ]
         qs = urllib.urlencode(qs)
-        pr = (pr.scheme, pr.netloc, pr.path, pr.params, qs, pr.fragment)
-        url = urlparse.urlunparse(pr)
+        parts = (
+            'http',
+            'api.launchpad.net',
+            urlparse.urljoin('/1.0/', self.tracker.launchpad_name),
+            '',
+            qs,
+            '')
+        url = urlparse.urlunparse(parts)
         return url
 
 reversion.register(LaunchpadTrackerModel, follow=["launchpadquerymodel_set"])
diff --git a/mysite/customs/templates/customs/edit_tracker.html b/mysite/customs/templates/customs/edit_tracker.html
index 66b41de..2e96fe3 100644
--- a/mysite/customs/templates/customs/edit_tracker.html
+++ b/mysite/customs/templates/customs/edit_tracker.html
@@ -43,6 +43,7 @@
 {% endblock form_body %}
 
 {% block content_below_form %}
+{% if tracker_urlmodel %}
 <table>
     <tr>
         <th>Tracker URL</th>
@@ -58,4 +59,5 @@
     </tr>
     {% endfor %}
 </table>
+    {% endif %}
 {% endblock content_below_form %}
diff --git a/mysite/customs/tests.py b/mysite/customs/tests.py
index 2efc4c4..8062673 100644
--- a/mysite/customs/tests.py
+++ b/mysite/customs/tests.py
@@ -2208,3 +2208,32 @@ class LaunchpadBugImport(django.test.TestCase):
 
         self.assertEqual('vila', bug_model.submitter_username)
         self.assertEqual('Vincent Ladeuil', bug_model.submitter_realname)
+
+
+@skipIf(mysite.base.depends.lxml.html is None, "To run these tests, you must install lxml. See ADVANCED_INSTALLATION.mkd for more.")
+class LaunchpadTrackerEditingViews(TwillTests):
+    fixtures = ['user-paulproteus', 'person-paulproteus']
+
+    def setUp(self):
+        super(LaunchpadTrackerEditingViews, self).setUp()
+        self.kde = mysite.search.models.Project.create_dummy(name='KDE')
+
+    def test_form_create_launchpad_tracker(self):
+        # We start with no LaunchpadTrackerModel objects in the DB
+        self.assertEqual(0,
+                         mysite.customs.models.LaunchpadTrackerModel.objects.all().select_subclasses().count())
+        form = mysite.customs.forms.LaunchpadTrackerForm({
+                'tracker_name': 'KDE Bugzill',
+                'launchpad_name': 'https://bugs.kde.org/',
+                'created_for_project': self.kde.id,
+                'bitsized_tag': 'easy',
+                'max_connections': '8',
+                'documentation_tag': 'doc',
+                'bug_project_name_format': 'format'})
+        if form.errors:
+            logging.info(form.errors)
+        self.assertTrue(form.is_valid())
+        form.save()
+
+        self.assertEqual(1,
+                         mysite.customs.models.LaunchpadTrackerModel.objects.all().select_subclasses().count())
diff --git a/mysite/customs/views.py b/mysite/customs/views.py
index 0a90515..957b114 100644
--- a/mysite/customs/views.py
+++ b/mysite/customs/views.py
@@ -118,7 +118,8 @@ def add_tracker_do(request, tracker_type):
 @login_required
 def add_tracker_url(request, tracker_type, tracker_name, url_form=None):
     data = {}
-    if tracker_type in all_trackers:
+    if tracker_type in all_trackers and (
+        url_form or all_trackers[tracker_type].get('urlform', None)):
         if url_form is None:
             try:
                 tracker_obj = all_trackers[tracker_type]['model'].all_trackers.get(
@@ -181,8 +182,12 @@ def edit_tracker(request, tracker_type, tracker_name, tracker_form=None):
             if tracker_form is None:
                 tracker_form = all_trackers[tracker_type]['form'](
                         instance=tracker_obj, prefix='edit_tracker')
-            tracker_urls = all_trackers[tracker_type]['urlmodel'].objects.filter(
+            tracker_urlmodel = all_trackers[tracker_type]['urlmodel']
+            if tracker_urlmodel:
+                tracker_urls = tracker_urlmodel.objects.filter(
                     tracker=tracker_obj)
+            else:
+                tracker_urls = []
         except all_trackers[tracker_type]['model'].DoesNotExist:
             return HttpResponseRedirect(reverse(list_trackers) +
                                         '?notification_id=tracker-existence-fail')
@@ -190,6 +195,7 @@ def edit_tracker(request, tracker_type, tracker_name, tracker_form=None):
         data['tracker_type'] = tracker_type
         data['tracker_form'] = tracker_form
         data['tracker_urls'] = tracker_urls
+        data['tracker_urlmodel'] = tracker_urlmodel
         return mysite.base.decorators.as_view(request, 'customs/edit_tracker.html', data, None)
     else:
         return HttpResponseRedirect(reverse(list_trackers))
-- 
1.7.5.4

