Hey Jamie,

I appreciate the response.

You are defining a custom create method on the Model class, and then dispatching the actual creation to the model Manager anyway. This is bad design — managers and .create() exist for a reason, so subclass and override them confidently

For me, this falls under seperation of concerns. I consider models and managers as responsible soley for integrating with the database. When I implement business logic I often do it in a designated function.

Generally speaking, I try to avoid overriding built-in functions such as create, save and delete. Especially when they might have side effects such as writing log records etc.

This is a much better solution, and because it is standardised many other packages you are using (like ModelForms and APIViews) can chain together failed validator attempts and give the end user a proper, comprehensive error message.

I agree that there are better ways to validate data. I usually use RPC rather than REST so I often use a serializer to validate incoming data. In this post I wanted to focus on the model.

There is 0 reason to be using custom exceptions here

I strongly disagree. I consider error messages an integral part of any API (and by API I mean any API — the model functions, RPC or REST).

I agree it might involve a bit more work to integrate into DRF or Django forms. I found custom error message to be very usefull.

You shouldn’t be implementing weird subclassed test methods like that.

They say the best way to test a code is to use it… This is why I usually create a “test client” for each model / business process I test and focus on testing the business logic. The test client is used to abstract the techincal bits (serialization, transport, etc) and help focus on what’s important. It also helps when you want to do some e2e testing, generate fixtures and provide sensible defaults.

I don’t think it can get any simpler than this:

self.deposit(100)
self.withdraw(50)
self.assertEqual(self.account.balance, 50)

I strongly encourage you to try this approach.

It is very, very rare that you should ever be passing static data like that to a test. That shows only that the number 100 might work, but not that 101 will.

I’m not sure what you mean by that. If you mean that the tests in the post are not covering all edge cases than you are right, they dont. It’s an example.

This article was written over a year ago and naturally some of our patterns have evolved. However, the concepts presented in the article lasted the test of time and proven them self as being both reliable and maintaiable.

Written by

Full Stack Developer, Team Leader, Independent. More from me at https://hakibenita.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store