- version : 1.2

- description : adding a delete route and the corresponding button in
  the html file .
هذا الالتزام موجود في:
2025-06-12 15:58:27 +03:00
الأصل e96de0d016
التزام ad95102ae9
2 ملفات معدلة مع 63 إضافات و27 حذوفات

19
app.py
عرض الملف

@@ -214,6 +214,25 @@ def modify_student(student_id):
return redirect(url_for('index'))
@app.route('/delete_student/<int:student_id>', methods=['POST'])
def delete_student(student_id):
try:
with get_db_connection() as conn:
# First, check if the student exists
student = conn.execute('SELECT id FROM students WHERE id = ?', (student_id,)).fetchone()
if student is None:
flash('الطالب غير موجود.', 'danger')
return redirect(url_for('index'))
conn.execute('DELETE FROM students WHERE id = ?', (student_id,))
conn.commit()
flash('تم حذف الطالب بنجاح!', 'success')
except sqlite3.Error as e:
flash(f'خطأ في قاعدة البيانات أثناء الحذف: {str(e)}', 'danger')
except Exception as e:
flash(f'خطأ غير متوقع أثناء الحذف: {str(e)}', 'danger')
return redirect(url_for('index'))
@app.route('/import_csv', methods=['POST'])
def import_csv():

عرض الملف

