diff --git a/app/admin/views.py b/app/admin/views.py
index a84d9b9b54be13a84c7913d76f716d538acb8314..a42a80d430e5e3f083e2e22dc9fb0dbee6c26847 100644
--- a/app/admin/views.py
+++ b/app/admin/views.py
@@ -83,6 +83,11 @@ class ItemAdmin(AdminModelView):
 
 class NetworkAdmin(AdminModelView):
 
+    # Replace TextAreaField (default for Text) with StringField
+    form_overrides = {
+        'vlan_name': fields.StringField,
+    }
+
     form_args = {
         'gateway': {
             'filters': [lambda x: x or None],
diff --git a/app/api/main.py b/app/api/main.py
index c8295ae4b677e1034eb078081f1fcb14543e4b5e..0738634a024a5356923bc50b7f08ef24ca2b582e 100644
--- a/app/api/main.py
+++ b/app/api/main.py
@@ -244,7 +244,7 @@ def create_status():
 def get_networks():
     # TODO: add pagination
     query = utils.get_query(Network.query, request.args)
-    networks = query.order_by(Network.prefix)
+    networks = query.order_by(Network.address)
     data = [network.to_dict() for network in networks]
     return jsonify(data)
 
@@ -254,7 +254,8 @@ def get_networks():
 @jwt_groups_accepted('admin')
 def create_network():
     """Create a new network"""
-    return create_generic_model(Network, mandatory_fields=('name', 'prefix', 'first', 'last'))
+    return create_generic_model(Network, mandatory_fields=(
+        'vlan_name', 'vlan_id', 'address', 'first_ip', 'last_ip', 'scope'))
 
 
 @bp.route('/hosts')
diff --git a/app/factory.py b/app/factory.py
index 37461e229c5f068767c0072a8f454e0b3d6946ef..3ce227d91d147048cbe21df213ce4358c5d74364 100644
--- a/app/factory.py
+++ b/app/factory.py
@@ -101,9 +101,11 @@ def create_app(config=None):
     admin.add_view(AdminModelView(models.Location, db.session))
     admin.add_view(AdminModelView(models.Status, db.session))
     admin.add_view(ItemAdmin(models.Item, db.session))
+    admin.add_view(AdminModelView(models.NetworkScope, db.session))
     admin.add_view(NetworkAdmin(models.Network, db.session))
     admin.add_view(HostAdmin(models.Host, db.session))
     admin.add_view(AdminModelView(models.Mac, db.session))
+    admin.add_view(AdminModelView(models.Cname, db.session))
 
     app.register_blueprint(main)
     app.register_blueprint(users)
diff --git a/app/main/forms.py b/app/main/forms.py
index 341bbb1231ee59bb5bf304ffedc345c7b995024a..66a4a00036b84b7f53f1aed6af8fa9622a193fe0 100644
--- a/app/main/forms.py
+++ b/app/main/forms.py
@@ -46,4 +46,4 @@ class HostForm(FlaskForm):
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self.network_id.choices = [(str(network.id), network.prefix) for network in models.Network.query.all()]
+        self.network_id.choices = [(str(network.id), network.address) for network in models.Network.query.all()]
diff --git a/app/main/views.py b/app/main/views.py
index 3b160249921dbfd48ea1bde9f29570791b242779..6acd739ab407390d8a02ed2479d351764967ca03 100644
--- a/app/main/views.py
+++ b/app/main/views.py
@@ -151,7 +151,7 @@ def hosts_index():
 @bp.route('/_retrieve_hosts')
 @login_required
 def retrieve_hosts():
-    data = [(host.name, host.ip, host.network.prefix) for host in models.Host.query.all()]
+    data = [(host.name, host.ip, host.network.vlan_name) for host in models.Host.query.all()]
     return jsonify(data=data)
 
 
diff --git a/app/models.py b/app/models.py
index 775989c2c3db932d7bd3a2ba1a1a8750b66f4c49..56e01def8bdec93cff8b6e1b7c7e914d884c66cd 100644
--- a/app/models.py
+++ b/app/models.py
@@ -177,7 +177,6 @@ class Model(QRCodeMixin, db.Model):
 
 class Location(QRCodeMixin, db.Model):
     items = db.relationship('Item', back_populates='location')
-    networks = db.relationship('Network', backref='location')
 
 
 class Status(QRCodeMixin, db.Model):
@@ -271,36 +270,45 @@ class Item(db.Model):
 
 class Network(db.Model):
     id = db.Column(db.Integer, primary_key=True)
-    name = db.Column(db.Text, nullable=False, unique=True)
-    prefix = db.Column(postgresql.CIDR, nullable=False, unique=True)
-    first = db.Column(postgresql.INET, nullable=False, unique=True)
-    last = db.Column(postgresql.INET, nullable=False, unique=True)
+    vlan_name = db.Column(CIText, nullable=False, unique=True)
+    vlan_id = db.Column(db.Integer, nullable=False, unique=True)
+    address = db.Column(postgresql.CIDR, nullable=False, unique=True)
+    first_ip = db.Column(postgresql.INET, nullable=False, unique=True)
+    last_ip = db.Column(postgresql.INET, nullable=False, unique=True)
     gateway = db.Column(postgresql.INET)
-    vlanid = db.Column(db.Integer, unique=True)
-    location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
+    description = db.Column(db.Text)
+    admin_only = db.Column(db.Boolean, nullable=False, default=False)
+    scope_id = db.Column(db.Integer, db.ForeignKey('network_scope.id'), nullable=False)
 
     hosts = db.relationship('Host', backref='network')
 
     __table_args__ = (
-        sa.CheckConstraint('first < last', name='first_less_than_last'),
-        sa.CheckConstraint('first << prefix', name='first_in_prefix'),
-        sa.CheckConstraint('last << prefix', name='last_in_prefix'),
+        sa.CheckConstraint('first_ip < last_ip', name='first_ip_less_than_last_ip'),
+        sa.CheckConstraint('first_ip << address', name='first_ip_in_network'),
+        sa.CheckConstraint('last_ip << address', name='last_ip_in_network'),
     )
 
+    def __init__(self, **kwargs):
+        # Automatically convert scope to an instance of NetworkScope if it was passed
+        # as a string
+        if 'scope' in kwargs:
+            kwargs['scope'] = utils.convert_to_model(kwargs['scope'], NetworkScope, 'name')
+        super().__init__(**kwargs)
+
     def __str__(self):
-        return str(self.prefix)
+        return str(self.vlan_name)
 
     @property
     def network_ip(self):
-        return ipaddress.ip_network(self.prefix)
+        return ipaddress.ip_network(self.address)
 
     @property
-    def first_ip(self):
-        return ipaddress.ip_address(self.first)
+    def first(self):
+        return ipaddress.ip_address(self.first_ip)
 
     @property
-    def last_ip(self):
-        return ipaddress.ip_address(self.last)
+    def last(self):
+        return ipaddress.ip_address(self.last_ip)
 
     def ip_range(self):
         """Return the list of IP addresses that can be assigned for this network
@@ -308,7 +316,7 @@ class Network(db.Model):
         The range is defined by the first and last IP
         """
         return [addr for addr in self.network_ip.hosts()
-                if self.first_ip <= addr <= self.last_ip]
+                if self.first <= addr <= self.last]
 
     def used_ips(self):
         """Return the list of IP addresses in use
@@ -323,7 +331,7 @@ class Network(db.Model):
                 if addr not in self.used_ips()]
 
     @staticmethod
-    def ip_in_network(ip, prefix):
+    def ip_in_network(ip, address):
         """Ensure the IP is in the network
 
         :param str user_id: unicode ID of a user
@@ -331,43 +339,45 @@ class Network(db.Model):
         :raises: ValidationError if the IP is not in the network
         """
         addr = ipaddress.ip_address(ip)
-        net = ipaddress.ip_network(prefix)
+        net = ipaddress.ip_network(address)
         if addr not in net:
-            raise ValidationError(f'IP address {ip} is not in network {prefix}')
+            raise ValidationError(f'IP address {ip} is not in network {address}')
         return (addr, net)
 
-    @validates('first')
-    def validate_first(self, key, ip):
+    @validates('first_ip')
+    def validate_first_ip(self, key, ip):
         """Ensure the first IP is in the network"""
-        self.ip_in_network(ip, self.prefix)
+        self.ip_in_network(ip, self.address)
         return ip
 
-    @validates('last')
-    def validate_last(self, key, ip):
-        """Ensure the last IP is in the network"""
-        addr, net = self.ip_in_network(ip, self.prefix)
-        if addr < ipaddress.ip_address(self.first):
+    @validates('last_ip')
+    def validate_last_ip(self, key, ip):
+        """Ensure the last IP is in the network and greater than first_ip"""
+        addr, net = self.ip_in_network(ip, self.address)
+        if addr < self.first:
             raise ValidationError(f'Last IP address {ip} is less than the first address {self.first}')
         return ip
 
     @validates('hosts')
     def validate_hosts(self, key, host):
         """Ensure the host IP is in the network range"""
-        addr, net = self.ip_in_network(host.ip, self.prefix)
-        if addr < ipaddress.ip_address(self.first) or addr > ipaddress.ip_address(self.last):
+        addr, net = self.ip_in_network(host.ip, self.address)
+        if addr < self.first or addr > self.last:
             raise ValidationError(f'IP address {host.ip} is not in range {self.first} - {self.last}')
         return host
 
     def to_dict(self):
         return {
             'id': self.id,
-            'name': self.name,
-            'prefix': self.prefix,
-            'first': self.first,
-            'last': self.last,
+            'vlan_name': self.vlan_name,
+            'address': self.address,
+            'first_ip': self.first_ip,
+            'last_ip': self.last_ip,
             'gateway': self.gateway,
-            'vlanid': self.vlanid,
-            'location': utils.format_field(self.location),
+            'vlan_id': self.vlan_id,
+            'description': self.description,
+            'admin_only': self.admin_only,
+            'scope': utils.format_field(self.scope),
         }
 
 
@@ -379,12 +389,13 @@ class Host(db.Model):
 
     # This is a One To One relationship (set uselist to False)
     mac = db.relationship('Mac', backref='host', uselist=False)
+    cnames = db.relationship('Cname', backref='host')
 
     def __init__(self, **kwargs):
         # Automatically convert network to an instance of Network if it was passed
-        # as a prefix string
+        # as an address string
         if 'network' in kwargs:
-            kwargs['network'] = utils.convert_to_model(kwargs['network'], Network, 'prefix')
+            kwargs['network'] = utils.convert_to_model(kwargs['network'], Network, 'address')
         # WARNING! Setting self.network will call validates_hosts in the Network class
         # For the validation to work, self.ip must be set before!
         # Ensure that ip is passed before network
@@ -442,6 +453,45 @@ class Mac(db.Model):
         return d
 
 
+class Cname(db.Model):
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.Text, nullable=False, unique=True)
+    host_id = db.Column(db.Integer, db.ForeignKey('host.id'), nullable=False, unique=True)
+
+    def __str__(self):
+        return str(self.name)
+
+    def to_dict(self):
+        return {
+            'id': self.id,
+            'name': self.name,
+            'host_id': self.host_id,
+        }
+
+
+class NetworkScope(db.Model):
+    __tablename__ = 'network_scope'
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(CIText, nullable=False, unique=True)
+    first_vlan = db.Column(db.Integer, nullable=False, unique=True)
+    last_vlan = db.Column(db.Integer, nullable=False, unique=True)
+    subnet = db.Column(postgresql.CIDR, nullable=False, unique=True)
+
+    networks = db.relationship('Network', backref='scope')
+
+    def __str__(self):
+        return str(self.name)
+
+    def to_dict(self):
+        return {
+            'id': self.id,
+            'name': self.name,
+            'first_vlan': self.first_vlan,
+            'last_vlan': self.last_vlan,
+            'subnet': self.subnet,
+        }
+
+
 # call configure_mappers after defining all the models
 # required by sqlalchemy_continuum
 sa.orm.configure_mappers()
diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py
index 9fb3008753c2903a4db81fecec9c5765a67748ab..bd589a0c86836264bd7e0d41c5573ac31372721a 100644
--- a/tests/functional/conftest.py
+++ b/tests/functional/conftest.py
@@ -23,6 +23,7 @@ register(factories.ModelFactory)
 register(factories.LocationFactory)
 register(factories.StatusFactory)
 register(factories.ItemFactory)
+register(factories.NetworkScopeFactory)
 register(factories.NetworkFactory)
 register(factories.HostFactory)
 
diff --git a/tests/functional/factories.py b/tests/functional/factories.py
index ab714d62873fa83ce6ec63daeeb5420903fee1d8..006cc31111f1222667b83473397ee78a3955e803 100644
--- a/tests/functional/factories.py
+++ b/tests/functional/factories.py
@@ -78,31 +78,44 @@ class ItemFactory(factory.alchemy.SQLAlchemyModelFactory):
     status = factory.SubFactory(StatusFactory)
 
 
+class NetworkScopeFactory(factory.alchemy.SQLAlchemyModelFactory):
+    class Meta:
+        model = models.NetworkScope
+        sqlalchemy_session = common.Session
+        sqlalchemy_session_persistence = 'commit'
+
+    name = factory.Sequence(lambda n: f'scope{n}')
+    first_vlan = factory.Sequence(lambda n: 1600 + 10 * n)
+    last_vlan = factory.Sequence(lambda n: 1609 + 10 * n)
+    subnet = factory.Faker('ipv4', network=True)
+
+
 class NetworkFactory(factory.alchemy.SQLAlchemyModelFactory):
     class Meta:
         model = models.Network
         sqlalchemy_session = common.Session
         sqlalchemy_session_persistence = 'commit'
 
-    name = factory.Sequence(lambda n: f'network{n}')
-    prefix = factory.Faker('ipv4', network=True)
-    vlanid = factory.Sequence(lambda n: 1600 + n)
+    vlan_name = factory.Sequence(lambda n: f'vlan{n}')
+    address = factory.Faker('ipv4', network=True)
+    vlan_id = factory.Sequence(lambda n: 1600 + n)
+    scope = factory.SubFactory(NetworkScopeFactory)
 
     @factory.lazy_attribute
-    def first(self):
-        net = ipaddress.ip_network(self.prefix)
+    def first_ip(self):
+        net = ipaddress.ip_network(self.address)
         hosts = list(net.hosts())
         return str(hosts[4])
 
     @factory.lazy_attribute
-    def last(self):
-        net = ipaddress.ip_network(self.prefix)
+    def last_ip(self):
+        net = ipaddress.ip_network(self.address)
         hosts = list(net.hosts())
         return str(hosts[-5])
 
     @factory.lazy_attribute
     def gateway(self):
-        net = ipaddress.ip_network(self.prefix)
+        net = ipaddress.ip_network(self.address)
         hosts = list(net.hosts())
         return str(hosts[-1])
 
diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py
index 2b4f97d03722ae84ae0b58a75696615a017850db..96de4f78f6a43193a91ddf2c1d2b539d56ec8310 100644
--- a/tests/functional/test_api.py
+++ b/tests/functional/test_api.py
@@ -431,26 +431,19 @@ def test_get_items(client, session, readonly_token):
     check_response_message(response, 'Invalid query arguments', 422)
 
 
-def test_get_networks(client, location_factory, network_factory, readonly_token):
+def test_get_networks(client, network_factory, readonly_token):
     # Create some networks
-    location = location_factory(name='G02')
-    network1 = network_factory(prefix='172.16.1.0/24', first='172.16.1.1', last='172.16.1.254')
-    network2 = network_factory(prefix='172.16.20.0/22', first='172.16.20.11', last='172.16.20.250')
-    network3 = network_factory(prefix='172.16.5.0/24', first='172.16.5.10', last='172.16.5.254', location=location)
+    network1 = network_factory(address='172.16.1.0/24', first_ip='172.16.1.1', last_ip='172.16.1.254')
+    network2 = network_factory(address='172.16.20.0/22', first_ip='172.16.20.11', last_ip='172.16.20.250')
+    network3 = network_factory(address='172.16.5.0/24', first_ip='172.16.5.10', last_ip='172.16.5.254')
 
     response = get(client, '/api/networks', token=readonly_token)
     assert response.status_code == 200
     assert len(response.json) == 3
     check_input_is_subset_of_response(response, (network1.to_dict(), network2.to_dict(), network3.to_dict()))
 
-    # test filtering by location_id
-    response = get(client, f'/api/networks?location_id={location.id}', token=readonly_token)
-    assert response.status_code == 200
-    assert len(response.json) == 1
-    check_input_is_subset_of_response(response, (network3.to_dict(),))
-
-    # test filtering by prefix
-    response = get(client, '/api/networks?prefix=172.16.20.0/22', token=readonly_token)
+    # test filtering by address
+    response = get(client, '/api/networks?address=172.16.20.0/22', token=readonly_token)
     assert response.status_code == 200
     assert len(response.json) == 1
     check_input_is_subset_of_response(response, (network2.to_dict(),))
@@ -462,125 +455,146 @@ def test_create_network_auth_fail(client, session, user_token):
     check_response_message(response, "User doesn't have the required group", 403)
 
 
-def test_create_network(client, location_factory, admin_token):
-    location = location_factory(name='G02')
-    # check that name, prefix, first and last are mandatory
+def test_create_network(client, admin_token, network_scope_factory):
+    scope = network_scope_factory(subnet='172.16.0.0/16')
+    # check that vlan_name, vlan_id, address, first_ip, last_ip and scope are mandatory
     response = post(client, '/api/networks', data={}, token=admin_token)
-    check_response_message(response, "Missing mandatory field 'name'", 422)
-    response = post(client, '/api/networks', data={'first': '172.16.1.10', 'last': '172.16.1.250'}, token=admin_token)
-    check_response_message(response, "Missing mandatory field 'name'", 422)
-    response = post(client, '/api/networks', data={'prefix': '172.16.1.0/24'}, token=admin_token)
-    check_response_message(response, "Missing mandatory field 'name'", 422)
-    response = post(client, '/api/networks', data={'name': 'network1'}, token=admin_token)
-    check_response_message(response, "Missing mandatory field 'prefix'", 422)
-    response = post(client, '/api/networks', data={'name': 'network1', 'prefix': '172.16.1.0/24', 'first': '172.16.1.10'}, token=admin_token)
-    check_response_message(response, "Missing mandatory field 'last'", 422)
-
-    data = {'name': 'network1',
-            'prefix': '172.16.1.0/24',
-            'first': '172.16.1.10',
-            'last': '172.16.1.250'}
+    check_response_message(response, "Missing mandatory field 'vlan_name'", 422)
+    response = post(client, '/api/networks', data={'first_ip': '172.16.1.10', 'last_ip': '172.16.1.250'}, token=admin_token)
+    check_response_message(response, "Missing mandatory field 'vlan_name'", 422)
+    response = post(client, '/api/networks', data={'address': '172.16.1.0/24'}, token=admin_token)
+    check_response_message(response, "Missing mandatory field 'vlan_name'", 422)
+    response = post(client, '/api/networks', data={'vlan_name': 'network1'}, token=admin_token)
+    check_response_message(response, "Missing mandatory field 'vlan_id'", 422)
+    response = post(client, '/api/networks', data={'vlan_name': 'network1', 'vlan_id': 1600}, token=admin_token)
+    check_response_message(response, "Missing mandatory field 'address'", 422)
+    response = post(client, '/api/networks', data={'vlan_name': 'network1', 'vlan_id': 1600, 'address': '172.16.1.0/24', 'first_ip': '172.16.1.10'}, token=admin_token)
+    check_response_message(response, "Missing mandatory field 'last_ip'", 422)
+
+    data = {'vlan_name': 'network1',
+            'vlan_id': 1600,
+            'address': '172.16.1.0/24',
+            'first_ip': '172.16.1.10',
+            'last_ip': '172.16.1.250',
+            'scope': scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     assert response.status_code == 201
-    assert {'id', 'name', 'prefix', 'first', 'last', 'vlanid', 'gateway', 'location'} == set(response.json.keys())
-    assert response.json['name'] == 'network1'
-    assert response.json['prefix'] == '172.16.1.0/24'
-    assert response.json['first'] == '172.16.1.10'
-    assert response.json['last'] == '172.16.1.250'
-
-    # Check that prefix and name shall be unique
+    assert {'id', 'vlan_name', 'vlan_id', 'address', 'first_ip',
+            'last_ip', 'gateway', 'description', 'is_admin', 'scope'} == set(response.json.keys())
+    assert response.json['vlan_name'] == 'network1'
+    assert response.json['vlan_id'] == 1600
+    assert response.json['address'] == '172.16.1.0/24'
+    assert response.json['first_ip'] == '172.16.1.10'
+    assert response.json['last_ip'] == '172.16.1.250'
+
+    # Check that address and name shall be unique
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422)
-    data_same_prefix = data.copy()
-    data_same_prefix['name'] = 'networkX'
-    response = post(client, '/api/networks', data=data_same_prefix, token=admin_token)
+    data_same_address = data.copy()
+    data_same_address['vlan_name'] = 'networkX'
+    response = post(client, '/api/networks', data=data_same_address, token=admin_token)
     check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422)
-    data_same_name = {'name': 'network1',
-                      'prefix': '172.16.2.0/24',
-                      'first': '172.16.2.10',
-                      'last': '172.16.2.250'}
+    data_same_name = {'vlan_name': 'network1',
+                      'vlan_id': '1600',
+                      'address': '172.16.2.0/24',
+                      'first_ip': '172.16.2.10',
+                      'last_ip': '172.16.2.250',
+                      'scope': scope.name}
     response = post(client, '/api/networks', data=data_same_name, token=admin_token)
     check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422)
 
     # Check that all parameters can be passed
-    data2 = {'name': 'network2',
-             'prefix': '172.16.5.0/24',
-             'first': '172.16.5.11',
-             'last': '172.16.5.250',
+    data2 = {'vlan_name': 'network2',
+             'vlan_id': '1601',
+             'address': '172.16.5.0/24',
+             'first_ip': '172.16.5.11',
+             'last_ip': '172.16.5.250',
              'gateway': '172.16.5.10',
-             'vlanid': 1601,
-             'location_id': location.id}
+             'description': 'long description',
+             'scope': scope.name}
     response = post(client, '/api/networks', data=data2, token=admin_token)
     assert response.status_code == 201
-    assert response.json['location'] == location.name
+    assert response.json['description'] == 'long description'
 
     # check all items that were created
     assert models.Network.query.count() == 2
 
 
-def test_create_network_invalid_prefix(client, session, admin_token):
+def test_create_network_invalid_address(client, session, admin_token, network_scope):
     # invalid network address
-    data = {'name': 'network1',
-            'prefix': 'foo',
-            'first': '172.16.1.10',
-            'last': '172.16.1.250'}
+    data = {'vlan_name': 'network1',
+            'vlan_id': '1600',
+            'address': 'foo',
+            'first_ip': '172.16.1.10',
+            'last_ip': '172.16.1.250',
+            'scope': network_scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, "'foo' does not appear to be an IPv4 or IPv6 network", 422)
-    data['prefix'] = '172.16.1'
+    data['address'] = '172.16.1'
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, "'172.16.1' does not appear to be an IPv4 or IPv6 network", 422)
-    # prefix address has host bits set
-    data['prefix'] = '172.16.1.1/24'
+    # address has host bits set
+    data['address'] = '172.16.1.1/24'
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, '172.16.1.1/24 has host bits set', 422)
 
 
 @pytest.mark.parametrize('address', ('', 'foo', '192.168'))
-def test_create_network_invalid_ip(address, client, session, admin_token):
+def test_create_network_invalid_ip(address, client, session, admin_token, network_scope):
     # invalid first IP address
-    data = {'name': 'network1',
-            'prefix': '192.168.0.0/24',
-            'first': address,
-            'last': '192.168.0.250'}
+    data = {'vlan_name': 'network1',
+            'vlan_id': '1600',
+            'address': '192.168.0.0/24',
+            'first_ip': address,
+            'last_ip': '192.168.0.250',
+            'scope': network_scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, f"'{address}' does not appear to be an IPv4 or IPv6 address", 422)
     # invalid last IP address
-    data = {'name': 'network1',
-            'prefix': '192.168.0.0/24',
-            'first': '192.168.0.250',
-            'last': address}
+    data = {'vlan_name': 'network1',
+            'vlan_id': '1600',
+            'address': '192.168.0.0/24',
+            'first_ip': '192.168.0.250',
+            'last_ip': address,
+            'scope': network_scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, f"'{address}' does not appear to be an IPv4 or IPv6 address", 422)
 
 
-def test_create_network_invalid_range(client, session, admin_token):
-    # first not in prefix
-    data = {'name': 'network1',
-            'prefix': '172.16.1.0/24',
-            'first': '172.16.2.10',
-            'last': '172.16.1.250'}
+def test_create_network_invalid_range(client, session, admin_token, network_scope):
+    # first_ip not in network address
+    data = {'vlan_name': 'network1',
+            'vlan_id': '1600',
+            'address': '172.16.1.0/24',
+            'first_ip': '172.16.2.10',
+            'last_ip': '172.16.1.250',
+            'scope': network_scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, 'IP address 172.16.2.10 is not in network 172.16.1.0/24', 422)
-    # last not in prefix
-    data = {'name': 'network1',
-            'prefix': '172.16.1.0/24',
-            'first': '172.16.1.10',
-            'last': '172.16.5.250'}
+    # last_ip not in network address
+    data = {'vlan_name': 'network1',
+            'vlan_id': '1600',
+            'address': '172.16.1.0/24',
+            'first_ip': '172.16.1.10',
+            'last_ip': '172.16.5.250',
+            'scope': network_scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, 'IP address 172.16.5.250 is not in network 172.16.1.0/24', 422)
-    # first > last
-    data = {'name': 'network1',
-            'prefix': '172.16.1.0/24',
-            'first': '172.16.1.10',
-            'last': '172.16.1.9'}
+    # first_ip > last_ip
+    data = {'vlan_name': 'network1',
+            'vlan_id': '1600',
+            'address': '172.16.1.0/24',
+            'first_ip': '172.16.1.10',
+            'last_ip': '172.16.1.9',
+            'scope': network_scope.name}
     response = post(client, '/api/networks', data=data, token=admin_token)
     check_response_message(response, 'Last IP address 172.16.1.9 is less than the first address 172.16.1.10', 422)
 
 
 def test_get_hosts(client, network_factory, host_factory, readonly_token):
     # Create some hosts
-    network1 = network_factory(prefix='192.168.1.0/24', first='192.168.1.10', last='192.168.1.250')
-    network2 = network_factory(prefix='192.168.2.0/24', first='192.168.2.10', last='192.168.2.250')
+    network1 = network_factory(address='192.168.1.0/24', first_ip='192.168.1.10', last_ip='192.168.1.250')
+    network2 = network_factory(address='192.168.2.0/24', first_ip='192.168.2.10', last_ip='192.168.2.250')
     host1 = host_factory(network=network1, ip='192.168.1.10')
     host2 = host_factory(network=network1, ip='192.168.1.11', name='hostname2')
     host3 = host_factory(network=network2, ip='192.168.2.10')
@@ -598,16 +612,16 @@ def test_get_hosts(client, network_factory, host_factory, readonly_token):
 
 
 def test_create_host(client, network_factory, user_token):
-    network = network_factory(prefix='192.168.1.0/24', first='192.168.1.10', last='192.168.1.250')
+    network = network_factory(address='192.168.1.0/24', first_ip='192.168.1.10', last_ip='192.168.1.250')
     # check that network_id and ip are mandatory
     response = post(client, '/api/hosts', data={}, token=user_token)
     check_response_message(response, "Missing mandatory field 'network'", 422)
     response = post(client, '/api/hosts', data={'ip': '192.168.1.20'}, token=user_token)
     check_response_message(response, "Missing mandatory field 'network'", 422)
-    response = post(client, '/api/hosts', data={'network': network.prefix}, token=user_token)
+    response = post(client, '/api/hosts', data={'network': network.address}, token=user_token)
     check_response_message(response, "Missing mandatory field 'ip'", 422)
 
-    data = {'network': network.prefix,
+    data = {'network': network.address,
             'ip': '192.168.1.20'}
     response = post(client, '/api/hosts', data=data, token=user_token)
     assert response.status_code == 201
@@ -620,7 +634,7 @@ def test_create_host(client, network_factory, user_token):
     check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422)
 
     # Check that all parameters can be passed
-    data2 = {'network': network.prefix,
+    data2 = {'network': network.address,
              'ip': '192.168.1.21',
              'name': 'myhostname'}
     response = post(client, '/api/hosts', data=data2, token=user_token)
@@ -633,18 +647,18 @@ def test_create_host(client, network_factory, user_token):
 
 @pytest.mark.parametrize('ip', ('', 'foo', '192.168'))
 def test_create_host_invalid_ip(ip, client, network_factory, user_token):
-    network = network_factory(prefix='192.168.1.0/24', first='192.168.1.10', last='192.168.1.250')
+    network = network_factory(address='192.168.1.0/24', first_ip='192.168.1.10', last_ip='192.168.1.250')
     # invalid IP address
-    data = {'network': network.prefix,
+    data = {'network': network.address,
             'ip': ip}
     response = post(client, '/api/hosts', data=data, token=user_token)
     check_response_message(response, f"'{ip}' does not appear to be an IPv4 or IPv6 address", 422)
 
 
 def test_create_host_ip_not_in_network(client, network_factory, user_token):
-    network = network_factory(prefix='192.168.1.0/24', first='192.168.1.10', last='192.168.1.250')
+    network = network_factory(address='192.168.1.0/24', first_ip='192.168.1.10', last_ip='192.168.1.250')
     # IP address not in range
-    data = {'network': network.prefix,
+    data = {'network': network.address,
             'ip': '192.168.2.4'}
     response = post(client, '/api/hosts', data=data, token=user_token)
     check_response_message(response, 'IP address 192.168.2.4 is not in network 192.168.1.0/24', 422)
diff --git a/tests/functional/test_models.py b/tests/functional/test_models.py
index cffd358c90a975667c9d8fd4d96e3a77f57b37b9..1009f7b4c87017586cb31942cb286c9b3872b463 100644
--- a/tests/functional/test_models.py
+++ b/tests/functional/test_models.py
@@ -14,20 +14,20 @@ import ipaddress
 
 def test_network_ip_properties(network_factory):
     # Create some networks
-    network1 = network_factory(prefix='172.16.1.0/24', first='172.16.1.10', last='172.16.1.250')
-    network2 = network_factory(prefix='172.16.20.0/26', first='172.16.20.11', last='172.16.20.14')
+    network1 = network_factory(address='172.16.1.0/24', first_ip='172.16.1.10', last_ip='172.16.1.250')
+    network2 = network_factory(address='172.16.20.0/26', first_ip='172.16.20.11', last_ip='172.16.20.14')
 
     assert network1.network_ip == ipaddress.ip_network('172.16.1.0/24')
-    assert network1.first_ip == ipaddress.ip_address('172.16.1.10')
-    assert network1.last_ip == ipaddress.ip_address('172.16.1.250')
+    assert network1.first == ipaddress.ip_address('172.16.1.10')
+    assert network1.last == ipaddress.ip_address('172.16.1.250')
     assert len(network1.ip_range()) == 241
     assert network1.ip_range() == [ipaddress.ip_address(f'172.16.1.{i}') for i in range(10, 251)]
     assert network1.ip_range() == network1.available_ips()
     assert network1.used_ips() == []
 
     assert network2.network_ip == ipaddress.ip_network('172.16.20.0/26')
-    assert network2.first_ip == ipaddress.ip_address('172.16.20.11')
-    assert network2.last_ip == ipaddress.ip_address('172.16.20.14')
+    assert network2.first == ipaddress.ip_address('172.16.20.11')
+    assert network2.last == ipaddress.ip_address('172.16.20.14')
     assert len(network2.ip_range()) == 4
     assert network2.ip_range() == [ipaddress.ip_address(f'172.16.20.{i}') for i in range(11, 15)]
     assert network2.ip_range() == network2.available_ips()
@@ -36,8 +36,8 @@ def test_network_ip_properties(network_factory):
 
 def test_network_available_and_used_ips(network_factory, host_factory):
     # Create some networks and hosts
-    network1 = network_factory(prefix='172.16.1.0/24', first='172.16.1.10', last='172.16.1.250')
-    network2 = network_factory(prefix='172.16.20.0/26', first='172.16.20.11', last='172.16.20.14')
+    network1 = network_factory(address='172.16.1.0/24', first_ip='172.16.1.10', last_ip='172.16.1.250')
+    network2 = network_factory(address='172.16.20.0/26', first_ip='172.16.20.11', last_ip='172.16.20.14')
     for i in range(10, 20):
         host_factory(network=network1, ip=f'172.16.1.{i}')
     host_factory(network=network2, ip='172.16.20.13')