Package: django-ninja-crud
Django Ninja CRUDDjango Ninja CRUD is adeclarative, powerful, and yet opinionated framework that simplifies the development ofCRUD(Create,Read,Update,Delete) views and tests withDjango Ninja.
It promotes best practices for efficient, robust endpoint creation, allowing you to focus on what matters most: solving real problems.
Initially inspired by DRF'sModelViewSet, Django Ninja CRUD evolved to address its limitations, adopting acomposition-over-inheritanceapproach to achieve true modularity – a foundational step towards a broader declarative interface for endpoint creation.✨ Key FeaturesPurely Declarative: Embrace an approach where defining views and tests is a matter of declaring what you want, not how to achieve it.Unmatched Modularity: Tailor your viewsets with the desired CRUD views and customize each view's behavior with ease. Extend the flexibility by creating your own subclasses of the provided views and tests.Powerful Testing Framework: Leverage a matrix-based testing framework for defining diverse test scenarios declaratively.Focus on What Matters: Spend more time solving real-world problems and less on CRUD boilerplate.Its blend of declarative syntax, modularity, and powerful testing capabilities sets a new standard for developers seeking efficiency and precision.Django Ninja CRUD is not just a tool; it's a paradigm shift in Django web application development and testing.📝 Requirements⚒️ Installationpipinstalldjango-ninja-crudFor more information, see theinstallation guide.👨‍🎨 ExampleUsageLet's imagine you're building a system for a university and you have a model calledDepartment. Each department in your university has a unique title.# examples/models.pyfromdjango.dbimportmodelsclassDepartment(models.Model):title=models.CharField(max_length=255,unique=True)To interact with this data, we need a way to convert it between Python objects and a format that's easy to read and write (like JSON). In Django Ninja, we do this withSchema:# examples/schemas.pyfromninjaimportSchemaclassDepartmentIn(Schema):title:strclassDepartmentOut(Schema):id:inttitle:strTheDepartmentInschema defines what data we need when creating or updating a department. TheDepartmentOutschema defines what data we'll provide when retrieving a department.Now, here comes the power of Django Ninja CRUD. With it, you can set up theCRUDoperations for theDepartmentmodel with just a few lines of code:# examples/views/department_views.pyfromdjango.httpimportHttpRequestfromninjaimportRouterfromninja_crudimportviews,viewsetsfromexamples.modelsimportDepartmentfromexamples.schemasimportDepartmentIn,DepartmentOutrouter=Router()classDepartmentViewSet(viewsets.ModelViewSet):model=Departmentdefault_input_schema=DepartmentIndefault_output_schema=DepartmentOutlist_view=views.ListModelView()create_view=views.CreateModelView()retrieve_view=views.RetrieveModelView()update_view=views.UpdateModelView()delete_view=views.DeleteModelView()# The register_routes method must be called to register the routesDepartmentViewSet.register_routes(router)# Beyond the CRUD operations managed by the viewset,# the router can be used in the standard Django Ninja way@router.get("/statistics/",response=dict)defretrieve_department_statistics(request:HttpRequest):return{"total":Department.objects.count()}TestingA key advantage of this package is that it makes your views easy to test. Once you've set up yourCRUDoperations, you can write tests to ensure they're working as expected. Here's an example of how you might test theDepartmentoperations:# examples/tests/test_department_views.pyfromninja_crudimporttestingfromexamples.modelsimportDepartmentfromexamples.views.department_viewsimportDepartmentViewSetclassTestDepartmentViewSet(testing.viewsets.ModelViewSetTestCase):model_viewset_class=DepartmentViewSetbase_path="api/departments"@classmethoddefsetUpTestData(cls):cls.department_1=Department.objects.create(title="department-1")cls.department_2=Department.objects.create(title="department-2")@propertydefpath_parameters(self):returntesting.components.PathParameters(ok={"id":self.department_1.id},not_found={"id":9999})@propertydefpayloads(self):returntesting.components.Payloads(ok={"title":"department-3"},bad_request={},conflict={"title":self.department_2.title},)test_list_view=testing.views.ListModelViewTest()test_create_view=testing.views.CreateModelViewTest(payloads)test_retrieve_view=testing.views.RetrieveModelViewTest(path_parameters)test_update_view=testing.views.UpdateModelViewTest(path_parameters,payloads)test_delete_view=testing.views.DeleteModelViewTest(path_parameters)# You can then add additional tests as neededdeftest_retrieve_department_statistics(self):response=self.client.get(f"{self.base_path}/statistics/")self.assertEqual(response.status_code,200)...# Additional assertions📚 DocumentationFor more information, see thedocumentation.🫶 SupportFirst and foremost, a heartfelt thank you for taking an interest in this project. If it has been helpful to you or you believe in its potential, kindly consider giving it a star on GitHub. Such recognition not only fuels my drive to maintain and improve this work but also makes it more visible to new potential users and contributors.If you've benefited from this project or appreciate the dedication behind it, consider showing further support. Whether it's the price of a coffee, a word of encouragement, or a sponsorship, every gesture adds fuel to the open-source fire, making it shine even brighter. ✨Your kindness and support make a world of difference. Thank you! 🙏