diff --git a/smash/web/api_urls.py b/smash/web/api_urls.py
index 8b880d23e238e756e9d85c8bbcceea6f53675520..56f9dc4f46cbac9ca9c7ab622abd000aadbe9aa5 100644
--- a/smash/web/api_urls.py
+++ b/smash/web/api_urls.py
@@ -21,6 +21,8 @@ from web.api_views import worker, location, subject, appointment_type, appointme
 urlpatterns = [
     # appointments
     url(r'^appointments/(?P<appointment_type>[A-z]+)$', appointment.appointments, name='web.api.appointments'),
+    url(r'^appointments:columns/(?P<appointment_list_type>[A-z]+)$', appointment.get_appointment_columns,
+        name='web.api.appointments.columns'),
 
     # appointment types
     url(r'^appointment_types$', appointment_type.appointment_types, name='web.api.appointment_types'),
diff --git a/smash/web/api_views/appointment.py b/smash/web/api_views/appointment.py
index ee9bee9746b9f3afc97f54a3b546c886883b414a..fe5a1828c450022f33ae67b95716fa5babea18eb 100644
--- a/smash/web/api_views/appointment.py
+++ b/smash/web/api_views/appointment.py
@@ -6,21 +6,45 @@ from django.http import JsonResponse
 from django.urls import reverse
 from django.utils import timezone
 
-from web.api_views.serialization_utils import serialize_datetime, location_to_str, flying_team_to_str
-from web.models import Appointment
-from web.views.appointment import APPOINTMENT_LIST_GENERIC, APPOINTMENT_LIST_UNFINISHED, APPOINTMENT_LIST_APPROACHING
-from web.views.notifications import get_filter_locations, \
-    get_today_midnight_date, \
-    get_unfinished_appointments
+from web.api_views.serialization_utils import serialize_datetime, location_to_str, flying_team_to_str, add_column, \
+    bool_to_yes_no
+from web.models import Appointment, Study, SubjectColumns, AppointmentColumns, AppointmentList
+from web.models.appointment_list import APPOINTMENT_LIST_GENERIC, APPOINTMENT_LIST_UNFINISHED, \
+    APPOINTMENT_LIST_APPROACHING
+from web.models.constants import GLOBAL_STUDY_ID
+from web.views.notifications import get_filter_locations, get_today_midnight_date, get_unfinished_appointments
 
 logger = logging.getLogger(__name__)
 
 
+@login_required
+def get_appointment_columns(request, appointment_list_type):
+    study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
+    appointment_lists = AppointmentList.objects.filter(study=study, type=appointment_list_type)
+    if len(appointment_lists) > 0:
+        appointment_list = appointment_lists[0]
+        subject_columns = appointment_list.visible_subject_columns
+        appointment_columns = appointment_list.visible_appointment_columns
+    else:
+        subject_columns = SubjectColumns()
+        appointment_columns = AppointmentColumns()
+
+    result = []
+    add_column(result, "First name", "first_name", subject_columns, "string_filter")
+    add_column(result, "Last name", "last_name", subject_columns, "string_filter")
+    add_column(result, "Info sent", "post_mail_sent", appointment_columns, "yes_no_filter")
+    add_column(result, "Date", "datetime_when", appointment_columns, None)
+    add_column(result, "Appointment types", "appointment_types", appointment_columns, "appointment_type_filter",
+               sortable=False)
+    add_column(result, "Edit", "edit", None, None, sortable=False)
+
+    return JsonResponse({"columns": result})
+
+
 @login_required
 def get_appointments(request, appointment_type, min_date, max_date):
     if appointment_type == APPOINTMENT_LIST_GENERIC:
-        result = Appointment.objects.filter(location__in=get_filter_locations(request.user),
-                                            )
+        result = Appointment.objects.filter(location__in=get_filter_locations(request.user))
     elif appointment_type == APPOINTMENT_LIST_UNFINISHED:
         result = get_unfinished_appointments(request.user)
     elif appointment_type == APPOINTMENT_LIST_APPROACHING:
@@ -42,6 +66,60 @@ def get_appointments(request, appointment_type, min_date, max_date):
     return result.order_by("datetime_when")
 
 
+def get_appointments_order(appointments_to_be_ordered, order_column, order_direction):
+    result = appointments_to_be_ordered
+    if order_direction == "asc":
+        order_direction = ""
+    else:
+        order_direction = "-"
+    if order_column == "first_name":
+        result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__subject__first_name')
+    elif order_column == "last_name":
+        result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__subject__last_name')
+    elif order_column == "default_location":
+        result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__default_location')
+    elif order_column == "flying_team":
+        result = appointments_to_be_ordered.order_by(order_direction + 'visit__subject__flying_team')
+    elif order_column == "post_mail_sent":
+        result = appointments_to_be_ordered.order_by(order_direction + 'post_mail_sent')
+    elif order_column == "datetime_when":
+        result = appointments_to_be_ordered.order_by(order_direction + 'datetime_when')
+    else:
+        logger.warn("Unknown sort column: " + str(order_column))
+    return result
+
+
+def filter_by_appointment(appointments_to_filter, appointment_type):
+    result = appointments_to_filter.filter(appointment_types=appointment_type)
+    return result
+
+
+def get_appointments_filtered(appointments_to_be_filtered, filters):
+    result = appointments_to_be_filtered
+    for row in filters:
+        column = row[0]
+        value = row[1]
+        if column == "first_name":
+            result = result.filter(visit__subject__subject__first_name__icontains=value)
+        elif column == "last_name":
+            result = result.filter(visit__subject__subject__last_name__icontains=value)
+        elif column == "default_location":
+            result = result.filter(visit__subject__default_location=value)
+        elif column == "flying_team":
+            result = result.filter(visit__subject__flying_team=value)
+        elif column == "appointment_types":
+            result = filter_by_appointment(result, value)
+        else:
+            message = "UNKNOWN filter: "
+            if column is None:
+                message += "[None]"
+            else:
+                message += str(column)
+            logger.warn(message)
+
+    return result
+
+
 @login_required
 def appointments(request, appointment_type):
     # id of the query from dataTable: https://datatables.net/manual/server-side
@@ -50,9 +128,21 @@ def appointments(request, appointment_type):
     start = int(request.GET.get("start", "0"))
     length = int(request.GET.get("length", "10"))
 
+    order = int(request.GET.get("order[0][column]", "0"))
+    order_dir = request.GET.get("order[0][dir]", "asc")
+    order_column = request.GET.get("columns[" + str(order) + "][data]", "last_name")
+
     min_date = request.GET.get("start_date", None)
     max_date = request.GET.get("end_date", None)
 
+    filters = []
+    column_id = 0
+    while request.GET.get("columns[" + str(column_id) + "][search][value]", "unknown") != "unknown":
+        val = request.GET.get("columns[" + str(column_id) + "][search][value]", "unknown")
+        if val != "":
+            filters.append([request.GET.get("columns[" + str(column_id) + "][data]"), val])
+        column_id += 1
+
     if min_date is not None:
         length = 1000000000
 
@@ -60,9 +150,11 @@ def appointments(request, appointment_type):
 
     count = all_appointments.count()
 
-    sliced_subjects = all_appointments[start:(start + length)]
+    sorted_appointments = get_appointments_order(all_appointments, order_column, order_dir)
+    filtered_appointments = get_appointments_filtered(sorted_appointments, filters)
+    sliced_appointments = filtered_appointments[start:(start + length)]
 
-    result_appointments = sliced_subjects
+    result_appointments = sliced_appointments
 
     count_filtered = all_appointments.count()
 
@@ -80,23 +172,27 @@ def appointments(request, appointment_type):
 
 def serialize_appointment(appointment):
     subject_string = ""
-    nd_number = screening_number = phone_numbers = appointment_types = None
+    first_name = ""
+    last_name = ""
+    nd_number = screening_number = phone_numbers = appointment_type_names = None
     if appointment.visit is not None:
         title = "Visit " + str(appointment.visit.visit_number)
         study_subject = appointment.visit.subject
         subject_string = study_subject.subject.last_name + " " + study_subject.subject.first_name
+        first_name = study_subject.subject.first_name
+        last_name = study_subject.subject.last_name
         nd_number = study_subject.nd_number
         screening_number = study_subject.screening_number
         phone_numbers = ", ".join(filter(None,
                                          [study_subject.subject.phone_number, study_subject.subject.phone_number_2,
                                           study_subject.subject.phone_number_3]))
-        appointment_types = ", ".join(
-            [unicode(appointment_type) for appointment_type in appointment.appointment_types.all()])
+        appointment_type_names = ", ".join(
+            [unicode(appointment_type_codes) for appointment_type_codes in appointment.appointment_types.all()])
     else:
         title = appointment.comment
 
-    appointment_type = ", ".join([appointment_type.code for appointment_type in appointment.appointment_types.all()])
-    time = serialize_datetime(appointment.datetime_when)
+    appointment_type_codes = ", ".join(
+        [appointment_type_codes.code for appointment_type_codes in appointment.appointment_types.all()])
     until = serialize_datetime(appointment.datetime_until())
 
     location = location_to_str(appointment.location)
@@ -108,15 +204,19 @@ def serialize_appointment(appointment):
         "nd_number": nd_number,
         "screening_number": screening_number,
         "phone_number": phone_numbers,
-        "appointment_types": appointment_types,
-        "type": appointment_type,
-        "datetime_when": time,
+        "appointment_type_names": appointment_type_names,
         "datetime_until": until,
         "comment": appointment.comment,
         "color": appointment.color(),
         "id": appointment.id,
+
+        "first_name": first_name,
+        "last_name": last_name,
         "location": location,
         "flying_team": flying_team,
+        "post_mail_sent": bool_to_yes_no(appointment.post_mail_sent),
+        "datetime_when": serialize_datetime(appointment.datetime_when),
+        "appointment_types": appointment_type_codes,
         "url": reverse('web.views.appointment_edit', kwargs={'id': str(appointment.id)})
     }
     return result
