diff --git a/gms/gms/settings.py b/gms/gms/settings.py
index 606e6a2f0c791429ff761d1eba6aa29625289a0f..4c34c04ea0f446a64e487601c9e15a40f1b2123e 100644
--- a/gms/gms/settings.py
+++ b/gms/gms/settings.py
@@ -21,6 +21,7 @@ INSTALLED_APPS = (
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'memberdb',
+    'import_members',
 )
 
 MIDDLEWARE = [
@@ -54,6 +55,8 @@ USE_TZ = True
 LOGIN_URL = 'memberdb:login'
 LOGIN_REDIRECT_URL = 'memberdb:index'
 
+DATABASE_ROUTERS = ['import_members.db.MemberDbRouter']
+
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/1.7/howto/static-files/
 
diff --git a/gms/gms/settings_local.example.py b/gms/gms/settings_local.example.py
index 5d5edde7367035293fd7186f5bb5b84901d8c47f..f8984ca920cd8bfd05cc5fb8c02477bfb1b333a9 100644
--- a/gms/gms/settings_local.example.py
+++ b/gms/gms/settings_local.example.py
@@ -14,13 +14,21 @@ ADMINS = (
 ### Database connection options ###
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',     # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+        'ENGINE': 'django.db.backends.sqlite3',     # Add 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
         # this should end up in uccportal/.db/members.db
         'NAME': os.path.join(ROOT_DIR, '.db', 'members.db'),   # Or path to database file if using sqlite3.
         'USER': '',                                 # Not used with sqlite3.
         'PASSWORD': '',                             # Not used with sqlite3.
         'HOST': '',                                 # Set to empty string for localhost. Not used with sqlite3.
         'PORT': '',                                 # Set to empty string for default. Not used with sqlite3.
+    },
+    'memberdb_old': {
+        'ENGINE': 'django.db.backends.postgresql',
+        'NAME': 'uccmemberdb_2018',
+        'USER': 'uccmemberdb',
+        'PASSWORD': 'something-secret-here',
+        'HOST': 'mussel.ucc.gu.uwa.edu.au',
+        'PORT': '',
     }
 }
 
