NDjango.RestFramework — a C#/.NET port of DRF's conventions #9971
Replies: 2 comments 3 replies
-
|
One more thing worth mentioning for anyone who lands here from a Django/Python background: there's a sibling project in the same org that tackles the other half of the Django experience — the admin site. NDjango.Admin is a Django-admin-inspired auto-generated admin dashboard for ASP.NET Core. Same spirit as the library above: take an idiom Django users already have in their heads and make it native in .NET. You register it with one line over your A few details that might matter to people coming from Django Admin specifically:
Both libraries are pre-1.0 and the same "look at the tests / sample projects" caveat applies. Sharing it here in case anyone reading this thread is also missing the Django Admin side of the story in .NET — happy to hear feedback there too. |
Beta Was this translation helpful? Give feedback.
-
|
With all due respect, I ask, “Why are you trying to reinvent the wheel?” Speaking purely objectively, I ask, “When might a company or individual need this project?” For a company that started out using Python, switching to C# is a major risk, and I can’t say I’ve ever seen a company make that decision before. The DRF project has dozens of maintainers, yet it has faced issues with inactivity in recent years. Given that such problems can arise even with a project this popular, expecting someone from the group of people who “know C# but want to use Django, yet feel compelled to use .NET due to the requirement to use C#” to support this project (it’s great that you’ve started working on the project today, but who can guarantee you’ll still be willing to be a developer in the future?) seems a bit too optimistic to me. When viewed from a C# perspective, this structure reveals a significant inconsistency. Generally, the C# community is (naturally) eager to follow what is known as the “Microsoft path.” This is somewhat akin to the paradox of saying, “I want to break my chains, but I like the chains.” From a technical perspective, Python is a dynamic language (duck typing), while C# is a static and strict language. Trying to emulate Python’s flexibility in C# sometimes results in complex “generic” structures. If the library hits a roadblock at some point, you’ll need to know both DRF and decipher how the author adapted it to C# to resolve the issue. If I found myself sitting across from this table one day and had to make a decision as an architect, I would either opt for using DRF with Python or decide to write in C# with ASP.NET. While your experimental work is commendable, it feels like the metaphor of a force a whale up a tree. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
Long-time DRF user here. I wanted to share a project that's been brewing for a while: NDjango.RestFramework — a port of DRF's conventions to C# / ASP.NET Core + EF Core.
It's not a rewrite of DRF, and it doesn't try to be a one-to-one clone. The goal is narrower: take the vocabulary and ergonomics DRF users already have in their heads —
Serializer,perform_create/perform_update/perform_destroy,validate_<field>+validate(),partial=True, queryset-scoped writes,PageNumberPaginationresponse shape — and make them feel native in idiomatic C# (generics instead of duck typing,IQueryable<T>instead ofQuerySet,Taskinstead of sync views).What that looks like in practice
A
BaseController<TOrigin, TDestination, TPrimaryKey, TContext>gives you the standard CRUD surface in one declaration — list (with filters / search / sort / pagination), retrieve, create, update, partial update, delete, and an opt-in bulk delete. ThePageNumberPaginationresponse shape matches DRF's exactly (count/next/previous/results), and PATCH semantics are DRF-faithful via aPartialJsonObject<T>that tracks which fields were actually sent.The seams DRF users reach for are all there:
perform_create/perform_update/perform_destroy→PerformCreateAsync/PerformUpdateAsync/PerformDestroyAsyncon the controller.validate_<field>→ auto-discoveredValidate{Field}Asynchooks on the serializer, with aValidationContextthat exposesOperation/IsCreate/IsPartialUpdate/IsSet(field).validate()→ anoverride ValidateAsync(...)cross-field hook that only runs if per-field hooks passed.get_object→ a queryset-naiveSerializer.GetObjectAsync(query, id, ct)that the controller composes onto its filter chain before every write, so a tenant/soft-delete filter protectsPUT/PATCH/DELETEthe same way it protects reads.A deliberate divergence worth flagging: there's no HTTP bulk-update verb, mirroring DRF's stance that
ListSerializer.updateraisesNotImplementedErrorbecause broadcasting one body to many rows is mass-assignment, not a generic update. Headless callers (consumers, jobs) can still callSerializer.UpdateManyAsyncdirectly.Learn by reading and running it
If you'd rather see this than read about it, the repo ships two things that exist precisely so newcomers don't have to take the README on faith:
./sample-project— a small ASP.NET Core service backed by SQL Server that uses the library the way a real consumer would. It models a tiny restaurant domain (Categories, Restaurants + nested RestaurantProfile, MenuItems, Ingredients, Tags, AuditLogs, TenantNotes, Gifts) and intentionally exercises one DRF idiom per resource:Tags— per-fieldValidate{Name,Slug}Asynchooks that normalize (trim / lowercase / dash-collapse) and do an async DB uniqueness check.AuditLogs—ActionOptionsgating, so PATCH / PUT / DELETE return405while still showing up in OpenAPI.TenantNotes— aTenantNoteTenantFilterscoping by anX-Tenantheader, demonstrating that the same filter chain protects writes (PUT/PATCH/DELETE/ bulk-DELETE), not just reads — DRF'sget_objectbehavior translated to EF CoreIQueryable.Restaurants—GetFields()nested-field projection ("RestaurantProfile:Website") for trimming serialized output without writing a custom serializer.Gifts— a wide CLR-primitive surface (Guid,decimal,DateOnly,TimeOnly,TimeSpan,DateTimeOffset, …) to show the OpenAPI / serialization story for every common type../playwright— a Playwright end-to-end suite that drives the sample over real HTTP. The specs are organized by capability rather than by resource, so each file reads as executable documentation for a feature:crud.spec.ts,list-features.spec.ts(filter / search / sort / pagination),queryset-scope.spec.ts(out-of-scope ids →404on writes, silently dropped on bulk delete),tags.spec.ts(hook validation + normalization round-trip),audit-logs.spec.ts(405gating),restaurants-nested.spec.ts, andopenapi.spec.ts(contract assertions on the generated document).docker compose up -d db && cd playwright && npm install && npm test— the test runner brings the sample up itself.Why share it here
Mostly because the design has been guided by DRF's source at tag
3.17.1— the mixins, the serializer pipeline, the pagination contract — and I'd rather the DRF community knows it exists than not. If anyone here has had to bounce between Django and .NET shops, hopefully this softens the landing.The library is still pre-1.0 and explicitly not recommended for production yet (the README says so). Issues, ideas, and "this would have been more DRF-like if you'd done X" feedback are all very welcome.
Beta Was this translation helpful? Give feedback.
All reactions