@@ -5,7 +5,7 @@
{% block content %}
<header class="text-center"> {# Removed mb-8 from header, now handled by h1 and nav #}
<h1 class="text-3xl sm:text-4xl font-bold text-gray-900 mb-6">نظام إدارة الطلاب</h1> {# Added mb-6 for spacing below title #}
{# Navigation Bar - More Eye-Attractive Styling #}
<nav class="mb-8"> {# Kept mb-8 for space below nav #}
<ul class="flex justify-center space-x-4 space-x-reverse bg-white p-2 rounded-full shadow-lg inline-flex"> {# Added padding, background, rounded corners, shadow, and inline-flex for better alignment #}
@@ -77,7 +77,7 @@
</div>
</form>
</div>
<div class="bg-white p-6 rounded-xl shadow-lg mb-8">
<h2 class="text-2xl font-semibold mb-4 text-gray-800 border-b pb-4">استيراد من ملف CSV</h2>
<div class="bg-yellow-50 border border-yellow-200 text-yellow-800 text-sm p-4 rounded-lg mt-4">
@@ -119,7 +119,7 @@
إضافة يدوية
</button>
</div>
{# Search input box for fuzzy finding #}
<div class="mb-6">
<label for="search-input" class="sr-only">البحث عن طالب</label>
@@ -131,7 +131,7 @@
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">#</th>
<th class="px-6 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">الإجراءات</th>
<th class="px-6 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">الإجراءات</th> {# Moved this header here #}
<th class="px-6 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">اسم الطالب</th>
<th class="px-6 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">العمر</th>
<th class="px-6 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">ولي الأمر</th>
@@ -145,12 +145,21 @@
<tbody class="bg-white divide-y divide-gray-200" id="students-table-body">
{% for student in students %}
<tr class="hover:bg-gray-50 transition-colors duration-200">
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-gray-700">{{ loop.index }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-gray-700">{{ loop.index }}</td>
{# Moved the actions column here #}
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<a href="{{ url_for('modify_student', student_id=student['id']) }}" class="text-indigo-600 hover:text-indigo-900">
<i class="fas fa-pen"></i> {# Pen icon #}
<a href="{{ url_for('modify_student', student_id=student['id']) }}" class="text-indigo-600 hover:text-indigo-900 mx-1">
<i class="fas fa-pen" title="تعديل"></i> {# Pen icon #}
</a>
{# You can add a delete button here later if needed #}
<a href="#" onclick="confirmDelete({{ student['id'] }}, '{{ student['student_name'] }}')" class="text-red-600 hover:text-red-900 mx-1">
<i class="fas fa-trash-alt" title="حذف"></i> {# Trash can icon #}
</a>
{# A hidden form for deletion, used by JavaScript.
In a real application, consider adding a CSRF token for security. #}
<form id="delete-form-{{ student['id'] }}" action="{{ url_for('delete_student', student_id=student['id']) }}" method="POST" style="display: none;">
{# Example for CSRF token (requires Flask-WTF or similar setup): #}
{# <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> #}
</form>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ student['student_name'] }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ student['age'] }}</td>
@@ -206,11 +215,11 @@
}
allStudentData.push({
element: row,
student_name: row.children[1] ? row.children[1].textContent : '',
parent_name: row.children[3] ? row.children[3].textContent : '',
student_name: row.children[2] ? row.children[2].textContent : '', // Adjusted index for student_name
parent_name: row.children[4] ? row.children[4].textContent : '', // Adjusted index for parent_name
// Store original HTML of potentially highlighted cells to restore them later
originalStudentNameHTML: row.children[1] ? row.children[1].innerHTML : '',
originalParentNameHTML: row.children[3] ? row.children[3].innerHTML : ''
originalStudentNameHTML: row.children[2] ? row.children[2].innerHTML : '', // Adjusted index
originalParentNameHTML: row.children[4] ? row.children[4].innerHTML : '' // Adjusted index
});
});
@@ -257,11 +266,11 @@
allStudentData.forEach(data => {
data.element.classList.remove('hidden');
// Restore original HTML for highlighted cells
if (data.element.children[1]) {
data.element.children[1].innerHTML = data.originalStudentNameHTML;
if (data.element.children[2]) { // Adjusted index
data.element.children[2].innerHTML = data.originalStudentNameHTML;
}
if (data.element.children[3]) {
data.element.children[3].innerHTML = data.originalParentNameHTML;
if (data.element.children[4]) { // Adjusted index
data.element.children[4].innerHTML = data.originalParentNameHTML;
}
});
noSearchResultsDiv.classList.add('hidden'); // Hide no results message
@@ -285,21 +294,21 @@
foundResults++;
// Apply highlighting to the student name cell
if (data.element.children[1]) {
data.element.children[1].innerHTML = highlightText(studentName, searchTerm);
if (data.element.children[2]) { // Adjusted index
data.element.children[2].innerHTML = highlightText(studentName, searchTerm);
}
// Apply highlighting to the parent name cell
if (data.element.children[3]) {
data.element.children[3].innerHTML = highlightText(parentName, searchTerm);
if (data.element.children[4]) { // Adjusted index
data.element.children[4].innerHTML = highlightText(parentName, searchTerm);
}
} else {
data.element.classList.add('hidden'); // Hide the row
// Restore original content if the row is hidden
if (data.element.children[1]) {
data.element.children[1].innerHTML = data.originalStudentNameHTML;
if (data.element.children[2]) { // Adjusted index
data.element.children[2].innerHTML = data.originalStudentNameHTML;
}
if (data.element.children[3]) {
data.element.children[3].innerHTML = data.originalParentNameHTML;
if (data.element.children[4]) { // Adjusted index
data.element.children[4].innerHTML = data.originalParentNameHTML;
}
}
});
@@ -325,11 +334,11 @@
if (csvFileInput.files.length > 0) {
const fileName = csvFileInput.files[0].name;
fileNameDisplay.textContent = `الملف المختار: ${fileName}`;
// Show the file name display and the submit button
fileNameDisplay.classList.remove('hidden');
submitImportButton.classList.remove('hidden');
// Hide the original "Choose File" button to avoid confusion
chooseFileButton.classList.add('hidden');
} else {
@@ -358,5 +367,13 @@
submitAddButton.disabled = true;
submitAddButton.textContent = 'جاري الحفظ...'; // "Saving..."
});
// --- New JavaScript for Delete Confirmation ---
function confirmDelete(studentId, studentName) {
if (confirm(`هل أنت متأكد أنك تريد حذف الطالب "${studentName}"؟ هذا الإجراء لا يمكن التراجع عنه.`)) {
// If confirmed, submit the hidden form for deletion
document.getElementById(`delete-form-${studentId}`).submit();
}
}
</script>
{% endblock %}
{% endblock %}