diff --git a/gms/import_members/actions.py b/gms/import_members/actions.py
new file mode 100644
index 0000000000000000000000000000000000000000..26639bff9fbb073d2c90e79c43a20f3ddc672b38
--- /dev/null
+++ b/gms/import_members/actions.py
@@ -0,0 +1,42 @@
+from django.contrib import messages
+from django.core.exceptions import ValidationError
+from django.db import IntegrityError
+
+from .models import OldMember
+from memberdb.models import Member
+
+def import_old_member(modeladmin, request, queryset):
+    """
+    admin action: Import the selected OldMember records into the new MemberDB format
+    don't overwrite records if they already exist (matching by username)
+    """
+    num_success = 0
+    total = queryset.count()
+    for om in queryset:
+        try:
+            # create a new Member object
+            nm = Member(username=om.username)
+
+            # fudge the data as much as we can, people will have to renew memberships and check this anyway
+            nm.first_name, nm.last_name = om.real_name.split(" ", 1)
+            nm.display_name = om.real_name
+            nm.is_guild = om.guild_member
+            nm.phone_number = om.phone_number
+            nm.id_number = om.student_no
+            nm.email_address = om.email_address
+            if (om.membership_type == 1 or om.membership_type == 2): # O'day special or student
+                nm.is_student = True
+            else:
+                nm.is_student = False
+        
+            if (nm.username == '' or nm.username is None):
+                raise ValidationError("username cannot be blank")
+            nm.save()
+            num_success += 1
+        except BaseException as e:
+            modeladmin.message_user(request, 'Could not import record (%s): %s' % (om, e), level=messages.ERROR)
+        
+    if (num_success > 0):
+        modeladmin.message_user(request, 'Successfully imported %d of %d records.' % (num_success, total))
+
+import_old_member.short_description = "Import selected records to new MemberDB"
\ No newline at end of file
diff --git a/gms/import_members/admin.py b/gms/import_members/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..32ca9c7bd743ca1d9a5ac0941284fd76157e9f99
--- /dev/null
+++ b/gms/import_members/admin.py
@@ -0,0 +1,41 @@
+from django.db.models import Q
+from gms import admin
+from memberdb.actions import download_as_csv
+
+from .models import OldMember
+from .actions import import_old_member
+
+class UsernameNullListFilter(admin.SimpleListFilter):
+    """
+    see https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
+    """
+    title = 'membership type'
+    parameter_name = 'type'
+
+    def lookups(self, request, model_admin):
+        return (
+            ('fresh', 'first time member (blank username)'),
+            ('stale', 'recurring member'),
+        )
+
+    def queryset(self, request, queryset):
+        """
+        Returns the filtered queryset based on the value
+        provided in the query string and retrievable via
+        `self.value()`.
+        """
+        fresh = Q(username__isnull=True) | Q(username__exact='')
+        if self.value() == 'fresh':
+            return queryset.filter(fresh)
+        if self.value() == 'stale':
+            return queryset.filter(~fresh)
+
+
+class MemberAdmin(admin.ModelAdmin):
+    list_display = ('real_name', 'username', 'membership_type', 'guild_member')
+    list_filter = ['guild_member', UsernameNullListFilter, 'membership_type']
+    search_fields = ('real_name', 'username', )
+    actions = [download_as_csv, import_old_member]
+
+# Register your models here.
+admin.site.register(OldMember, MemberAdmin)
\ No newline at end of file
diff --git a/gms/import_members/apps.py b/gms/import_members/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..8ab6072b2bb9e1e246d5a801faf4b75de419581d
--- /dev/null
+++ b/gms/import_members/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+class ImportMembersConfig(AppConfig):
+    name = 'import_members'
+    label = name
+    verbose_name = 'Import members from old MemberDB'
diff --git a/gms/import_members/db.py b/gms/import_members/db.py
new file mode 100644
index 0000000000000000000000000000000000000000..32e0d744eab5a2ecba5ee431a246dc304596db28
--- /dev/null
+++ b/gms/import_members/db.py
@@ -0,0 +1,30 @@
+"""
+Route model operations to the correct database (when using more than one)
+see https://docs.djangoproject.com/en/2.1/topics/db/multi-db/
+"""
+
+class MemberDbRouter:
+    """
+    Send all operations to the default database except for the old memberdb stuff (which goes to the memberdb_old database)
+    """
+    def db_for_read(self, model, **hints):
+        if model._meta.app_label == 'import_members':
+            return 'memberdb_old'
+        return None
+
+    def db_for_write(self, model, **hints):
+        if model._meta.app_label == 'import_members':
+            return 'memberdb_old'
+        return None
+
+    def allow_relation(self, obj1, obj2, **hints):
+        # Return the default setting
+        return None
+
+    def allow_migrate(self, db, app_label, model_name=None, **hints):
+        """
+        Make sure we don't do any migrations to the old database, it would only break things.
+        """
+        if app_label == 'import_members':
+            return False
+        return None
\ No newline at end of file
diff --git a/gms/import_members/models.py b/gms/import_members/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e5a04e1e129bcb256d51f5d4939bb007fad744f
--- /dev/null
+++ b/gms/import_members/models.py
@@ -0,0 +1,31 @@
+from django.db import models
+
+import datetime
+                               
+MEMBERSHIP_TYPES = (                       
+    (1, 'O\' Day Special'),                                           
+    (2, 'Student'),
+    (3, 'Non Student'),                  
+)
+
+class OldMember (models.Model):
+    real_name       = models.CharField ('Real Name', max_length=200,)
+    username        = models.CharField ('Username', max_length=16, blank=True)
+    email_address   = models.CharField ('Email Address', max_length=200, blank=True)
+    membership_type = models.IntegerField ('Membership Type', choices=MEMBERSHIP_TYPES,)
+    guild_member    = models.BooleanField ('Guild Member', default=False, blank=True)
+    student_no      = models.CharField ('Student Number or ID Number', max_length=20, blank=True)
+    phone_number    = models.CharField ('Phone Number', max_length=14, blank=True)
+    date_of_birth   = models.DateField ('Date of Birth', null=True, blank=True)
+    signed_up       = models.DateField ('Signed up')
+
+    def __str__(self):
+        if len (self.username) > 0:
+            return "%s [%s]" % (self.real_name, self.username)
+        else:
+            return self.real_name
+
+    class Meta:
+        managed = False
+        db_table = 'memberdb_member'
+        verbose_name = 'Old member record'
\ No newline at end of file
diff --git a/gms/memberdb/register.py b/gms/memberdb/register.py
index add57372bac5d74bfffdb5349c8ea46ce178cf27..a62863264fcc392b4f4ad11b87b0867f2a6f12df 100644
--- a/gms/memberdb/register.py
+++ b/gms/memberdb/register.py
@@ -97,7 +97,15 @@ class RenewView(LoginRequiredMixin, MyUpdateView):
     model = Member
 
     def get_object(self):
-        obj = Member.objects.filter(username__exact=self.request.user.username).first()
+        u = self.request.user
+
+        obj = Member.objects.filter(username__exact=u.username).first()
+        if (obj is None):
+            # make a new Member object and prefill some data
+            obj = Member(username=u.username)
+            obj.first_name = u.first_name
+            obj.last_name = u.last_name
+            obj.email_address = u.email
         return obj
 
     def get_context_data(self, **kwargs):
@@ -107,17 +115,6 @@ class RenewView(LoginRequiredMixin, MyUpdateView):
         })
         return context
 
-    # get the initial data with which to pre-fill the form
-    def get_initial(self):
-        data = super().get_initial()
-        u = self.request.user
-        data.update({
-            'first_name': u.first_name,
-            'last_name': u.last_name,
-            'email_address': u.email,
-        })
-        return data
-
     def form_valid(self, form):
         m, ms = form.save()
         return HttpResponseRedirect(reverse("memberdb:index"))