diff --git a/README.md b/README.md
index f5660a894ffe13924442c6e42d60335850084327..1b64c6d4b88fbcfc7c93584b5475ebaf5b2aa118 100644
--- a/README.md
+++ b/README.md
@@ -50,13 +50,17 @@ Le site utilise une base de données SQL. Plusieurs technologies existent mais o
 
 Après avoir installé PostgreSQL, démarrez le serveur en ouvrant pgAdmin, l'interface graphique qui sera installée en même temps que Postgres.
 
+- Créez une nouvelle base de données :
+
+Dans le menu de gauche, dépliez `Servers (1)`, puis votre serveur (nommé `PostgreSQL XX` par défaut), puis faites un clic droit sur l'onglet `Databases` et créez une base de données nommée `oser_backend_db`.
+
 ### Installation du projet
 
-- (Recommandé) Créez un environnement virtuel (ici appelé `env`) puis activez-le :
+- (Recommandé) Créez un environnement virtuel (appelé ici oser-back) à l'aide de conda et activez-le :
 
 ```bash
-$ python -m venv env
-$ source env/bin/activate
+$ conda create -n oser-back
+$ conda activate oser-back
 ```
 
 - Installez les dépendances :
@@ -70,6 +74,7 @@ $ pip install -r requirements.txt
 ```bash
 $ python manage.py migrate
 ```
+(En cas d'erreur, les logs du serveur PostgreSQL sont disponibles dans : %PROGRAMFILES%\PostgreSQL\POSTGRESQL_VERSION_NUM\data\log)
 
 Il ne vous reste plus qu'à lancer le serveur de développement :
 
diff --git a/api/urls.py b/api/urls.py
index dbd3f62fe5ce8ba2ed67d64dca500e2b15060aee..46497be11fa1b6e898d2887dd91eaf1fe3c6933d 100644
--- a/api/urls.py
+++ b/api/urls.py
@@ -26,7 +26,7 @@ router.register('users', users_views.UserViewSet)
 
 # Profiles views
 router.register('tutors', profiles_views.TutorViewSet)
-router.register('students', profiles_views.StudentViewSet)
+router.register('students', profiles_views.StudentViewSet, base_name='student')
 
 # Register views
 router.register('registrations', register_views.RegistrationViewSet)
diff --git a/core/factory.py b/core/factory.py
index a812eedf66da680b44e704315bd4a2fc0f7810f6..7167327d48510efeb20e2ae1e70c981bee7fb623 100644
--- a/core/factory.py
+++ b/core/factory.py
@@ -5,7 +5,7 @@ import factory.django
 from . import models
 
 
-class DocumentFactory(factory.DjangoModelFactory):
+class DocumentFactory(factory.django.DjangoModelFactory):
     """Document object factory."""
 
     class Meta:  # noqa
@@ -15,7 +15,7 @@ class DocumentFactory(factory.DjangoModelFactory):
     content = factory.Faker('text', max_nb_chars=1000, locale='fr')
 
 
-class AddressFactory(factory.DjangoModelFactory):
+class AddressFactory(factory.django.DjangoModelFactory):
     """Address object factory."""
 
     class Meta:  # noqa
diff --git a/oser_backend/serializers.py b/oser_backend/serializers.py
index 576a486df57cd73a4b7479200552c27528ddfb8a..d1535112a9014e66d3ef565658b270c84ff9fe32 100644
--- a/oser_backend/serializers.py
+++ b/oser_backend/serializers.py
@@ -28,7 +28,7 @@ class PasswordResetSerializer(serializers.Serializer):
 
             ###### USE YOUR TEXT FILE ######
             'email_template_name': 'email-reset-template.txt',
-
+            'subject_template_name': 'subject-reset-template.txt',
             'request': request,
         }
         self.reset_form.save(**opts)
