diff --git a/README.md b/README.md
index 36ac4fbbffba796dcd5155416999331ec509f6f3..bc1e83e59ecfec442adbd332e1a7de94c5be2b53 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
-This codebase uses Python flask, see https://flask.palletsprojects.com/ for more information.
-
 # Running the Website
 To host an instance of the server run the command ``python run.py`` in a terminal from the root directory of the project, where ``run.py`` is. 
 
@@ -21,6 +19,8 @@ To ensure a consistent code style Python [black](https://pypi.org/project/black/
 
 Python black follows pep8, that means snake_case for variables and function names, PascalCase for classes.
 
+This codebase uses Python flask, see https://flask.palletsprojects.com/ for more information.
+
 ## Static
 Static content, e.g. images, css, are stored in the static folder.
 
@@ -72,3 +72,5 @@ Ensure code works, do not knowingly commit broken code so as to avoid interrupti
 Commit messages should be as though they are telling the commit history what to do, e.g. "Add file.py".\
 Do not commit files that can be regenerated, for example virtual environment files.\
 Update requirements.txt with any newly imported moduless.
+
+[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 701fd76f05f9990acd121b3a2b725449cb866079..e9dbd773c1609b7758d260c4e90c238767d675aa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,4 +4,5 @@ Flask_WTF
 WTForms
 flask_login
 flask_mail
-requests
\ No newline at end of file
+requests
+black
diff --git a/store/forms.py b/store/forms.py
index ec125c50b01db198e8520e6836d8a0bf19e113d9..7f088a7253409cb6f527a9eedda4f8edf9ae9418 100644
--- a/store/forms.py
+++ b/store/forms.py
@@ -1,5 +1,13 @@
 from flask_wtf import FlaskForm
-from wtforms import BooleanField, StringField, PasswordField, SubmitField, validators
+from wtforms import (
+    BooleanField,
+    StringField,
+    PasswordField,
+    SubmitField,
+    SelectField,
+    IntegerField,
+    validators,
+)
 from wtforms.validators import DataRequired  # Basic example.#
 
 
@@ -37,3 +45,21 @@ class LoginForm(FlaskForm):
 class SearchForm(FlaskForm):
     query = StringField("Query", [validators.DataRequired()])
     submit = SubmitField("Submit")
+
+
+class AccessDataForm(FlaskForm):
+    table = SelectField(
+        "Table", choices=["Item", "Item Set"], validators=[validators.DataRequired()]
+    )
+    id = IntegerField("ID", [validators.DataRequired()])
+    submit = SubmitField("Submit")
+
+
+class AddForm(FlaskForm):
+    table = SelectField(
+        "Table", choices=["Item", "Item Set"], validators=[validators.DataRequired()]
+    )
+    description = StringField("Description", validators=[validators.DataRequired()])
+    # Default value so item set doesn't have validation errors despite not needing it.
+    price = IntegerField(default=0, validators=[validators.DataRequired()])
+    submit = SubmitField("Submit")
diff --git a/store/models.py b/store/models.py
index 06b869cb95456d1241b9cdf471fa9a21a0ea3be1..076efd6f5f7d3ad7804a555cca3d8e3587cb0049 100644
--- a/store/models.py
+++ b/store/models.py
@@ -58,7 +58,6 @@ class ItemSet(db.Model):
 
     id = db.Column(db.Integer, primary_key=True)
     description = db.Column(db.String(256), nullable=False)
-    quantity = db.Column(db.Integer, nullable=False)
     items = db.relationship(
         "Item",
         secondary=itemSets,
@@ -70,6 +69,10 @@ class ItemSet(db.Model):
     def price(self):
         return sum(int(item.price) for item in self.items)
 
+    @property
+    def quantity(self):
+        return len(self.items)
+
     def __repr__(self):
         return f"id: {self.id}, description: {self.description}, items: {self.items}, quantity: {self.price}, price: { self.calculate_price() }"  # TODO: Rename price to quantity
 
diff --git a/store/routes.py b/store/routes.py
index 0009d09fe34db43236165fefbbb77b538e3d9f3b..8d426f6611773a8c1212500c93dd18713f05619d 100644
--- a/store/routes.py
+++ b/store/routes.py
@@ -1,5 +1,14 @@
 from store import app, db
-from flask import render_template, request, flash, redirect, url_for, Flask, session
+from flask import (
+    render_template,
+    request,
+    flash,
+    redirect,
+    url_for,
+    Flask,
+    session,
+    abort,
+)
 from flask_wtf import FlaskForm
 from flask_wtf.csrf import generate_csrf
 import requests
@@ -19,6 +28,7 @@ from store.utility import *
 from store.forms import *
 import string
 import random
+import sys
 
 
 # Official flask-login doc free liecense
@@ -316,6 +326,146 @@ def admin():
         return render_template("userContent/admin.html")
 
 
+@app.route("/database_management", methods=["GET", "POST"])
+@login_required
+def database_management():
+    if current_user.userType != "admin":
+        flash("Unauthorized access")
+        return redirect(url_for("home"))
+    # No need for an else statement as early return will
+    # prevent access anyway.
+    access_data_form = AccessDataForm()
+    if access_data_form.validate_on_submit():
+        if access_data_form.table.data == "Item":
+            table = Item
+        elif access_data_form.table.data == "Item Set":
+            table = ItemSet
+        id = access_data_form.id.data
+        item = table.query.get(id)
+        if item == None:
+            flash("Invalid ID!")
+
+        # No point to using another page, just use the same template.
+        return render_template(
+            "userContent/database_management.html",
+            access_data_form=access_data_form,
+            main_item=item,
+            is_item=type(item) is Item,
+        )
+
+    return render_template(
+        "userContent/database_management.html",
+        access_data_form=access_data_form,
+        main_item=None,
+    )
+
+
+@app.route("/database_management_add", methods=["GET", "POST"])
+@login_required
+def database_management_add():
+    if current_user.userType != "admin":
+        flash("Unauthorized access")
+        return redirect(url_for("home"))
+
+    form = AddForm()
+    if form.validate_on_submit():
+        description = form.description.data
+        price = form.price.data
+
+        item = None
+        if form.table.data == "Item":
+            item = Item(description=description, price=price)
+        elif form.table.data == "Item Set":
+            item = ItemSet(description=description)
+        db.session.add(item)
+        db.session.commit()
+
+        access_data_form = AccessDataForm()
+        return render_template(
+            "userContent/database_management.html",
+            access_data_form=access_data_form,
+            main_item=item,
+            is_item=type(item) is Item,
+        )
+
+    return render_template(
+        "userContent/database_management_add.html",
+        form=form,
+    )
+
+
+@app.route("/add_item_to_set", methods=["GET", "POST"])
+def add_item_to_set():
+    print("Adding Item", file=sys.stderr)
+    if current_user.userType != "admin":
+        flash("Unauthorized access")
+        return redirect(url_for("home"))
+
+    item_id = request.form.get("item_id")
+    set_id = request.form.get("set_id")
+    item_set = ItemSet.query.get(set_id)
+    item = Item.query.get(item_id)
+    print("Adding Item:", item_id, "To Set:", set_id, file=sys.stderr)
+
+    if item_set == None or item == None:
+        abort(406)
+    if item in item_set.items:
+        abort(406)
+
+    print("Adding Item:", item_id, "To Set:", set_id, file=sys.stderr)
+    item_set.items.append(item)
+    db.session.commit()
+    return "ok"
+
+
+@app.route("/delete_item", methods=["DELETE"])
+def delete_item():
+    if current_user.userType != "admin":
+        flash("Unauthorized access")
+        return redirect(url_for("home"))
+    id = request.form.get("item_id")
+    item = Item.query.get(id)
+    if item == None:
+        print("Could not delete item:", id, file=sys.stderr)
+        abort(406)
+    print("Deleting Item:", id, file=sys.stderr)
+    remove_item(item)
+    return "ok"
+
+
+@app.route("/delete_item_set", methods=["DELETE"])
+def delete_item_set():
+    if current_user.userType != "admin":
+        flash("Unauthorized access")
+        return redirect(url_for("home"))
+    id = request.form.get("item_id")
+    item = ItemSet.query.get(id)
+    if item == None:
+        abort(406)
+    print("Deleting Item Set:", id, file=sys.stderr)
+    remove_item_set(item)
+    return "ok"
+
+
+@app.route("/delete_item_from_set", methods=["DELETE"])
+def delete_item_from_set():
+    if current_user.userType != "admin":
+        flash("Unauthorized access")
+        return redirect(url_for("home"))
+    item_id = request.form.get("item_id")
+    set_id = request.form.get("set_id")
+    item_set = ItemSet.query.get(set_id)
+    item = Item.query.get(item_id)
+
+    if item_set == None or item == None:
+        abort(406)
+
+    print("Deleting Item:", item_id, "From Set:", set_id, file=sys.stderr)
+    item_set.items.remove(item)
+    db.session.commit()
+    return "ok"
+
+
 @app.route("/ChangeUsername/", methods=["GET", "POST"])
 @login_required
 def ChangeUsername():
@@ -562,7 +712,7 @@ def add_to_basket_set():
 
 
 @app.route("/remove_item", methods=["POST"])
-def remove_item():
+def remove_item_basket():  # Calling this remove_item shadows the utility function remove_item()
     if request.method == "POST":
         item_id = request.form["item"]
 
diff --git a/store/templates/base.html b/store/templates/base.html
index 36c73cd05b7585f0d667353706521fe1fd419f19..078786afef4d5ea9499d4648f8c6d634a52d9310 100644
--- a/store/templates/base.html
+++ b/store/templates/base.html
@@ -6,6 +6,7 @@
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
   <title>{% block title %}{% endblock%}</title>
   <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='_main.css') }}"> <!-- Load the CSS. -->
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
 </head>
 
 <body>
