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 9de8bb8dc83b5c38a249f8ad2c36b6c448f5c897..b2c7d6208a05cb7e80273d2aa9d32bd2964d7f3e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,4 +3,5 @@ Flask_SQLAlchemy
 Flask_WTF
 WTForms
 flask_login
-flask_mail
\ No newline at end of file
+flask_mail
+black
\ No newline at end of file
diff --git a/store/forms.py b/store/forms.py
index ec125c50b01db198e8520e6836d8a0bf19e113d9..25703edb29161a1b947c64b5af21ad6452de58a4 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,9 @@ class LoginForm(FlaskForm):
 class SearchForm(FlaskForm):
     query = StringField("Query", [validators.DataRequired()])
     submit = SubmitField("Submit")
+
+
+class AccessDataForm(FlaskForm):
+    table = SelectField("Table", choices=["Item", "Item Set"])
+    id = IntegerField("ID", [validators.DataRequired()])
+    submit = SubmitField("Submit")
diff --git a/store/routes.py b/store/routes.py
index e63b9cc3fd83d4fe3871c7446eac7ef1bccb2779..f29e07370703ab43c4ce7ef88076d1310c8231b9 100644
--- a/store/routes.py
+++ b/store/routes.py
@@ -1,10 +1,20 @@
 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,
+)
 import json
 from store.utility import *
 from store.forms import *
 import string
 import random
+import sys
 
 
 # Official flask-login doc free liecense
@@ -318,6 +328,92 @@ 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("/add_item", methods=["POST"])
+# def add_item():
+#     if current_user.userType != "admin":
+#         flash("Unauthorized access")
+#         return redirect(url_for("home"))
+
+
+@app.route("/delete_item", methods=["POST"])
+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:
+        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():
@@ -435,7 +531,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..1632a25a1e3a468e36006d27e44172a27e929746 100644
--- a/store/templates/userContent/admin.html
+++ b/store/templates/userContent/admin.html
@@ -6,5 +6,6 @@
 <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')}}">View database management</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..6f9e013e8be21262d407b955f217c5f9cac2866f
--- /dev/null
+++ b/store/templates/userContent/database_management.html
@@ -0,0 +1,100 @@
+{% 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 class="loginTable">
+            <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 main_item.items %}
+    <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>
+                </tr>
+                <button onclick="deleteItemFromSet({{item.id}}, {{main_item.id}})">Delete</button>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+    {% endif %}
+</div>
+{% endif %}
+
+<script>
+    function deleteItem(id) {
+        if (confirm("Are you sure you want to delete this item? It is irreversible.")) {
+            $.ajax({
+                url: '/delete_item',
+                type: 'POST',
+                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/utility.py b/store/utility.py
index aae06c2a84caa914ac84e37bfaf957b068039aba..a7e9fea0bd3f0752f176913bbf96c86988410183 100644
--- a/store/utility.py
+++ b/store/utility.py
@@ -76,12 +76,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.
@@ -103,15 +97,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):
@@ -120,8 +107,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)
@@ -147,7 +152,3 @@ def update_set(reference_item):
         itemset.items.remove(reference_item)
         itemset.items.append(similar_items[0])
     db.session.commit()
-
-
-def get_item_by_id(id):
-    return Item.query.get(id)