\ No newline at end of file
diff --git a/oser_backend/settings/common.py b/oser_backend/settings/common.py
index ca0a6074c8124e6ee6b3a9c04c8e964b97c107e5..9579af4b53b12213685b37613ac01aa7bdc42a30 100644
--- a/oser_backend/settings/common.py
+++ b/oser_backend/settings/common.py
@@ -5,10 +5,13 @@ Common settings suitable for all environmebts.
 """
 
 import os
+from dotenv import load_dotenv
 
 import dj_database_url
 import pymdownx.emoji
 
+load_dotenv()
+
 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
 dn = os.path.dirname
 BASE_DIR = dn(dn(dn(os.path.abspath(__file__))))
@@ -35,7 +38,7 @@ DJANGO_APPS = [
     'whitenoise.runserver_nostatic',
     'django.contrib.staticfiles',
     'django.forms',
-    'django.contrib.sites',
+    'django.contrib.sites'
 ]
 
 THIRD_PARTY_APPS = [
@@ -233,7 +236,7 @@ LOGGING = {
 # Connect custom PasswordResetSerializer to override default
 
 REST_AUTH_SERIALIZERS = {
-    'PASSWORD_RESET_SERIALIZER': 
+    'PASSWORD_RESET_SERIALIZER':
         'oser_backend.serializers.PasswordResetSerializer',
 }
 
@@ -243,7 +246,7 @@ DEFAULT_FROM_EMAIL = "admin@oser-cs.fr"
 EMAIL_BACKEND = 'sendgrid_backend.SendgridBackend'
 SENDGRID_API_KEY = os.getenv('SENDGRID_API_KEY')
 
-# Sendgrid configuration 
+# Sendgrid configuration
 
 EMAIL_HOST = 'smtp.sendgrid.net'
 EMAIL_HOST_USER = 'apikey'
diff --git a/oser_backend/settings/dev.py b/oser_backend/settings/dev.py
index 18aab0f6f479d72f69479446573d9a10e84a5cdd..524f70a2c3a53b2060e43e14e8703097b55df5fd 100644
--- a/oser_backend/settings/dev.py
+++ b/oser_backend/settings/dev.py
@@ -5,7 +5,7 @@ from .common import *
 from .common import BASE_DIR
 
 DEBUG = True
-ALLOWED_HOSTS = ['localhost']
+ALLOWED_HOSTS = ['localhost','127.0.0.1']
 
 # Static files (CSS, JavaScript, Images) and media files (user-uploaded)
 
@@ -25,4 +25,4 @@ DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
 # Mails config
 
 # However emails won't be delivered by SendGrid (use dev_sendgrid settings)
-MAILS_ENABLED = True
+MAILS_ENABLED = False
diff --git a/oser_backend/settings/dev_sendgrid.py b/oser_backend/settings/dev_sendgrid.py
index 868345b995a13c8bd6d99d56dc48cee8a9ea87b9..468b0aa3277bd7fb2f300f556e6781920fb0f145 100644
--- a/oser_backend/settings/dev_sendgrid.py
+++ b/oser_backend/settings/dev_sendgrid.py
@@ -5,3 +5,4 @@ from .dev import *
 # Allow to send emails with SendGrid while in DEBUG mode.
 # See: https://github.com/sklarsa/django-sendgrid-v5#other-settings
 SENDGRID_SANDBOX_MODE_IN_DEBUG = False
+
diff --git a/profiles/MultiSelectFieldListFilter.py b/profiles/MultiSelectFieldListFilter.py
new file mode 100644
index 0000000000000000000000000000000000000000..53f2eefdb0d64f73e21483b9e3fe02175e2267d9
--- /dev/null
+++ b/profiles/MultiSelectFieldListFilter.py
@@ -0,0 +1,65 @@
+from django.contrib import admin
+from django.contrib.admin.utils import reverse_field_path
+from django.utils.translation import gettext_lazy as _
+
+class MultiSelectFieldListFilter(admin.FieldListFilter):
+    def __init__(self, field, request, params, model, model_admin, field_path):
+        self.lookup_kwarg = field_path + '__in'
+        self.lookup_kwarg_isnull = field_path + '__isnull'
+
+        super().__init__(field, request, params, model, model_admin, field_path)
+
+        self.lookup_val = self.used_parameters.get(self.lookup_kwarg, [])
+        if len(self.lookup_val) == 1 and self.lookup_val[0] == '':
+            self.lookup_val = []
+        self.lookup_val_isnull = self.used_parameters.get(self.lookup_kwarg_isnull)
+
+        self.empty_value_display = model_admin.get_empty_value_display()
+        parent_model, reverse_path = reverse_field_path(model, field_path)
+        # Obey parent ModelAdmin queryset when deciding which options to show
+        if model == parent_model:
+            queryset = model_admin.get_queryset(request)
+        else:
+            queryset = parent_model._default_manager.all()
+        self.lookup_choices = queryset.distinct().order_by(field.name).values_list(field.name, flat=True)
+
+    def expected_parameters(self):
+        return [self.lookup_kwarg, self.lookup_kwarg_isnull]
+
+    def choices(self, changelist):
+        yield {
+            'selected': not self.lookup_val and self.lookup_val_isnull is None,
+            'query_string': changelist.get_query_string(remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]),
+            'display': _('All'),
+        }
+        include_none = False
+        for val in self.lookup_choices:
+            if val is None:
+                include_none = True
+                continue
+            val = str(val)
+
+            if val in self.lookup_val:
+                values = [v for v in self.lookup_val if v != val]
+            else:
+                values = self.lookup_val + [ val ]
+
+            if values:
+                yield {
+                    'selected': val in self.lookup_val,
+                    'query_string': changelist.get_query_string({self.lookup_kwarg: ','.join(values)}, [self.lookup_kwarg_isnull]),
+                    'display': val,
+                }
+            else:
+                yield {
+                    'selected': val in self.lookup_val,
+                    'query_string': changelist.get_query_string(remove=[self.lookup_kwarg]),
+                    'display': val,
+                }
+
+        if include_none:
+            yield {
+                'selected': bool(self.lookup_val_isnull),
+                'query_string': changelist.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]),
+                'display': self.empty_value_display,
+            }
\ No newline at end of file
diff --git a/profiles/admin.py b/profiles/admin.py
index 4f00aa12ef96c41e9b9b99522ef931d97c651dec..9109a6fd5889f333c659c9a89008376f3cf8f758 100644
--- a/profiles/admin.py
+++ b/profiles/admin.py
@@ -2,6 +2,8 @@
 
 from django.contrib import admin
 from .models import Student, Tutor
+from .MultiSelectFieldListFilter import MultiSelectFieldListFilter
+import codecs
 
 import csv
 from django.http import HttpResponse
@@ -13,7 +15,8 @@ class ExportCsvMixin:
 
         response = HttpResponse(content_type='text/csv')
         response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
-        writer = csv.writer(response)
+        response.write(codecs.BOM_UTF8) #force response to be UTF-8
+        writer = csv.writer(response, delimiter=';')
 
         writer.writerow(field_names)
         for obj in queryset:
@@ -21,7 +24,7 @@ class ExportCsvMixin:
 
         return response
 
-    export_as_csv.short_description = "Export Selected"
+    export_as_csv.short_description = "Exporter sélection (en .csv)"
 
 
 class ProfileAdminMixin:
@@ -40,10 +43,11 @@ class TutorAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
         model = Tutor
     actions = ["export_as_csv"]
 
+
 @admin.register(Student)
 class StudentAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
     """Student admin panel."""
-
+    list_filter = (('school',MultiSelectFieldListFilter), 'year')
     class Meta:  # noqa
         model = Student
     actions = ["export_as_csv"]
\ No newline at end of file
diff --git a/profiles/factory.py b/profiles/factory.py
index 886b5dde680d2945e4fbc1b30455990a390fa491..6b8b4ff6b212ccb5c6c58d0c47b62cf855a09b0c 100644
--- a/profiles/factory.py
+++ b/profiles/factory.py
@@ -12,7 +12,7 @@ from users.factory import UserFactory
 from . import models
 
 
-class StudentFactory(factory.DjangoModelFactory):
+class StudentFactory(factory.django.DjangoModelFactory):
     """Student object factory."""
 
     class Meta:  # noqa
@@ -24,7 +24,7 @@ class StudentFactory(factory.DjangoModelFactory):
 _this_year = datetime.today().year
 
 
-class TutorFactory(factory.DjangoModelFactory):
+class TutorFactory(factory.django.DjangoModelFactory):
     """Tutor object factory."""
 
     class Meta:  # noqa
diff --git a/profiles/migrations/0003_auto_20200914_0057.py b/profiles/migrations/0003_auto_20200914_0057.py
new file mode 100644
index 0000000000000000000000000000000000000000..ebe33bdb9876e88f5967032f96c1bf3adc9f4bbb
--- /dev/null
+++ b/profiles/migrations/0003_auto_20200914_0057.py
@@ -0,0 +1,88 @@
+# Generated by Django 2.2 on 2020-09-13 22:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0002_auto_20180911_1938'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='student',
+            name='addressNumber',
+            field=models.IntegerField(blank=True, null=True, verbose_name='numéro de rue'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='city',
+            field=models.CharField(blank=True, max_length=50, null=True, verbose_name='nom de ville'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='dependantsNumber',
+            field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numero d'urgence"),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='fatherActivity',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='metier du pere'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='gender',
+            field=models.CharField(blank=True, max_length=20, null=True, verbose_name='genre'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='grade',
+            field=models.CharField(blank=True, max_length=20, null=True, verbose_name='nom du niveau de la classe'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='motherActivity',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='metier de la mere'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='parentsEmail',
+            field=models.EmailField(blank=True, max_length=20, null=True, verbose_name='adresse mail parentale'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='parentsPhone',
+            field=models.CharField(blank=True, max_length=12, null=True, verbose_name='numéro de téléphone parental'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='parentsStatus',
+            field=models.CharField(blank=True, max_length=30, null=True, verbose_name='statut des parents'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='personnalPhone',
+            field=models.CharField(blank=True, max_length=12, null=True, verbose_name='numéro de téléphone personnel'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='scholarship',
+            field=models.BooleanField(blank=True, null=True, verbose_name='boursier'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='school',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'ecole"),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='street',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='nom de rue'),
+        ),
+        migrations.AlterField(
+            model_name='tutor',
+            name='promotion',
+            field=models.IntegerField(choices=[(2023, '2023'), (2022, '2022'), (2021, '2021'), (2020, '2020'), (2019, '2019')], default=2023),
+        ),
+    ]
diff --git a/profiles/migrations/0004_auto_20200915_1827.py b/profiles/migrations/0004_auto_20200915_1827.py
new file mode 100644
index 0000000000000000000000000000000000000000..d94b486a824cbe4d55b98228c8065bb28520bf80
--- /dev/null
+++ b/profiles/migrations/0004_auto_20200915_1827.py
@@ -0,0 +1,43 @@
+# Generated by Django 2.2 on 2020-09-15 16:27
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0003_auto_20200914_0057'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='student',
+            name='dependantsNumber',
+            field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numéro d'urgence"),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='fatherActivity',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier du père'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='grade',
+            field=models.CharField(blank=True, max_length=20, null=True, verbose_name='niveau de la classe'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='motherActivity',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier de la mère'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='scholarship',
+            field=models.NullBooleanField(verbose_name='boursier'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='school',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'école"),
+        ),
+    ]
diff --git a/profiles/migrations/0004_auto_20200918_1320.py b/profiles/migrations/0004_auto_20200918_1320.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b1e26b5ff27618b90b05d48a5b4959b5c196d05
--- /dev/null
+++ b/profiles/migrations/0004_auto_20200918_1320.py
@@ -0,0 +1,43 @@
+# Generated by Django 2.2 on 2020-09-18 11:20
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0003_auto_20200914_0057'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='student',
+            name='dependantsNumber',
+            field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numéro d'urgence"),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='fatherActivity',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier du père'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='grade',
+            field=models.CharField(blank=True, max_length=20, null=True, verbose_name='niveau de la classe'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='motherActivity',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier de la mère'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='scholarship',
+            field=models.NullBooleanField(verbose_name='boursier'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='school',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'école"),
+        ),
+    ]
diff --git a/profiles/migrations/0005_auto_20200918_1805.py b/profiles/migrations/0005_auto_20200918_1805.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e5756b35f30031a1461c9e722ade5bd3c0d56b9
--- /dev/null
+++ b/profiles/migrations/0005_auto_20200918_1805.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2 on 2020-09-18 16:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0004_auto_20200918_1320'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='student',
+            name='scholarship',
+            field=models.CharField(blank=True, max_length=10, null=True, verbose_name='boursier'),
+        ),
+    ]
diff --git a/profiles/migrations/0006_auto_20200918_1818.py b/profiles/migrations/0006_auto_20200918_1818.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1d92c84cb5637c04014142e8f0eb6a0ce7047ee
--- /dev/null
+++ b/profiles/migrations/0006_auto_20200918_1818.py
@@ -0,0 +1,28 @@
+# Generated by Django 2.2 on 2020-09-18 16:18
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0005_auto_20200918_1805'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='student',
+            name='nationality',
+            field=models.CharField(blank=True, max_length=30, null=True, verbose_name='nationalité'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='specialTeaching',
+            field=models.CharField(blank=True, max_length=30, null=True, verbose_name='enseignement de spécialité'),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='zipCode',
+            field=models.CharField(blank=True, max_length=10, null=True, verbose_name='code postal'),
+        ),
+    ]
diff --git a/profiles/migrations/0007_merge_20200918_1824.py b/profiles/migrations/0007_merge_20200918_1824.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff45a3495fcaffea7b785342967fdf43431f60e6
--- /dev/null
+++ b/profiles/migrations/0007_merge_20200918_1824.py
@@ -0,0 +1,14 @@
+# Generated by Django 2.2 on 2020-09-18 16:24
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0006_auto_20200918_1818'),
+        ('profiles', '0004_auto_20200915_1827'),
+    ]
+
+    operations = [
+    ]
diff --git a/profiles/migrations/0008_auto_20200918_1913.py b/profiles/migrations/0008_auto_20200918_1913.py
new file mode 100644
index 0000000000000000000000000000000000000000..cdf1810b92ba16c81f69a0c1d03524b70671e8a3
--- /dev/null
+++ b/profiles/migrations/0008_auto_20200918_1913.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2 on 2020-09-18 17:13
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0007_merge_20200918_1824'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='student',
+            name='scholarship',
+            field=models.CharField(blank=True, max_length=10, null=True, verbose_name='boursier'),
+        ),
+    ]
diff --git a/profiles/migrations/0009_auto_20200923_1329.py b/profiles/migrations/0009_auto_20200923_1329.py
new file mode 100644
index 0000000000000000000000000000000000000000..5dc6c13dc8941b3a97754791132d8f584da47eb8
--- /dev/null
+++ b/profiles/migrations/0009_auto_20200923_1329.py
@@ -0,0 +1,43 @@
+# Generated by Django 2.2 on 2020-09-23 11:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0008_auto_20200918_1913'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='student',
+            name='dependantsNumber',
+            field=models.IntegerField(blank=True, null=True, verbose_name='nombre de personnes à charge'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='nationality',
+            field=models.CharField(blank=True, max_length=50, null=True, verbose_name='nationalité'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='parentsEmail',
+            field=models.EmailField(blank=True, max_length=70, null=True, verbose_name='adresse mail parentale'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='parentsStatus',
+            field=models.CharField(blank=True, max_length=70, null=True, verbose_name='statut des parents'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='scholarship',
+            field=models.CharField(blank=True, max_length=50, null=True, verbose_name='boursier'),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='specialTeaching',
+            field=models.CharField(blank=True, max_length=50, null=True, verbose_name='enseignement de spécialité'),
+        ),
+    ]
diff --git a/profiles/migrations/0010_auto_20200923_1444.py b/profiles/migrations/0010_auto_20200923_1444.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd5da54118b9f0ff8ba3e85af509d8cf7ac87a14
--- /dev/null
+++ b/profiles/migrations/0010_auto_20200923_1444.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2 on 2020-09-23 12:44
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0009_auto_20200923_1329'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='student',
+            old_name='personnalPhone',
+            new_name='personalPhone',
+        ),
+    ]
diff --git a/profiles/migrations/0011_student_classtype.py b/profiles/migrations/0011_student_classtype.py
new file mode 100644
index 0000000000000000000000000000000000000000..04821189e139d63ba4fcb74c6986fb7b0e67b3af
--- /dev/null
+++ b/profiles/migrations/0011_student_classtype.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2 on 2020-09-24 16:56
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0010_auto_20200923_1444'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='student',
+            name='classType',
+            field=models.CharField(blank=True, max_length=50, null=True, verbose_name='général/techno'),
+        ),
+    ]
diff --git a/profiles/migrations/0012_student_year.py b/profiles/migrations/0012_student_year.py
new file mode 100644
index 0000000000000000000000000000000000000000..359b6cbd51b920471e2203e942a3805120f98cc2
--- /dev/null
+++ b/profiles/migrations/0012_student_year.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2 on 2020-09-25 12:14
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('profiles', '0011_student_classtype'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='student',
+            name='year',
+            field=models.CharField(blank=True, max_length=10, null=True, verbose_name='année'),
+        ),
+    ]
diff --git a/profiles/models.py b/profiles/models.py
index 28061fa97817f7fd8dd4c0a58ad90d3e8da141bd..6f9dd0dafe33d456124e641e49b78175b2b085ed 100644
--- a/profiles/models.py
+++ b/profiles/models.py
@@ -4,6 +4,8 @@ from django.db import models
 from django.shortcuts import reverse
 from dry_rest_permissions.generics import authenticated_users
 from .utils import get_promotion_range
+from datetime import datetime
+from .notifications import SendDocs
 
 
 class ProfileMixin:
@@ -52,6 +54,147 @@ class Student(ProfileMixin, models.Model):
         related_name='student',
     )
 
+    classType = models.CharField(max_length=50,
+        null=True,
+        blank=True,
+        verbose_name="général/techno",
+    )
+
+    nationality = models.CharField(max_length=50,
+        null=True,
+        blank=True,
+        verbose_name="nationalité",
+    )
+
+    specialTeaching = models.CharField(max_length=50,
+        null=True,
+        blank=True,
+        verbose_name="enseignement de spécialité",
+    )
+
+    zipCode = models.CharField(max_length=10,
+        null=True,
+        blank=True,
+        verbose_name="code postal",
+    )
+
+
+    gender = models.CharField(max_length=20,
+        null=True,
+        blank=True,
+        verbose_name="genre",
+    )
+
+    addressNumber = models.IntegerField(
+        null=True,
+        blank=True,
+        verbose_name="numéro de rue"
+    )
+
+    street = models.CharField(max_length=70,
+        null=True,
+        blank=True,
+        verbose_name="nom de rue"
+    )
+
+    city = models.CharField(max_length=50,
+        null=True,
+        blank=True,
+        verbose_name="nom de ville"
+    )
+
+    personalPhone = models.CharField(max_length=12,
+        null=True,
+        blank=True,
+        verbose_name="numéro de téléphone personnel"
+    )
+
+    parentsPhone = models.CharField(max_length=12,
+        null=True,
+        blank=True,
+        verbose_name="numéro de téléphone parental"
+    )
+
+    parentsEmail = models.EmailField(max_length=70,
+        null=True,
+        blank=True,
+        verbose_name="adresse mail parentale"
+    )
+
+
+    school = models.CharField(max_length=70,
+        null=True,
+        blank=True,
+        verbose_name="établissement"
+    )
+
+
+    grade = models.CharField(max_length=20,
+        null=True,
+        blank=True,
+        verbose_name="niveau de la classe"
+    )
+
+
+    scholarship = models.CharField(max_length=50,
+        null=True,
+        blank=True,
+        verbose_name="boursier"
+    )
+
+
+    fatherActivity = models.CharField(max_length=70,
+        null=True,
+        blank=True,
+        verbose_name="métier du père"
+    )
+
+
+    motherActivity = models.CharField(max_length=70,
+        null=True,
+        blank=True,
+        verbose_name="métier de la mère"
+    )
+
+
+    parentsStatus = models.CharField(max_length=70,
+        null=True,
+        blank=True,
+        verbose_name="statut des parents"
+    )
+
+
+    dependantsNumber = models.IntegerField(
+        null=True,
+        blank=True,
+        verbose_name="nombre de personnes à charge"
+    )
+
+    year = models.CharField(max_length=10,
+        null=True,
+        blank=True,
+        verbose_name="année"
+    )
+
+    @staticmethod
+    def has_write_permission(request):
+        return True
+
+    def has_object_write_permission(self, request):
+        return request.user == self.user
+
+    def save(self, *args, **kwargs):
+        """Updates the year field based on the last modified date"""
+        date_now = datetime.now()
+        if date_now.month>=9:
+            self.year = f"{date_now.year}/{date_now.year+1}"
+        else:
+            self.year = f"{date_now.year-1}/{date_now.year}"
+
+        SendDocs(user=self.user).send() # send email with link to registration docs
+
+        return super(Student,self).save(*args, **kwargs)
+
     class Meta:  # noqa
         verbose_name = 'lycéen'
 
diff --git a/profiles/notifications.py b/profiles/notifications.py
new file mode 100644
index 0000000000000000000000000000000000000000..bdd010bc663b378239b51d14bb18ddcb951685dd
--- /dev/null
+++ b/profiles/notifications.py
@@ -0,0 +1,11 @@
+from mails import Notification
+
+class SendDocs(Notification):
+    """Sends a link to the google docs containing the registration documents"""
+    subject = "Dossier d'inscription OSER"
+
+    template_name = "profiles/registration_docs.md"
+    args = ('user',)
+    def get_recipients(self):
+        return [self.user.email]
+
diff --git a/profiles/serializers.py b/profiles/serializers.py
index 31b20310d293647aacde450dca91509f8af66088..778dc21ff9563ca1a6e9b848915ae409146112ab 100644
--- a/profiles/serializers.py
+++ b/profiles/serializers.py
@@ -31,11 +31,11 @@ class StudentSerializer(serializers.HyperlinkedModelSerializer):
         read_only=True)
     registration = StudentRegistrationSerializer()
 
+
     class Meta:  # noqa
         model = Student
         fields = (
-            'user_id', 'user', 'registration', 'visits', 'url',
-        )
+            'user_id', 'user', 'url', 'registration', 'visits', 'gender', 'addressNumber', 'street', 'city', 'personalPhone', 'parentsPhone', 'parentsEmail', 'school', 'grade', 'scholarship', 'fatherActivity', 'motherActivity', 'parentsStatus', 'dependantsNumber', 'specialTeaching', 'nationality', 'zipCode', 'classType')
         extra_kwargs = {
             'url': {'view_name': 'api:student-detail'},
         }
diff --git a/profiles/templates/profiles/registration_docs.md b/profiles/templates/profiles/registration_docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..bf90ad938b2f09564b9ca8ac771eeab1d01bd095
--- /dev/null
+++ b/profiles/templates/profiles/registration_docs.md
@@ -0,0 +1,18 @@
+{% extends 'mails/notification.md' %}
+
+{% block greeting %}
+Bonjour,
+{% endblock %}
+
+{% block body %}
+Si tu reçois ce mail c’est que tu as fait un compte sur le site d’OSER et que tu as correctement rempli tes données personnelles. Félicitations ! ✅
+
+Avant de te laisser tranquille et que tu aies accès aux inscriptions pour les sorties et les projets, il te reste une dernière tâche : remplir le dossier d’inscription. Tu peux le trouver à ce lien : [https://drive.google.com/drive/folders/1TSGPRP2dAu07nkucpioWYGToccSU2vLD?usp=sharing](https://drive.google.com/drive/folders/1TSGPRP2dAu07nkucpioWYGToccSU2vLD?usp=sharing) .
+Tu peux télécharger le document et l’imprimer. Si tu n’as pas d’imprimante tu peux demander un dossier papier à un tuteur de ta séance. Il faut rendre ce dossier sous format papier rempli aux tuteurs de ta séance. Dès que l’on recevra ton dossier, on validera ton compte !
+{% endblock %}
+
+{% block signature %}
+On espère passer une super année avec toi,
+
+L’équipe OSER
+{% endblock %}
\ No newline at end of file
diff --git a/profiles/views.py b/profiles/views.py
index 0c157ef80761cfde6b830d6820eae66d48ab365b..b81ec2cdb13554e7f45e37f7b4736f1a9a0c5d85 100644
--- a/profiles/views.py
+++ b/profiles/views.py
@@ -5,6 +5,7 @@ from dry_rest_permissions.generics import DRYPermissions
 from rest_framework import viewsets
 from rest_framework.decorators import action
 from rest_framework.response import Response
+from django_filters.rest_framework import DjangoFilterBackend
 
 from visits.serializers import VisitSerializer
 
@@ -23,40 +24,21 @@ class TutorViewSet(viewsets.ReadOnlyModelViewSet):
     permission_classes = (DRYPermissions,)
 
 
-class StudentViewSet(viewsets.ReadOnlyModelViewSet):
-    """API endpoint that allows students to be viewed.
+class StudentViewSet(viewsets.ModelViewSet):
+    """API endpoint that allows students to be viewed, and profiles to be updated."""
 
-    list:
+    def get_serializer(self, *args, **kwargs):
+            kwargs['partial'] = True
+            return super(StudentViewSet, self).get_serializer(*args, **kwargs)
 
-    ### Example response
+    def get_queryset(self):
+        user = self.request.user
+        if user.is_staff:
+            return Student.objects.all()
+        else:
+            return Student.objects.filter(user_id = user.id)
 
-    List of results from `retrieve` (see the example response for `retrieve`).
 
-    retrieve:
-
-    ### Example response
-
-        {
-            "user_id": 4,
-            "user": {
-                "id": 4,
-                "email": "charles.dumont@example.net",
-                "profile_type": null,
-                "first_name": "",
-                "last_name": "",
-                "url": "http://localhost:8000/api/users/4/"
-            },
-            "registration": {
-                "id": 3,
-                "submitted": "2018-05-05T14:15:10.998206+02:00",
-                "validated": false
-            },
-            "visits": [],
-            "url": "http://localhost:8000/api/students/2/"
-        }
-    """
-
-    queryset = Student.objects.all()
     serializer_class = StudentSerializer
     permission_classes = (DRYPermissions,)
 
diff --git a/projects/factory.py b/projects/factory.py
index f826ab8d36261eb8a99acd51cdcfb2a725f1fcfb..8a539812d5abff29ff8657c0a36a9292e4789920 100644
--- a/projects/factory.py
+++ b/projects/factory.py
@@ -7,7 +7,7 @@ from users.factory import UserFactory
 from .models import Project, Edition, Participation, EditionForm
 
 
-class ProjectFactory(factory.DjangoModelFactory):
+class ProjectFactory(factory.django.DjangoModelFactory):
     """Project object factory."""
 
     class Meta:  # noqa
@@ -20,7 +20,7 @@ class ProjectFactory(factory.DjangoModelFactory):
     logo = factory.django.ImageField(color='green')
 
 
-class EditionFactory(factory.DjangoModelFactory):
+class EditionFactory(factory.django.DjangoModelFactory):
     """Edition object factory."""
 
     class Meta:  # noqa
@@ -37,7 +37,7 @@ class EditionFactory(factory.DjangoModelFactory):
         return project and project or ProjectFactory.create()
 
 
-class EditionFormFactory(factory.DjangoModelFactory):
+class EditionFormFactory(factory.django.DjangoModelFactory):
 
     class Meta:  # noqa
         model = EditionForm
@@ -45,7 +45,7 @@ class EditionFormFactory(factory.DjangoModelFactory):
     deadline = factory.Faker('future_date')
 
 
-class ParticipationFactory(factory.DjangoModelFactory):
+class ParticipationFactory(factory.django.DjangoModelFactory):
     """Participation object factory."""
 
     class Meta:  # noqa
diff --git a/register/factory.py b/register/factory.py
index 973d6e793e7b4abeef18708936f0b0eeef3b44fd..4fe95805b716f63146d51b8b76e76fb3c99a3fcd 100644
--- a/register/factory.py
+++ b/register/factory.py
@@ -8,7 +8,7 @@ from utils import printable_only
 from . import models
 
 
-class RegistrationFactory(factory.DjangoModelFactory):
+class RegistrationFactory(factory.django.DjangoModelFactory):
     """Registration object factory."""
 
     class Meta:  # noqa
diff --git a/requirements.txt b/requirements.txt
index 924e008527b9f4141c9146a3629b7428dd5767f6..85baa939feb52944045b1648211bc371283a6767 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -35,6 +35,9 @@ Pillow
 # Testing
 factory-boy
 
+# Miscellanneous
+python-dotenv==0.11
+
 # Deployment
 django-heroku  # Heroku integration
 whitenoise  # Static files serving
diff --git a/templates/email-reset-template.txt b/templates/email-reset-template.txt
index f222d5919241d2b60062eb0d6451bd619c690fb4..36aab0790716a61c71efe0a26d6e3cd5c837bc26 100644
--- a/templates/email-reset-template.txt
+++ b/templates/email-reset-template.txt
@@ -1,15 +1,15 @@
 {% load i18n %}{% autoescape off %}
-{% blocktrans %}Vous recevez ce courriel car vous avez demander à 
-réinitialiser le mot de passe de votre compte Oser.{% endblocktrans %}
+{% blocktrans %}Vous recevez ce courriel car vous avez demandé à 
+réinitialiser le mot de passe de votre compte OSER.{% endblocktrans %}
 
 {% trans "Please go to the following page and choose a new password:" %}
 {% block reset_link %}
-http://localhost:4200{% url 'password_reset_confirm' uidb64=uid token=token %}
+https://www.oser-cs.fr/{% url 'password_reset_confirm' uidb64=uid token=token %}
 {% endblock %}
 {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
 
 {% trans "Thanks for using our site!" %}
 
-{% blocktrans %}The Oser team{% endblocktrans %}
+{% blocktrans %}La Team OSER {% endblocktrans %}
 
 {% endautoescape %}
\ No newline at end of file
diff --git a/templates/subject-reset-template.txt b/templates/subject-reset-template.txt
new file mode 100644
index 0000000000000000000000000000000000000000..88499bb15e4f974b37963428650e3189f6675b72
--- /dev/null
+++ b/templates/subject-reset-template.txt
@@ -0,0 +1,3 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}Réinitialisation du mot de passe de votre compte OSER{% endblocktrans %}
+{% endautoescape %}
diff --git a/tests/test_profiles/test_student.py b/tests/test_profiles/test_student.py
index 0d9d65fc47e1619475c78325b8eb82f4af3641b2..f5b6541951f94976be5db30cde8b0fe1b8f7f402 100644
--- a/tests/test_profiles/test_student.py
+++ b/tests/test_profiles/test_student.py
@@ -3,7 +3,7 @@
 from profiles.factory import StudentFactory
 from profiles.models import Student
 from tests.utils import ModelTestCase
-from users.factory import UserFactory
+from users.factory import UserFactory, StaffUserFactory
 
 
 class StudentTestCase(ModelTestCase):
@@ -32,7 +32,8 @@ class StudentTestCase(ModelTestCase):
         self.assertEqual(self.obj, self.obj.user.student)
 
     def test_get_absolute_url(self):
-        self.client.force_login(UserFactory.create())
+        staff_user = StaffUserFactory.create()
+        self.client.force_login(staff_user)
         url = self.obj.get_absolute_url()
         response = self.client.get(url)
         self.assertEqual(200, response.status_code)
diff --git a/tests/test_profiles/test_student_api.py b/tests/test_profiles/test_student_api.py
index 204649b47eadba66ce7be8a9e17c09568244d664..d9caacb0d140e89e4d3724b35fcc0780647d2e74 100644
--- a/tests/test_profiles/test_student_api.py
+++ b/tests/test_profiles/test_student_api.py
@@ -19,7 +19,7 @@ class StudentEndpointsTest(HyperlinkedAPITestCase):
     def perform_retrieve(self, obj=None):
         if obj is None:
             obj = self.factory.create()
-        response = self.client.get('/api/students/{obj.pk}/'.format(obj=obj))
+        response = self.client.get('/api/students/')
         return response
 
     def test_list(self):
diff --git a/users/factory.py b/users/factory.py
index b197e55f088bb9b1901794aaad9f16272576836c..850d0c4b7a167af11e3dfc7d016e85a79218ea98 100644
--- a/users/factory.py
+++ b/users/factory.py
@@ -9,7 +9,7 @@ from utils import printable_only
 User = get_user_model()
 
 
-class UserFactory(factory.DjangoModelFactory):
+class UserFactory(factory.django.DjangoModelFactory):
     """User object factory."""
 
     class Meta:  # noqa
@@ -41,3 +41,7 @@ class UserFactory(factory.DjangoModelFactory):
         manager = cls._get_manager(model_class)
         # The default would use ``manager.create(*args, **kwargs)``
         return manager.create_user(*args, **kwargs)
+
+class StaffUserFactory(UserFactory):
+    """Staff user object factory."""
+    is_staff = True
\ No newline at end of file
diff --git a/visits/factory.py b/visits/factory.py
index 11817aa2c4692fcf5483f3029886a64cb5b9eae3..05fce07d0a39d1fcd1d5257c7a68390876e28f30 100644
--- a/visits/factory.py
+++ b/visits/factory.py
@@ -15,7 +15,7 @@ from . import models
 User = get_user_model()
 
 
-class PlaceFactory(factory.DjangoModelFactory):
+class PlaceFactory(factory.django.DjangoModelFactory):
     """Place object factory."""
 
     class Meta:  # noqa
@@ -28,7 +28,7 @@ class PlaceFactory(factory.DjangoModelFactory):
     description = factory.LazyAttribute(lambda o: '\n'.join(o._description))
 
 
-class VisitFactory(factory.DjangoModelFactory):
+class VisitFactory(factory.django.DjangoModelFactory):
     """Visit object factory."""
 
     deadline_random_range = (-5, -1)
@@ -81,7 +81,7 @@ class VisitWithClosedRegistrationsFactory(VisitFactory):
     deadline_random_range = (-10, -6)  # guaranteed to be before today
 
 
-class ParticipationFactory(factory.DjangoModelFactory):
+class ParticipationFactory(factory.django.DjangoModelFactory):
     """Visit participant object factory.
 
     Users and visit are picked from pre-existing objects,
diff --git a/visits/templates/visits/confirm_participation.md b/visits/templates/visits/confirm_participation.md
index 8772191966ebd1875daed20fe0decc878606a5b1..01466352b7109e7616e393a213df1f23ebb96964 100644
--- a/visits/templates/visits/confirm_participation.md
+++ b/visits/templates/visits/confirm_participation.md
@@ -10,7 +10,7 @@ Bonjour{% if participation.user.first_name %} {{ participation.user.first_name }
 {% if participation.accepted %}
 Bonne nouvelle : nous avons validé ta participation à la sortie. ✅
 
-En te rendant sur [l'espace sorties]({{ participation.visit.get_site_url }}), tu peux dès à présent:
+Avant la sortie, tu pourras, en te rendant sur [l'espace sorties]({{ participation.visit.get_site_url }}) :
 
 - Consulter les informations pratiques ;
 - Télécharger la fiche sortie ;