diff --git a/ldvspec/lofardata/forms.py b/ldvspec/lofardata/forms.py
index c0a7944e6960540592b9c7c361b814ada3272109..d83159e41e57f7dfcbae14f16007da12813ff04c 100644
--- a/ldvspec/lofardata/forms.py
+++ b/ldvspec/lofardata/forms.py
@@ -2,7 +2,7 @@ from django.core.exceptions import ValidationError
 
 from .models import WorkSpecification, DataProductFilter, Group
 
-from django.forms import ModelForm, CharField
+from django.forms import ModelForm, CharField, ChoiceField, ModelChoiceField
 
 
 class WorkSpecificationForm(ModelForm):
@@ -10,6 +10,7 @@ class WorkSpecificationForm(ModelForm):
         super().__init__(*args, **kwargs)
         self.fields['predecessor_specification'].required = False
         self.fields['filters'].required = False
+        self.fields['group'].required = False
 
     def _extract_filters(self):
         filter_names = [filter_name[0] for filter_name in DataProductFilter.objects.all().values_list('field')]
diff --git a/ldvspec/lofardata/templates/lofardata/index.html b/ldvspec/lofardata/templates/lofardata/index.html
index 7f7dc9237bfca25a09e6faab9a067ef8334e7dbd..1e9895a21068cd7651afe5b57d94530f52e2a240 100644
--- a/ldvspec/lofardata/templates/lofardata/index.html
+++ b/ldvspec/lofardata/templates/lofardata/index.html
@@ -14,7 +14,6 @@
                href="{% url 'specification-create' %}">
                 <span class="icon icon--plus"></span></a>
             <a class="button button--secondary button--icon-button margin-left"
-               style="display: none"
                title="Create a new group"
                href="{% url 'group-create' %}">
                 <span class="icon icon--layer-plus"></span></a>
diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html b/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html
index bcb708c992d973507d9784b18aa4fe78006ce392..358908523f525f4c92f2b580a1833a496e368b04 100644
--- a/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html
+++ b/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html
@@ -24,10 +24,9 @@
                         <!-- Standard input fields -->
                         <div class="custom--div-margin">
                             <h3 class="text text--primary text--title">Selection</h3>
-                            <div class="flex-wrapper flex-wrapper--row" id="div_id_group" style="display: none">
+                            <div class="flex-wrapper flex-wrapper--row" id="div_id_group">
                                 <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
-                                    <label class="input__label"
-                                           for="id_group">{{ form.group.label }}</label>
+                                    <label class="input__label">{{ form.group.label }}</label>
                                     <a class="tooltip-dias tooltip-dias-right custom--tooltip"
                                        data-tooltip="{{ form.group.help_text }}">m</a>
                                 </div>
diff --git a/ldvspec/lofardata/tests/test_dataproduct.py b/ldvspec/lofardata/tests/test_dataproduct.py
index 55016df18bd3f9f1730f10d88ec9dd3cd28393df..1c7fb8a9a272a46f15eef099fc5b1a04d83c1649 100644
--- a/ldvspec/lofardata/tests/test_dataproduct.py
+++ b/ldvspec/lofardata/tests/test_dataproduct.py
@@ -1,9 +1,10 @@
-import django.test as dtest
 import rest_framework.test as rtest
 from django.contrib.auth.models import User
 import rest_framework.status as response_status
 from django.db import IntegrityError
 