diff --git a/smash/web/migrations/0088_appointmentcolumns_appointmentlist.py b/smash/web/migrations/0088_appointmentcolumns_appointmentlist.py
new file mode 100644
index 0000000000000000000000000000000000000000..3473fdc6d0f2a643a4bfe2f4e22c8c3e089bfe85
--- /dev/null
+++ b/smash/web/migrations/0088_appointmentcolumns_appointmentlist.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-12-07 13:07
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0087_approaching_visit_wihout_appointment_list'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='AppointmentColumns',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('flying_team', models.BooleanField(default=False, verbose_name=b'Flying team')),
+                ('worker_assigned', models.BooleanField(default=False, verbose_name=b'Worker conducting the assessment')),
+                ('appointment_types', models.BooleanField(default=True, verbose_name=b'Appointment types')),
+                ('room', models.BooleanField(default=False, verbose_name=b'Room')),
+                ('location', models.BooleanField(default=False, verbose_name=b'Location')),
+                ('comment', models.BooleanField(default=False, verbose_name=b'Comment')),
+                ('datetime_when', models.BooleanField(default=True, verbose_name=b'Comment')),
+                ('length', models.BooleanField(default=False, verbose_name=b'Appointment length')),
+                ('status', models.BooleanField(default=False, verbose_name=b'Status')),
+                ('post_mail_sent', models.BooleanField(default=False, verbose_name=b'Post mail sent')),
+            ],
+        ),
+        migrations.CreateModel(
+            name='AppointmentList',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('type', models.CharField(choices=[(b'GENERIC', b'Generic'), (b'UNFINISHED', b'Unfinished'), (b'APPROACHING', b'Approaching')], max_length=50, verbose_name=b'Type of list')),
+                ('study', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.Study')),
+                ('visible_appointment_columns', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.AppointmentColumns')),
+                ('visible_study_subject_columns', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.StudyColumns')),
+                ('visible_subject_columns', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.SubjectColumns')),
+                ('visible_visit_columns', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.VisitColumns')),
+            ],
+        ),
+    ]
diff --git a/smash/web/models/__init__.py b/smash/web/models/__init__.py
index 746b15bf599f4f08e2605b8274ddc97137b609d8..d9ee4dab7c6289bcac5c3daa75f84d463f9fde83 100644
--- a/smash/web/models/__init__.py
+++ b/smash/web/models/__init__.py
@@ -8,6 +8,7 @@ from flying_team import FlyingTeam
 from location import Location
 from appointment_type_link import AppointmentTypeLink
 from country import Country
+from appointment_columns import AppointmentColumns
 from subject_columns import SubjectColumns
 from study_columns import StudyColumns
 from visit_columns import VisitColumns
@@ -26,6 +27,7 @@ from subject import Subject
 from study_subject import StudySubject
 from study_subject_list import StudySubjectList
 from study_visit_list import StudyVisitList
+from appointment_list import AppointmentList
 from contact_attempt import ContactAttempt
 from mail_template import MailTemplate
 from missing_subject import MissingSubject
@@ -33,5 +35,6 @@ from inconsistent_subject import InconsistentSubject, InconsistentField
 
 __all__ = [Study, FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room,
            Subject, StudySubject, StudySubjectList, SubjectColumns, StudyNotificationParameters,
-           Visit, Worker, ContactAttempt, ConfigurationItem, MailTemplate, AppointmentTypeLink, MissingSubject,
-           InconsistentSubject, InconsistentField, Country, StudyColumns, VisitColumns, StudyVisitList]
+           AppointmentList, AppointmentColumns, Visit, Worker, ContactAttempt, ConfigurationItem, MailTemplate,
+           AppointmentTypeLink,
+           MissingSubject, InconsistentSubject, InconsistentField, Country, StudyColumns, VisitColumns, StudyVisitList]
diff --git a/smash/web/models/appointment_columns.py b/smash/web/models/appointment_columns.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a65c60b9347ed2612036e6516a33e48c0fc8c28
--- /dev/null
+++ b/smash/web/models/appointment_columns.py
@@ -0,0 +1,47 @@
+# coding=utf-8
+from django.db import models
+
+
+class AppointmentColumns(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    flying_team = models.BooleanField(default=False,
+                                      verbose_name='Flying team',
+                                      )
+
+    worker_assigned = models.BooleanField(default=False,
+                                          verbose_name='Worker conducting the assessment',
+                                          )
+
+    appointment_types = models.BooleanField(default=True,
+                                            verbose_name='Appointment types',
+                                            )
+
+    room = models.BooleanField(default=False,
+                               verbose_name='Room',
+                               )
+
+    location = models.BooleanField(default=False,
+                                   verbose_name='Location',
+                                   )
+
+    comment = models.BooleanField(default=False,
+                                  verbose_name='Comment',
+                                  )
+
+    datetime_when = models.BooleanField(default=True,
+                                        verbose_name='Comment',
+                                        )
+
+    length = models.BooleanField(default=False,
+                                 verbose_name='Appointment length',
+                                 )
+
+    status = models.BooleanField(default=False,
+                                 verbose_name='Status',
+                                 )
+
+    post_mail_sent = models.BooleanField(default=False,
+                                         verbose_name='Post mail sent',
+                                         )
diff --git a/smash/web/models/appointment_list.py b/smash/web/models/appointment_list.py
new file mode 100644
index 0000000000000000000000000000000000000000..e04142320afcd4dddbd82ab6b4cf1dbc9efcb61c
--- /dev/null
+++ b/smash/web/models/appointment_list.py
@@ -0,0 +1,52 @@
+# coding=utf-8
+from django.db import models
+
+from web.models import Study, SubjectColumns, VisitColumns, AppointmentColumns, StudyColumns
+
+APPOINTMENT_LIST_GENERIC = "GENERIC"
+APPOINTMENT_LIST_UNFINISHED = "UNFINISHED"
+APPOINTMENT_LIST_APPROACHING = "APPROACHING"
+
+APPOINTMENT_LIST_CHOICES = {
+    APPOINTMENT_LIST_GENERIC: 'Generic',
+    APPOINTMENT_LIST_UNFINISHED: 'Unfinished',
+    APPOINTMENT_LIST_APPROACHING: 'Approaching',
+}
+
+
+class AppointmentList(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    study = models.ForeignKey(
+        Study,
+        on_delete=models.CASCADE,
+        null=False,
+    )
+
+    visible_visit_columns = models.ForeignKey(
+        VisitColumns,
+        on_delete=models.CASCADE,
+        null=False,
+    )
+
+    visible_subject_columns = models.ForeignKey(
+        SubjectColumns,
+        on_delete=models.CASCADE,
+        null=False,
+    )
+    visible_study_subject_columns = models.ForeignKey(
+        StudyColumns,
+        on_delete=models.CASCADE,
+        null=False,
+    )
+    visible_appointment_columns = models.ForeignKey(
+        AppointmentColumns,
+        on_delete=models.CASCADE,
+        null=False,
+    )
+
+    type = models.CharField(max_length=50,
+                            choices=APPOINTMENT_LIST_CHOICES.items(),
+                            verbose_name='Type of list',
+                            )
diff --git a/smash/web/static/js/appointment.js b/smash/web/static/js/appointment.js
index 27c25a15abe1ae70652f65da1dd5775c6b161eba..86ad7cd8848bb9b1752d434a6c72cd799438e141 100644
--- a/smash/web/static/js/appointment.js
+++ b/smash/web/static/js/appointment.js
@@ -244,7 +244,7 @@ function get_calendar_events_function(source, allow_url_redirection, day_headers
                     const entry = doc.data[i];
                     var title = entry.subject;
                     if (title !== "") {
-                        title += " (" + entry.nd_number + "); type: " + entry.type;
+                        title += " (" + entry.nd_number + "); type: " + entry.appointment_types;
                     } else {
                         title = entry.title
                     }
@@ -259,7 +259,8 @@ function get_calendar_events_function(source, allow_url_redirection, day_headers
                         flying_team: entry.flying_team,
                         screening_number: entry.screening_number,
                         phone_number: entry.phone_number,
-                        appointment_types: entry.appointment_types
+                        appointment_types: entry.appointment_types,
+                        appointment_type_names: entry.appointment_type_names
                     };
                     if (allow_url_redirection) {
                         event["url"] = entry.url;
@@ -271,3 +272,7 @@ function get_calendar_events_function(source, allow_url_redirection, day_headers
         });
     }
 }
+
+function createAppointmentsTable(params) {
+    return createTable(params);
+}
diff --git a/smash/web/templates/appointments/index.html b/smash/web/templates/appointments/index.html
index 8b975928d7d641a20399fa98118d4ca3257c8881..0452729eb4b61a1b8c3d2942299ac2040b637240 100644
--- a/smash/web/templates/appointments/index.html
+++ b/smash/web/templates/appointments/index.html
@@ -133,8 +133,8 @@
                     if (event.nd_number) {
                         content += '<li>ND number: ' + event.nd_number + '</li>'
                     }
-                    if (event.appointment_types) {
-                        content += '<li>Appointment types: ' + event.appointment_types + '</li>'
+                    if (event.appointment_type_names) {
+                        content += '<li>Appointment types: ' + event.appointment_type_names + '</li>'
                     }
                     if (event.location) {
                         var location = event.location;
diff --git a/smash/web/templates/appointments/list.html b/smash/web/templates/appointments/list.html
index b20d99c7b0dfcf3dee0d1eb9609ae3902b84faf0..24de957c72f74339e13d3d31e08ca4acdd50ce42 100644
--- a/smash/web/templates/appointments/list.html
+++ b/smash/web/templates/appointments/list.html
@@ -19,25 +19,12 @@
 {% endblock breadcrumb %}
 
 {% block maincontent %}
-    <div class="row">
-        <div class="col-md-16">
-            <table id="table" class="table table-bordered table-striped">
-                <thead>
-                <tr>
-                    <th>Subject</th>
-                    <th>Visit</th>
-                    <th>Type</th>
-                    <th>Date</th>
-                    <th>Details</th>
-                    <th>Edit</th>
-                </tr>
-                </thead>
-                <tbody>
-                </tbody>
-                <tfoot style="display: table-header-group;"/>
-            </table>
-
-        </div>
+    <div class="box-body">
+        <table id="table" class="table table-bordered table-striped table-responsive">
+        </table>
+    </div>
+    <h3>Visible columns</h3>
+    <div id="visible-column-checkboxes" style="display:table; width:100%">
     </div>
 {% endblock maincontent %}
 
@@ -46,53 +33,32 @@
 
     <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script>
     <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script>
+    <script src="{% static 'js/appointment.js' %}"></script>
 
     <script>
-        $(function () {
-            var table = $('#table').DataTable({
-                serverSide: true,
-                processing: true,
-                ordering: false,
-                ajax: "{% url 'web.api.appointments' list_type %}",
-                columns: [
-                    {"data": "subject"},
-                    {"data": "title"},
-                    {"data": "type"},
-                    {"data": "datetime_when"},
-                    {"data": "comment"},
-                    {"data": null},
-                ],
-                columnDefs: [{
-                    "targets": 5,
-                    "data": "id",
-                    "defaultContent": '<a href="#" type="button" class="btn btn-block btn-default">Edit</a>'
-                },
-{#                    {#}
-{#                        render: function (data, type, row) {#}
-{#                            var date = new Date(data);#}
-{#                            var mm = date.getMonth() + 1; // getMonth() is zero-based#}
-{#                            var dd = date.getDate();#}
-{#                            var hour = date.getHours();#}
-{#                            var minute = date.getMinutes();#}
-{##}
-{#                            return [date.getFullYear(),#}
-{#                                    (mm > 9 ? '' : '0') + mm,#}
-{#                                    (dd > 9 ? '' : '0') + dd#}
-{#                                ].join('-') + " " + hour + ":" + minute;#}
-{#                        },#}
-{#                        targets: 3#}
-{#                    }#}
-                ]
-            });
+        function getSubjectEditUrl(id) {
+            return "{% url 'web.views.appointment_edit' 1234567 %}".replace(/1234567/, id);
+        }
 
-            $('#table tbody').on('click', 'a', function () {
-                var data = table.row($(this).parents('tr')).data();
-                var url = "{% url 'web.views.appointment_edit' 12345 %}".replace(/12345/, data.id.toString());
-                window.location.href = url;
-            });
+        var worker_locations = [];
+        {% for location in worker.locations.all %}
+            worker_locations.push({id: location.id, name: location.name});
+        {% endfor %}
 
-            $('#table_filter').css("display", "none");
+        $.get("{% url 'web.api.appointments.columns' list_type %}", function (data) {
+            createAppointmentsTable({
+                worker_locations: worker_locations,
+                appointment_types_url: "{% url 'web.api.appointment_types' %}",
+                subject_types_url: "{% url 'web.api.subject_types' %}",
+                locations_url: "{% url 'web.api.locations' %}",
+                subjects_url: "{% url 'web.api.appointments' list_type %}",
+                flying_teams_url: "{% url 'web.api.flying_teams' %}",
+                tableElement: document.getElementById("table"),
+                columns: getColumns(data.columns, getSubjectEditUrl),
+                checkboxesElement: document.getElementById("visible-column-checkboxes")
+            })
         });
+
     </script>
 
 {% endblock scripts %}
diff --git a/smash/web/views/appointment.py b/smash/web/views/appointment.py
index ff4afa90d3a537f54d1eb140df02a61de0faccda..6d64acd468487ffc1a569241661c309d5b12f5ae 100644
--- a/smash/web/views/appointment.py
+++ b/smash/web/views/appointment.py
@@ -6,15 +6,13 @@ from django.contrib import messages
 from django.core.exceptions import ValidationError
 from django.shortcuts import get_object_or_404, redirect
 
+from web.models.appointment_list import APPOINTMENT_LIST_APPROACHING, APPOINTMENT_LIST_GENERIC, \
+    APPOINTMENT_LIST_UNFINISHED
 from . import wrap_response
 from ..forms import AppointmentDetailForm, AppointmentAddForm, AppointmentEditForm, SubjectEditForm, \
     StudySubjectEditForm
 from ..models import Appointment, StudySubject, MailTemplate
 
-APPOINTMENT_LIST_GENERIC = "GENERIC"
-APPOINTMENT_LIST_UNFINISHED = "UNFINISHED"
-APPOINTMENT_LIST_APPROACHING = "APPROACHING"
-
 logger = logging.getLogger(__name__)