diff --git a/store/templates/userContent/admin.html b/store/templates/userContent/admin.html
index dec9ae5c92aafa455f90a6505556298cd575ad05..35187f877c03846f0c9a72b16db649f42845f9aa 100644
--- a/store/templates/userContent/admin.html
+++ b/store/templates/userContent/admin.html
@@ -6,5 +6,8 @@
 <ul>
     <li><a href="{{ url_for('accountDetails')}}">View my Account details</a></li>
     <li><a href="{{ url_for('view_address')}}">View my shipping address</a></li>
+    <li><a href="{{ url_for('database_management')}}">Edit existing entries</a></li>
+    <li><a href="{{ url_for('database_management_add')}}">Add new entries</a></li>
+
 </ul>
 {% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/database_management.html b/store/templates/userContent/database_management.html
new file mode 100644
index 0000000000000000000000000000000000000000..1c731139628312a3db62625d6754993fa3eba1ab
--- /dev/null
+++ b/store/templates/userContent/database_management.html
@@ -0,0 +1,116 @@
+{% from "_formhelpers.html" import render_field %}
+{%extends 'base.html' %}
+{% block title %} Database Management | Antiques Online {% endblock %}
+{% block content %}
+<form method="POST">
+    {{access_data_form.hidden_tag()}}
+    <dl>
+        <table>
+            <tr>
+                <td>{{ render_field(access_data_form.table) }} </td>
+            </tr>
+            <tr>
+                <td>{{ render_field(access_data_form.id) }} </td>
+            </tr>
+        </table>
+    </dl>
+    <br>
+    {{access_data_form.submit()}}
+    <br>
+</form>
+
+{% if main_item %}
+<div>
+    <img src='..\static\image_placeholder.png' alt="Image Placeholder" width="200" height="170">
+    <br />
+    Item price: £{{main_item.price}}
+    <br />
+    Item description: {{main_item.description}}
+    <br />
+    {% if is_item %}
+    <button onclick="deleteItem({{main_item.id}})">Delete</button>
+    {%else%}
+    <button onclick="deleteItemSet({{main_item.id}})">Delete</button>
+    {% endif %}
+
+    {% if not is_item %}
+    <div>
+        <h1>Items contained in set: </h1>
+        <table>
+            <thead>
+                <tr>
+                    <th>Item description</th>
+                    <th>Item price</th>
+                    <th></th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for item in main_item.items %}
+                <tr>
+                    <td>{{ item['description'] }}</td>
+                    <td>£{{ item['price'] }}</td>
+                    <button onclick="deleteItemFromSet({{item.id}}, {{main_item.id}})">Delete</button>
+                </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+        <label for="itemID">Item ID:</label><br>
+        <input type="number" id="itemID" name="itemID"><br>
+        <button onclick="addItemToSet({{main_item.id}})">Add</button>
+    </div>
+    {% endif %}
+</div>
+{% endif %}
+
+<script>
+    function addItemToSet(set_id) {
+        console.log(set_id);
+        console.log($('#itemID').val());
+
+        $.ajax({
+            url: '/add_item_to_set',
+            type: 'POST',
+            data: { set_id: set_id, item_id: $('#itemID').val() },
+            success: function () {
+                window.location.href = window.location.href;
+            }
+        });
+    };
+    function deleteItem(id) {
+        if (confirm("Are you sure you want to delete this item? It is irreversible.")) {
+            $.ajax({
+                url: '/delete_item',
+                type: 'DELETE',
+                data: { item_id: id },
+                success: function () {
+                    window.location.href = window.location.href;
+                }
+            });
+        }
+    };
+    function deleteItemSet(id) {
+        if (confirm("Are you sure you want to delete this item? It is irreversible.")) {
+            $.ajax({
+                url: '/delete_item_set',
+                type: 'DELETE',
+                data: { item_id: id },
+                success: function () {
+                    window.location.href = window.location.href;
+                }
+            });
+        }
+    };
+    function deleteItemFromSet(id, set_id) {
+        if (confirm("Are you sure you want to delete this item? It is irreversible.")) {
+            $.ajax({
+                url: '/delete_item_from_set',
+                type: 'DELETE',
+                data: { set_id: set_id, item_id: id },
+                success: function () {
+                    window.location.href = window.location.href;
+                }
+            });
+        }
+    };
+</script>
+{% endblock %}
\ No newline at end of file
diff --git a/store/templates/userContent/database_management_add.html b/store/templates/userContent/database_management_add.html
new file mode 100644
index 0000000000000000000000000000000000000000..1ebfc8a0ad44f8cd446ef927f15ab0358f889916
--- /dev/null
+++ b/store/templates/userContent/database_management_add.html
@@ -0,0 +1,34 @@
+{% from "_formhelpers.html" import render_field %}
+{%extends 'base.html' %}
+{% block title %} Database Management | Antiques Online {% endblock %}
+{% block content %}
+<form method="POST">
+    {{form.hidden_tag()}}
+    <dl>
+        <table>
+            <tr>
+                <td>{{ render_field(form.table) }} </td>
+            </tr>
+            <tr>
+                <td>{{ render_field(form.description) }} </td>
+            </tr>
+            <tr id="price_optional">
+                <td>{{ render_field(form.price) }} </td>
+            </tr>
+            </div>
+        </table>
+    </dl>
+    <br>
+    {{form.submit()}}
+    <br>
+</form>
+
+<script>
+    $(document).ready(function () {
+        $('#table').change(function () {
+            $('#price_optional').toggle();
+        });
+    });
+</script>
+
+{% endblock %}
\ No newline at end of file
diff --git a/store/utility.py b/store/utility.py
index e1d9cac2108e65345268d20a9d083379c3911b89..8029ff9f8a9c6c99dbad6313104db14acb3d95e6 100644
--- a/store/utility.py
+++ b/store/utility.py
@@ -77,12 +77,6 @@ def get_similar_items(description):
     return found
 
 
