Skip to content

Add courses in bulk from a spreadsheet - #1981

Merged
vikrantwiz02 merged 1 commit into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:acad-bulk-add-courses
Sep 3, 2026
Merged

Add courses in bulk from a spreadsheet#1981
vikrantwiz02 merged 1 commit into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:acad-bulk-add-courses

Conversation

@vikrantwiz02

Copy link
Copy Markdown
Member

Setting up a session meant adding courses one at a time through the proposal form. POST /programme_curriculum/api/admin_add_courses_bulk/ takes a file instead — one row per course — gated to acadadmin and Dean Academic like the single-add view, and writing the same audit log entry per course.

Reads .xlsx, .xls and .csv. All three deliberately: a file named .xlsx is frequently a legacy .xls, which xlrd alone rejects.

Required Optional (falls back to the model default)
Course Code, Course Name, Credits, Max Seats, Disciplines Version, Lecture / Tutorial / Practical / Discussion / Project Hours, Pre-requisites, Syllabus, Reference Books

The seven assessment percentages are deliberately not columns. CourseForm requires them to total exactly 100 and the model defaults already do, so the sheet stays short and the invariant holds by construction. The bulk path therefore builds the model directly with explicit per-field validation instead of going through the form, and each check reports its own message.

A course shared across disciplines lists them in one cell. Semicolons and pipes are accepted besides commas, because a comma inside a cell has to be quoted in a CSV and that is easy to get wrong by hand; matching ignores case and punctuation, since one acronym in the table is Des. with a trailing dot.

Verified against a restored copy of the live database, inside rolled-back transactions.

Formats and failures:

xlsx / xls / csv        201, 2 created each
mixed good and bad      207, 2 created, 4 skipped
  Max Seats is blank.
  Disciplines is blank.
  no discipline named Nope Dept.
  Max Seats 'many' is not a number.
re-upload the same file 400, every row reported as already existing
header with no rows     400
unrecognised heading    returned in unknown_columns

Disciplines, every spelling:

"CSE, ME"        -> CSE, ME          "cse, me"       -> CSE, ME
"CSE;ME;ECE"     -> CSE, ECE, ME     "Des." / "Des"  -> Des.
"CSE|NS"         -> CSE, NS          full names      -> CSE, NS
"CSE, CSE, cse"  -> CSE (deduped)    "CSE, Astrology" -> row rejected

A row naming one unknown discipline is rejected whole rather than saved with a partial set, and the unknown name is echoed back as typed. Each row commits in its own savepoint, so one bad row cannot take down the batch, and the counts come from the table rather than the length of the list.

manage.py check clean, no migration. Pairs with the client PR adding the Bulk Add button.

Setting up a session meant adding courses one at a time through the
proposal form. This takes a file instead: one row per course, reading
.xlsx, .xls or .csv, since a file named .xlsx is often really an .xls.

Course code, name, credits, max seats and disciplines are required. The
rest are optional and fall back to the model defaults, which is what
keeps the seven assessment percentages adding up to 100 without the
office carrying seven more columns. A course shared across disciplines
lists them in one cell separated by semicolons, commas or pipes, matched
without regard to case or punctuation so Des., Des and des all resolve.

Each row commits in its own savepoint, so one bad row cannot take down
the batch, and the count reported is what the table accepted rather than
the length of the list. Every failure names the row and what is wrong
with it. Courses created this way get the same audit log entry as one
added through the form.
@vikrantwiz02
vikrantwiz02 merged commit 1fbaea2 into FusionIIIT:prod/acad-react Sep 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant