diff --git a/app/contributions/forms.py b/app/contributions/forms.py
index 04030fd0df0a2edf857fe3c1984975cd2b8c1933..b30c578e21e4b56992d418b4425003f591ca49e6 100644
--- a/app/contributions/forms.py
+++ b/app/contributions/forms.py
@@ -13,7 +13,7 @@ from wtforms.validators import InputRequired, Length
 from app.services import SERVICES
 
 
-class CreateContributionBaseForm(FlaskForm):
+class ContributionBaseForm(FlaskForm):
     title = StringField(
         'Title',
         validators=[InputRequired(), Length(max=64)]
@@ -48,7 +48,7 @@ class CreateContributionBaseForm(FlaskForm):
     submit = SubmitField()
 
 
-class CreateTesseractOCRPipelineModelForm(CreateContributionBaseForm):
+class CreateTesseractOCRPipelineModelForm(ContributionBaseForm):
     tesseract_model_file = FileField(
         'File',
         validators=[FileRequired()]
@@ -72,7 +72,7 @@ class CreateTesseractOCRPipelineModelForm(CreateContributionBaseForm):
         self.compatible_service_versions.default = ''
 
 
-class CreateSpaCyNLPPipelineModelForm(CreateContributionBaseForm):
+class CreateSpaCyNLPPipelineModelForm(ContributionBaseForm):
     spacy_model_file = FileField(
         'File',
         validators=[FileRequired()]
@@ -100,17 +100,8 @@ class CreateSpaCyNLPPipelineModelForm(CreateContributionBaseForm):
         self.compatible_service_versions.default = ''
 
 
-class EditContributionBaseForm(CreateContributionBaseForm):
-    def prefill(self, model_file):
-        ''' Pre-fill the form with data of an exististing corpus file '''
-        self.title.data = model_file.title
-        self.description.data = model_file.description
-        self.publisher.data = model_file.publisher
-        self.publishing_year.data = model_file.publishing_year
-        self.publisher_url.data = model_file.publisher_url
-        self.publishing_url.data = model_file.publishing_url
-        self.version.data = model_file.version
-        self.shared.data = model_file.shared
+class EditContributionBaseForm(ContributionBaseForm):
+    pass
 
 
 class EditTesseractOCRPipelineModelForm(EditContributionBaseForm):
@@ -122,7 +113,3 @@ class EditSpaCyNLPPipelineModelForm(EditContributionBaseForm):
         'Pipeline name',
         validators=[InputRequired(), Length(max=64)]
     )
-
-    def prefill(self, model_file):
-        super().prefill(model_file)
-        self.pipeline_name.data = model_file.pipeline_name
diff --git a/app/contributions/routes.py b/app/contributions/routes.py
index 79ed3fa84d38339adbe7c73ad508649d35c01fdc..650cfc87cf38ac944d270d8d33a623f368b13b59 100644
--- a/app/contributions/routes.py
+++ b/app/contributions/routes.py
@@ -1,4 +1,12 @@
-from flask import abort, current_app, flash, Markup, render_template, url_for
+from flask import (
+    abort,
+    current_app,
+    flash,
+    Markup,
+    redirect,
+    render_template,
+    url_for
+)
 from flask_login import login_required, current_user
 from threading import Thread
 from app import db
@@ -43,33 +51,17 @@ def tesseract_ocr_pipeline_models():
 @bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST'])
 def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
     tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id)
-    form = EditTesseractOCRPipelineModelForm(prefix='edit-tesseract-ocr-pipeline-model-form')
+    form = EditTesseractOCRPipelineModelForm(
+        obj=tesseract_ocr_pipeline_model,
+        prefix='edit-tesseract-ocr-pipeline-model-form'
+    )
     if form.validate_on_submit():
-        if tesseract_ocr_pipeline_model.title != form.title.data:
-            tesseract_ocr_pipeline_model.title = form.title.data
-        if tesseract_ocr_pipeline_model.description != form.description.data:
-            tesseract_ocr_pipeline_model.description = form.description.data
-        if tesseract_ocr_pipeline_model.publisher != form.publisher.data:
-            tesseract_ocr_pipeline_model.publisher = form.publisher.data
-        if tesseract_ocr_pipeline_model.publishing_year != form.publishing_year.data:
-            tesseract_ocr_pipeline_model.publishing_year = form.publishing_year.data
-        if tesseract_ocr_pipeline_model.publisher_url != form.publisher_url.data:
-            tesseract_ocr_pipeline_model.publisher_url = form.publisher_url.data
-        if tesseract_ocr_pipeline_model.publishing_url != form.publishing_url.data:
-            tesseract_ocr_pipeline_model.publishing_url = form.publishing_url.data
-        if tesseract_ocr_pipeline_model.version != form.version.data:
-            tesseract_ocr_pipeline_model.version = form.version.data
-        if tesseract_ocr_pipeline_model.shared != form.shared.data:
-            tesseract_ocr_pipeline_model.shared = form.shared.data
-        db.session.commit()
-        tesseract_ocr_pipeline_model_url = url_for(
-            '.tesseract_ocr_pipeline_model',
-            tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id
-        )
-        message = Markup(f'Tesseract OCR Pipeline model "<a href="{tesseract_ocr_pipeline_model_url}">{tesseract_ocr_pipeline_model.title}</a>" updated')
-        flash(message)
-        return {}, 201, {'Location': tesseract_ocr_pipeline_model_url}
-    form.prefill(tesseract_ocr_pipeline_model)
+        form.populate_obj(tesseract_ocr_pipeline_model)
+        if db.session.is_modified(tesseract_ocr_pipeline_model):
+            message = Markup(f'Tesseract OCR Pipeline model "<a href="{tesseract_ocr_pipeline_model.url}">{tesseract_ocr_pipeline_model.title}</a>" updated')
+            flash(message)
+            db.session.commit()
+        return redirect(url_for('.tesseract_ocr_pipeline_models'))
     return render_template(
         'contributions/tesseract_ocr_pipeline_model.html.j2',
         form=form,
@@ -146,36 +138,17 @@ def spacy_nlp_pipeline_models():
 @bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST'])
 def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id):
     spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
-    form = EditSpaCyNLPPipelineModelForm(prefix='edit-spacy-nlp-pipeline-model-form')
+    form = EditSpaCyNLPPipelineModelForm(
+        obj=spacy_nlp_pipeline_model,
+        prefix='edit-spacy-nlp-pipeline-model-form'
+    )
     if form.validate_on_submit():
-        if spacy_nlp_pipeline_model.title != form.title.data:
-            spacy_nlp_pipeline_model.title = form.title.data
-        if spacy_nlp_pipeline_model.description != form.description.data:
-            spacy_nlp_pipeline_model.description = form.description.data
-        if spacy_nlp_pipeline_model.pipeline_name != form.pipeline_name.data:
-            spacy_nlp_pipeline_model.pipeline_name = form.pipeline_name.data
-        if spacy_nlp_pipeline_model.publisher != form.publisher.data:
-            spacy_nlp_pipeline_model.publisher = form.publisher.data
-        if spacy_nlp_pipeline_model.publishing_year != form.publishing_year.data:
-            spacy_nlp_pipeline_model.publishing_year = form.publishing_year.data
-        if spacy_nlp_pipeline_model.publisher_url != form.publisher_url.data:
-            spacy_nlp_pipeline_model.publisher_url = form.publisher_url.data
-        if spacy_nlp_pipeline_model.publishing_url != form.publishing_url.data:
-            spacy_nlp_pipeline_model.publishing_url = form.publishing_url.data
-        if spacy_nlp_pipeline_model.version != form.version.data:
-            spacy_nlp_pipeline_model.version = form.version.data
-        if spacy_nlp_pipeline_model.shared != form.shared.data:
-            spacy_nlp_pipeline_model.shared = form.shared.data
-        current_app.logger.warning(db.session.dirty)
-        db.session.commit()
-        spacy_nlp_pipeline_model_url = url_for(
-            '.spacy_nlp_pipeline_model',
-            spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id
-        )
-        message = Markup(f'SpaCy NLP Pipeline model "<a href="{spacy_nlp_pipeline_model_url}">{spacy_nlp_pipeline_model.title}</a>" updated')
-        flash(message)
-        return {}, 201, {'Location': url_for('.contributions')}
-    form.prefill(spacy_nlp_pipeline_model)
+        form.populate_obj(spacy_nlp_pipeline_model)
+        if db.session.is_modified(spacy_nlp_pipeline_model):
+            message = Markup(f'SpaCy NLP Pipeline model "<a href="{spacy_nlp_pipeline_model.url}">{spacy_nlp_pipeline_model.title}</a>" updated')
+            flash(message)
+            db.session.commit()
+        return redirect(url_for('.spacy_nlp_pipeline_models'))
     return render_template(
         'contributions/spacy_nlp_pipeline_model.html.j2',
         form=form,
diff --git a/app/corpora/forms.py b/app/corpora/forms.py
index 73002edc9c2e2c3a67d9f003b6049ef2225b03c3..db46b0ad77131ffcdf1cac7cae5572a3cfa62699 100644
--- a/app/corpora/forms.py
+++ b/app/corpora/forms.py
@@ -47,20 +47,7 @@ class CreateCorpusFileForm(CorpusFileBaseForm):
 
 
 class EditCorpusFileForm(CorpusFileBaseForm):
-    def prefill(self, corpus_file):
-        ''' Pre-fill the form with data of an exististing corpus file '''
-        self.address.data = corpus_file.address
-        self.author.data = corpus_file.author
-        self.booktitle.data = corpus_file.booktitle
-        self.chapter.data = corpus_file.chapter
-        self.editor.data = corpus_file.editor
-        self.institution.data = corpus_file.institution
-        self.journal.data = corpus_file.journal
-        self.pages.data = corpus_file.pages
-        self.publisher.data = corpus_file.publisher
-        self.publishing_year.data = corpus_file.publishing_year
-        self.school.data = corpus_file.school
-        self.title.data = corpus_file.title
+    pass
 
 
 class ImportCorpusForm(FlaskForm):
diff --git a/app/corpora/routes.py b/app/corpora/routes.py
index 57c14e651c0303ceae8103cd18dc3fde1b221b54..8bf7b1fb3cffea97188975acb931d2f56c85a07e 100644
--- a/app/corpora/routes.py
+++ b/app/corpora/routes.py
@@ -176,52 +176,15 @@ def corpus_file(corpus_id, corpus_file_id):
         abort(404)
     if not (corpus_file.corpus.user == current_user or current_user.is_administrator()):
         abort(403)
-    form = EditCorpusFileForm(prefix='edit-corpus-file-form')
+    form = EditCorpusFileForm(obj=corpus_file, prefix='edit-corpus-file-form')
     if form.validate_on_submit():
-        has_changes = False
-        if corpus_file.address != form.address.data:
-            corpus_file.address = form.address.data
-            has_changes = True
-        if corpus_file.author != form.author.data:
-            corpus_file.author = form.author.data
-            has_changes = True
-        if corpus_file.booktitle != form.booktitle.data:
-            corpus_file.booktitle = form.booktitle.data
-            has_changes = True
-        if corpus_file.chapter != form.chapter.data:
-            corpus_file.chapter = form.chapter.data
-            has_changes = True
-        if corpus_file.editor != form.editor.data:
-            corpus_file.editor = form.editor.data
-            has_changes = True
-        if corpus_file.institution != form.institution.data:
-            corpus_file.institution = form.institution.data
-            has_changes = True
-        if corpus_file.journal != form.journal.data:
-            corpus_file.journal = form.journal.data
-            has_changes = True
-        if corpus_file.pages != form.pages.data:
-            corpus_file.pages = form.pages.data
-            has_changes = True
-        if corpus_file.publisher != form.publisher.data:
-            corpus_file.publisher = form.publisher.data
-            has_changes = True
-        if corpus_file.publishing_year != form.publishing_year.data:
-            corpus_file.publishing_year = form.publishing_year.data
-            has_changes = True
-        if corpus_file.school != form.school.data:
-            corpus_file.school = form.school.data
-            has_changes = True
-        if corpus_file.title != form.title.data:
-            corpus_file.title = form.title.data
-            has_changes = True
-        if has_changes:
+        form.populate_obj(corpus_file)
+        if db.session.is_modified(corpus_file):
             corpus_file.corpus.status = CorpusStatus.UNPREPARED
-        db.session.commit()
-        message = Markup(f'Corpus file "<a href="{corpus_file.url}">{corpus_file.filename}</a>" updated')
-        flash(message, category='corpus')
+            db.session.commit()
+            message = Markup(f'Corpus file "<a href="{corpus_file.url}">{corpus_file.filename}</a>" updated')
+            flash(message, category='corpus')
         return redirect(corpus_file.corpus.url)
-    form.prefill(corpus_file)
     return render_template(
         'corpora/corpus_file.html.j2',
         corpus=corpus_file.corpus,
diff --git a/app/models.py b/app/models.py
index 3bf7f8a71e6406b8c3ce85a383da08f8287899b6..16ff27254705ccb2ef5ba67584863965fa526485 100644
--- a/app/models.py
+++ b/app/models.py
@@ -552,6 +552,13 @@ class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model):
             str(self.id)
         )
 
+    @property
+    def url(self):
+        return url_for(
+            'contributions.tesseract_ocr_pipeline_model',
+            tesseract_ocr_pipeline_model_id=self.id
+        )
+
     @staticmethod
     def insert_defaults():
         nopaque_user = User.query.filter_by(username='nopaque').first()
@@ -660,6 +667,13 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
             str(self.id)
         )
 
+    @property
+    def url(self):
+        return url_for(
+            'contributions.spacy_nlp_pipeline_model',
+            spacy_nlp_pipeline_model_id=self.id
+        )
+
     @staticmethod
     def insert_defaults():
         nopaque_user = User.query.filter_by(username='nopaque').first()