+import django.test as dtest
+
 from lofardata.models import DataProduct
 
 test_object_value = dict(obs_id='12345', oid_source='SAS', dataproduct_source='lofar',
@@ -29,6 +30,7 @@ class TestDatabaseInteraction(dtest.TestCase):
             self.assertEqual(getattr(dp, field), test_values.get(field))
 
     def test_insert_with_helper_function(self):
+        test_object_value['surl'] = test_object_value['surl'] + 'rrr'
         test_values = dict(test_object_value)
 
         dp = DataProduct.insert_dataproduct(**test_values)
diff --git a/ldvspec/lofardata/tests/test_dataproductinfo.py b/ldvspec/lofardata/tests/test_dataproductinfo.py
index 270acd3cdd4eeee1c27f42cb0cf8e23ee97422a9..2fc618357688ac8149b445af10445bc68ccca956 100644
--- a/ldvspec/lofardata/tests/test_dataproductinfo.py
+++ b/ldvspec/lofardata/tests/test_dataproductinfo.py
@@ -1,14 +1,14 @@
-import unittest
-
 from lofardata.models import DataProduct
 from lofardata.view_helpers.dataproductinfo import retrieve_combined_information
 
+import django.test as dtest
+
 test_objects = [dict(obs_id='12345', oid_source='SAS', dataproduct_source='lofar',
                      dataproduct_type='observation',
                      project='LT10_10',
                      location='lta-head.lofar.psnc.pl',
                      activity='secret stuff',
-                     surl='srm://lta-head.lofar.psnc.pl:4884/subfolder/some_nice.tar',
+                     surl='srm://lta-head.lofar.psnc.pl:4884/subfolder/a_some_nice.tar',
                      filesize=40,
                      antenna_set='HBA Dual Inner',
                      instrument_filter='110-190 MHz',
@@ -114,7 +114,7 @@ test_objects = [dict(obs_id='12345', oid_source='SAS', dataproduct_source='lofar
                      dysco_compression=False)]
 
 
-class RetrieveDataProductInformation(unittest.TestCase):
+class RetrieveDataProductInformation(dtest.TestCase):
 
     def setUp(self):
         for test_object in test_objects:
diff --git a/ldvspec/lofardata/tests/test_group_creation.py b/ldvspec/lofardata/tests/test_group_creation.py
index 037db535934d080df9eb727943f651b99dd234b4..8b588e94790bc2bd56c00f80e4de233b3c8547c8 100644
--- a/ldvspec/lofardata/tests/test_group_creation.py
+++ b/ldvspec/lofardata/tests/test_group_creation.py
@@ -1,10 +1,74 @@
-import unittest
+import types
+from unittest import mock
 
-from lofardata.models import WorkSpecification, Group
+import django.test as dtest
 
-class WorkSpecificationCreation(unittest.TestCase):
-    def test_create_group_with_one_obs_id(self):
-        pass
+from django.contrib.auth.models import User
+from lofardata.models import WorkSpecification, Group, ATDBProcessingSite
+from lofardata.view_helpers.specification import create_work_specifications_for_group, \
+    create_work_specification_for_group
 
-    def test_create_group_with_multiple_obs_ids(self):
-        pass
+
+class WorkSpecificationCreationDatabaseInteraction(dtest.TestCase):
+    def setUp(self):
+        self.user, _ = User.objects.get_or_create()
+        self.site, _ = ATDBProcessingSite.objects.get_or_create(
+            name="marvel", url="http://marvel.com", access_token="dummy"
+        )
+        self.group, _ = Group.objects.get_or_create(name="x-men", processing_site=self.site, selected_workflow="claw",
+                                                    selected_workflow_tag="attack")
+
+        self.delay_return_value = types.SimpleNamespace(id='5')
+
+    @mock.patch('lofardata.tasks.define_work_specification.delay')
+    def test_create_group_with_one_obs_id(self, mock_delay):
+        mock_delay.return_value = self.delay_return_value
+        create_work_specification_for_group(self.group, self.user, "123")
+
+        work_specification = list(WorkSpecification.objects.filter(group=self.group.id))
+
+        self.assertEqual(len(work_specification), 1)
+
+        actual_inherited_group_values = [(x.processing_site, x.selected_workflow, x.selected_workflow_tag) for x in
+                                         work_specification if x.group is self.group]
+
+        for actual_inherited_group_value in actual_inherited_group_values:
+            self.assertTupleEqual(actual_inherited_group_value,
+                                  (self.site, self.group.selected_workflow, self.group.selected_workflow_tag))
+
+    @mock.patch('lofardata.tasks.define_work_specification.delay')
+    def test_create_group_with_multiple_obs_ids(self, mock_delay):
+        mock_delay.return_value = self.delay_return_value
+        create_work_specifications_for_group(self.group, self.user, ["123", "456", " 781 "])
+
+        work_specification = list(WorkSpecification.objects.filter(group=self.group.id))
+
+        self.assertEqual(len(work_specification), 3)
+
+        actual_inherited_group_values = [(x.processing_site, x.selected_workflow, x.selected_workflow_tag) for x in
+                                         work_specification if x.group is self.group]
+
+        for actual_inherited_group_value in actual_inherited_group_values:
+            self.assertTupleEqual(actual_inherited_group_value,
+                                  (self.site, self.group.selected_workflow, self.group.selected_workflow_tag))
+
+    @mock.patch('lofardata.tasks.define_work_specification.delay')
+    def test_create_group_with_filters(self, mock_delay):
+        mock_delay.return_value = self.delay_return_value
+        obs_ids = ['123', '456']
+        create_work_specifications_for_group(self.group, self.user, obs_ids)
+
+        work_specification = list(WorkSpecification.objects.filter(group=self.group.id))
+
+        actual_obs_ids = [x.filters['obs_id'] for x in work_specification if x.filters['obs_id'] in obs_ids]
+
+        # assertCountEqual: Asserts that two iterables have the same elements, the same number of
+        # times, without regard to order.
+        self.assertCountEqual(actual_obs_ids, obs_ids)
+
+    @mock.patch("lofardata.view_helpers.specification.set_post_submit_values")
+    @mock.patch('lofardata.tasks.define_work_specification.delay')
+    def test_create_group_with_post_submit_values(self, mock_delay, post_submit_mock):
+        mock_delay.return_value = self.delay_return_value
+        create_work_specifications_for_group(self.group, self.user, ["123"])
+        self.assertTrue(post_submit_mock.called)
diff --git a/ldvspec/lofardata/tests/test_split_obs_ids.py b/ldvspec/lofardata/tests/test_split_obs_ids.py
new file mode 100644
index 0000000000000000000000000000000000000000..af107fae318d91ab920593044e65f453bc5dc092
--- /dev/null
+++ b/ldvspec/lofardata/tests/test_split_obs_ids.py
@@ -0,0 +1,21 @@
+import unittest
+
+from lofardata.view_helpers.specification import split_obs_ids_string
+
+
+class TestSplitObsIds(unittest.TestCase):
+    def test_split_obs_ids_separate_by_comma(self):
+        actual = split_obs_ids_string('1,2,3')
+        self.assertEqual(actual, ['1', '2', '3'])
+
+    def test_split_obs_ids_trim_spaces(self):
+        actual = split_obs_ids_string('4  ,  5,6      ')
+        self.assertEqual(actual, ['4', '5', '6'])
+
+    def test_split_obs_ids_trim_newlines(self):
+        actual = split_obs_ids_string('4\n,5\n\n,\n6\n')
+        self.assertEqual(actual, ['4', '5', '6'])
+
+    def test_split_obs_ids_trim_tabs(self):
+        actual = split_obs_ids_string('4\t,5\t\t,\t6\t')
+        self.assertEqual(actual, ['4', '5', '6'])
\ No newline at end of file
diff --git a/ldvspec/lofardata/tests/test_workspecification_creation.py b/ldvspec/lofardata/tests/test_workspecification_creation.py
index 7f40c72452b2862d0b899d7035cca1ef9b08df9b..4ef9b90db8250b051cd4ffce94350fd9ecfe10d7 100644
--- a/ldvspec/lofardata/tests/test_workspecification_creation.py
+++ b/ldvspec/lofardata/tests/test_workspecification_creation.py
@@ -3,11 +3,11 @@ import unittest
 from django.contrib.auth.models import User
 
 from lofardata.models import WorkSpecification
-from lofardata.views import set_post_submit_values
+from lofardata.view_helpers.specification import set_post_submit_values
+
 
 class WorkSpecificationCreation(unittest.TestCase):
     def test_set_created_by_when_already_set(self):
-
         existing_user = User(pk=1, username='existing')
         new_user = User(pk=2, username='new')
 
diff --git a/ldvspec/lofardata/view_helpers/specification.py b/ldvspec/lofardata/view_helpers/specification.py
new file mode 100644
index 0000000000000000000000000000000000000000..b56af213568d7a85760655c20869b14d7a9ae916
--- /dev/null
+++ b/ldvspec/lofardata/view_helpers/specification.py
@@ -0,0 +1,35 @@
+from typing import List
+
+from django.contrib.auth.models import User
+
+from lofardata.models import Group, WorkSpecification
+
+
+def set_post_submit_values(specification, user):
+    specification.async_task_result = None
+    specification.is_ready = False
+    if specification.created_by is None:
+        specification.created_by = user
+
+
+def split_obs_ids_string(obs_ids_string: str) -> List[str]:
+    return [obs_id.strip() for obs_id in obs_ids_string.split(',')]
+
+
+def create_work_specifications_for_group(group: Group, created_by: User, obs_ids: List[str]):
+    for obs_id in obs_ids:
+        create_work_specification_for_group(group, created_by, obs_id)
+
+
+def create_work_specification_for_group(group: Group, created_by: User, obs_id: str):
+    workspecification = WorkSpecification(
+        processing_site=group.processing_site,
+        selected_workflow=group.selected_workflow,
+        selected_workflow_tag=group.selected_workflow_tag,
+        filters={"obs_id": obs_id},
+        group=group
+    )
+
+    set_post_submit_values(workspecification, created_by)
+
+    workspecification.save()
diff --git a/ldvspec/lofardata/views.py b/ldvspec/lofardata/views.py
index c4a28b5778f89b5e39e919ea40f138da0ee09e16..39e2fdb02bd8786548312d69dd343612f860705b 100644
--- a/ldvspec/lofardata/views.py
+++ b/ldvspec/lofardata/views.py
@@ -31,6 +31,8 @@ from .serializers import (
 )
 from .tasks import insert_task_into_atdb
 from .view_helpers import inputs_processor, dataproductinfo, filters_preprocessor
+from .view_helpers.specification import set_post_submit_values, split_obs_ids_string, \
+    create_work_specifications_for_group
 
 
 class DynamicFilterSet(filters.FilterSet):
@@ -67,14 +69,6 @@ def api(request):
     atdb_hosts = ATDBProcessingSite.objects.values("name", "url")
     return render(request, "lofardata/api.html", {"atdb_hosts": atdb_hosts})
 
-
-def set_post_submit_values(specification, user):
-    specification.async_task_result = None
-    specification.is_ready = False
-    if specification.created_by is None:
-        specification.created_by = user
-
-
 class Specifications(ListView):
     serializer_class = WorkSpecificationSerializer
     template_name = "lofardata/index.html"
@@ -116,7 +110,6 @@ class WorkSpecificationCreateUpdateView(LoginRequiredMixin, CanAccessWorkSpecifi
             specification = None
         context["filters"] = filters_preprocessor.preprocess(specification)
         context["processing_sites"] = list(ATDBProcessingSite.objects.values("name", "url"))
-
         return context
 
     def create_successor(self, specification):
@@ -311,3 +304,14 @@ class GroupCreateUpdateView(LoginRequiredMixin, UpdateView):
         context = super().get_context_data(**kwargs)
         context["processing_sites"] = list(ATDBProcessingSite.objects.values("name", "url"))
         return context
+
+    def form_valid(self, form):
+        group = form.save()
+        obs_ids = split_obs_ids_string(form.data.get("obs_ids"))
+        create_work_specifications_for_group(group, self.request.user, obs_ids)
+
+        return super().form_valid(form)
+
+    def get_success_url(self, **kwargs):
+        return reverse_lazy("index")
+