-def remove_item(item):
-    update_set(item)
-    db.session.Item.query(item).delete()
-    db.session.commit()
-
-
 def get_by_keyword(substring):
     """Search desciption for matching substring. Case insensitive.
     This is most useful for a user keyword search.
@@ -104,15 +98,8 @@ def get_itemsets_by_item_id(item_id):
     return item_set_contained_id
 
 
-def sell_item(item, date=datetime.datetime.today()):
-    update_set(item)
-    item.date_sold = date
-    db.session.commit()
-
-    # Alternate approach where items_sets are retrieved from queries, but are not in the desired format.
-    # item_sets = select(ItemSet).where(ItemSet.items.any(Item.id==item_id))
-    # flask_item_sets =  db.session.execute(item_sets).all()
-    # flask_item_set = flask_item_sets[0][0]
+def get_item_by_id(id):
+    return Item.query.get(id)
 
 
 def add_item(description, price, date_sold=None):
@@ -121,8 +108,26 @@ def add_item(description, price, date_sold=None):
     db.session.commit()
 
 
+def remove_item(item):
+    update_set(item)
+    db.session.delete(item)
+    db.session.commit()
+
+
+def remove_item_set(item):
+    db.session.delete(item)
+    db.session.commit()
+
+
+def sell_item(item, date=datetime.datetime.today()):
+    update_set(item)
+    item.date_sold = date
+    db.session.commit()
+
+
 def update_set(reference_item):
-    """Update the set that the passed item belongs to by removing it from the set and adding a similar item."""
+    """Update the set that the passed item belongs to by removing it from the set
+    and adding a similar item."""
 
     # We need the owning item set to avoid adding duplicates.
     owning_itemsets = get_itemsets_by_item_id(reference_item.id)
@@ -152,6 +157,3 @@ def update_set(reference_item):
 
 def get_item_by_id(id):
     return Item.query.get(id)
-
-
-