diff --git a/examples/bootstrap4/app.py b/examples/bootstrap4/app.py index cb08a91..193f3b7 100644 --- a/examples/bootstrap4/app.py +++ b/examples/bootstrap4/app.py @@ -271,10 +271,32 @@ def edit_message(message_id): def delete_message(message_id): message = Message.query.get(message_id) if message: + # Get current page from referrer or request args + current_page = request.args.get('page', 1, type=int) + if request.referrer and 'page=' in request.referrer: + # Extract page number from referrer URL + import re + page_match = re.search(r'[?&]page=(\d+)', request.referrer) + if page_match: + current_page = int(page_match.group(1)) + + # Delete the message db.session.delete(message) db.session.commit() - return f'Message {message_id} has been deleted. Return to table.' - return f'Message {message_id} did not exist and could therefore not be deleted. Return to table.' + + # Calculate total remaining messages and pages + total_messages = Message.query.count() + per_page = 10 # Same as used in test_table route + total_pages = max(1, (total_messages + per_page - 1) // per_page) # At least page 1 + + # Determine which page to redirect to + redirect_page = min(current_page, total_pages) + + flash(f'Message {message_id} has been deleted.', 'success') + return redirect(url_for('test_table', page=redirect_page)) + else: + flash(f'Message {message_id} did not exist and could therefore not be deleted.', 'warning') + return redirect(url_for('test_table')) @app.route('/table//like') diff --git a/examples/bootstrap5/app.py b/examples/bootstrap5/app.py index 0abe6d2..ec2633a 100644 --- a/examples/bootstrap5/app.py +++ b/examples/bootstrap5/app.py @@ -295,10 +295,32 @@ def edit_message(message_id): def delete_message(message_id): message = Message.query.get(message_id) if message: + # Get current page from referrer or request args + current_page = request.args.get('page', 1, type=int) + if request.referrer and 'page=' in request.referrer: + # Extract page number from referrer URL + import re + page_match = re.search(r'[?&]page=(\d+)', request.referrer) + if page_match: + current_page = int(page_match.group(1)) + + # Delete the message db.session.delete(message) db.session.commit() - return f'Message {message_id} has been deleted. Return to table.' - return f'Message {message_id} did not exist and could therefore not be deleted. Return to table.' + + # Calculate total remaining messages and pages + total_messages = Message.query.count() + per_page = 10 # Same as used in test_table route + total_pages = max(1, (total_messages + per_page - 1) // per_page) # At least page 1 + + # Determine which page to redirect to + redirect_page = min(current_page, total_pages) + + flash(f'Message {message_id} has been deleted.', 'success') + return redirect(url_for('test_table', page=redirect_page)) + else: + flash(f'Message {message_id} did not exist and could therefore not be deleted.', 'warning') + return redirect(url_for('test_table')) @app.route('/table//like') diff --git a/tests/test_bootstrap4/test_render_pagination.py b/tests/test_bootstrap4/test_render_pagination.py index e853584..24548fb 100644 --- a/tests/test_bootstrap4/test_render_pagination.py +++ b/tests/test_bootstrap4/test_render_pagination.py @@ -1,4 +1,4 @@ -from flask import render_template_string, request +from flask import render_template_string, request, redirect, url_for, flash from flask_sqlalchemy import SQLAlchemy @@ -36,3 +36,108 @@ def test(): assert '1' in data assert '2 (current)' in data assert '10' in data + + +def test_pagination_after_delete(app, client): # noqa: C901 + """Test that pagination works correctly after deleting items.""" + db = SQLAlchemy(app) + + class Message(db.Model): + id = db.Column(db.Integer, primary_key=True) + text = db.Column(db.String(100)) + + @app.route('/table') + def test_table(): + page = request.args.get('page', 1, type=int) + pagination = Message.query.paginate(page=page, per_page=10) + messages = pagination.items + return render_template_string(''' + Page {{ pagination.page }} of {{ pagination.pages }} + Total: {{ pagination.total }} + Messages: {{ messages|length }} + ''', pagination=pagination, messages=messages) + + @app.route('/table//delete', methods=['POST']) + def delete_message(message_id): + message = Message.query.get(message_id) + if message: + # Get current page from request args or referrer + current_page = request.args.get('page', 1, type=int) + if request.referrer and 'page=' in request.referrer: + import re + page_match = re.search(r'[?&]page=(\d+)', request.referrer) + if page_match: + current_page = int(page_match.group(1)) + + # Delete the message + db.session.delete(message) + db.session.commit() + + # Calculate total remaining messages and pages + total_messages = Message.query.count() + per_page = 10 + total_pages = (total_messages + per_page - 1) // per_page if total_messages > 0 else 1 + + # Determine which page to redirect to + redirect_page = current_page + if total_pages == 0 or total_messages == 0: + redirect_page = 1 + elif current_page > total_pages: + redirect_page = total_pages + + flash(f'Message {message_id} has been deleted.', 'success') + return redirect(url_for('test_table', page=redirect_page)) + else: + flash(f'Message {message_id} did not exist.', 'warning') + return redirect(url_for('test_table')) + + with app.app_context(): + # Test Case 1: Delete from middle page - should stay on same page + db.drop_all() + db.create_all() + for i in range(25): # Create 25 messages (3 pages of 10 each, 5 on last page) + msg = Message(text=f'Message {i+1}') + db.session.add(msg) + db.session.commit() + + # Go to page 2 and delete a message + response = client.get('/table?page=2') + assert 'Page 2 of 3' in response.get_data(as_text=True) + + # Delete message ID 15 (should be on page 2) + response = client.post('/table/15/delete?page=2', follow_redirects=True) + data = response.get_data(as_text=True) + assert 'Page 2 of 3' in data # Should still be on page 2 + assert 'Total: 24' in data # One less message + + # Test Case 2: Delete all items from last page - should redirect to previous page + db.drop_all() + db.create_all() + for i in range(21): # Create 21 messages (3 pages: 10, 10, 1) + msg = Message(text=f'Message {i+1}') + db.session.add(msg) + db.session.commit() + + # Go to page 3 (last page with 1 item) + response = client.get('/table?page=3') + data = response.get_data(as_text=True) + assert 'Page 3 of 3' in data + assert 'Total: 21' in data + + # Delete the only message on page 3 + response = client.post('/table/21/delete?page=3', follow_redirects=True) + data = response.get_data(as_text=True) + assert 'Page 2 of 2' in data # Should redirect to page 2 + assert 'Total: 20' in data # One less message + + # Test Case 3: Delete all messages - should go to page 1 + db.drop_all() + db.create_all() + msg = Message(text='Last message') + db.session.add(msg) + db.session.commit() + + response = client.post('/table/1/delete', follow_redirects=True) + data = response.get_data(as_text=True) + assert 'Page 1 of' in data # Should be on page 1 (could be "Page 1 of 0" or "Page 1 of 1") + assert 'Total: 0' in data # No messages left diff --git a/tests/test_bootstrap5/test_pagination.py b/tests/test_bootstrap5/test_pagination.py index 2df3bae..ef63589 100644 --- a/tests/test_bootstrap5/test_pagination.py +++ b/tests/test_bootstrap5/test_pagination.py @@ -1,4 +1,4 @@ -from flask import render_template_string, request +from flask import render_template_string, request, redirect, url_for, flash from flask_sqlalchemy import SQLAlchemy @@ -30,3 +30,108 @@ def test(): assert '1 (current)' not in data assert '
  • ' in data assert '1' in data + + +def test_pagination_after_delete(app, client): # noqa: C901 + """Test that pagination works correctly after deleting items.""" + db = SQLAlchemy(app) + + class Message(db.Model): + id = db.Column(db.Integer, primary_key=True) + text = db.Column(db.String(100)) + + @app.route('/table') + def test_table(): + page = request.args.get('page', 1, type=int) + pagination = Message.query.paginate(page=page, per_page=10) + messages = pagination.items + return render_template_string(''' + Page {{ pagination.page }} of {{ pagination.pages }} + Total: {{ pagination.total }} + Messages: {{ messages|length }} + ''', pagination=pagination, messages=messages) + + @app.route('/table//delete', methods=['POST']) + def delete_message(message_id): + message = Message.query.get(message_id) + if message: + # Get current page from request args or referrer + current_page = request.args.get('page', 1, type=int) + if request.referrer and 'page=' in request.referrer: + import re + page_match = re.search(r'[?&]page=(\d+)', request.referrer) + if page_match: + current_page = int(page_match.group(1)) + + # Delete the message + db.session.delete(message) + db.session.commit() + + # Calculate total remaining messages and pages + total_messages = Message.query.count() + per_page = 10 + total_pages = (total_messages + per_page - 1) // per_page if total_messages > 0 else 1 + + # Determine which page to redirect to + redirect_page = current_page + if total_pages == 0 or total_messages == 0: + redirect_page = 1 + elif current_page > total_pages: + redirect_page = total_pages + + flash(f'Message {message_id} has been deleted.', 'success') + return redirect(url_for('test_table', page=redirect_page)) + else: + flash(f'Message {message_id} did not exist.', 'warning') + return redirect(url_for('test_table')) + + with app.app_context(): + # Test Case 1: Delete from middle page - should stay on same page + db.drop_all() + db.create_all() + for i in range(25): # Create 25 messages (3 pages of 10 each, 5 on last page) + msg = Message(text=f'Message {i+1}') + db.session.add(msg) + db.session.commit() + + # Go to page 2 and delete a message + response = client.get('/table?page=2') + assert 'Page 2 of 3' in response.get_data(as_text=True) + + # Delete message ID 15 (should be on page 2) + response = client.post('/table/15/delete?page=2', follow_redirects=True) + data = response.get_data(as_text=True) + assert 'Page 2 of 3' in data # Should still be on page 2 + assert 'Total: 24' in data # One less message + + # Test Case 2: Delete all items from last page - should redirect to previous page + db.drop_all() + db.create_all() + for i in range(21): # Create 21 messages (3 pages: 10, 10, 1) + msg = Message(text=f'Message {i+1}') + db.session.add(msg) + db.session.commit() + + # Go to page 3 (last page with 1 item) + response = client.get('/table?page=3') + data = response.get_data(as_text=True) + assert 'Page 3 of 3' in data + assert 'Total: 21' in data + + # Delete the only message on page 3 + response = client.post('/table/21/delete?page=3', follow_redirects=True) + data = response.get_data(as_text=True) + assert 'Page 2 of 2' in data # Should redirect to page 2 + assert 'Total: 20' in data # One less message + + # Test Case 3: Delete all messages - should go to page 1 + db.drop_all() + db.create_all() + msg = Message(text='Last message') + db.session.add(msg) + db.session.commit() + + response = client.post('/table/1/delete', follow_redirects=True) + data = response.get_data(as_text=True) + assert 'Page 1 of' in data # Should be on page 1 (could be "Page 1 of 0" or "Page 1 of 1") + assert 'Total: 0' in data # No messages left