Flask: View, model and business logic segration - python

Please help me how to solve following task in "pythonic" way:
There are several model classes, which are mapped to the DB with the help of SQLAlchemy.
There is a Flask view, which handles the "POST" request.
The business logic of this method contains complex logic which includes:
Getting input parameters from input JSON
Validation
Creation of several different models and the saving to database.
Is it a good idea to leave this logic in the "View"? Or it would be much better to separate this this logic into different modules or classes, for instance by introducing business logic class?

If you need to unit test the code separate from the View then you should defiantly separate it into another module or class.
As there seems to be three parts to your business logic then I would say starting by splitting the view into three functions of a module seems a good place to start.

Related

Modular python admin pages

I'm building a personal website that I need to apply modularity to it for purpose of learning. What it means is that there is a model that contains x number of classes with variations, as an example a button is a module that you can modify as much depending on provided attributes. I also have a pages model that need to select any of created modules and render it. I can't find any documentation of how to access multiple classes from one field to reference to.
Model structure is as below:
Modules, contains module A and module B
Pages should be able to select any of module A and order its structure.
Please let me know if not clear, this is the simplest form I could describe. Am I confusing this with meta classes? How one to achieve what I'm trying to achieve?
I ended up using Proxy models but will also try polymorphic approach. This is exactly what is designed to do, inherit models from a parent model in both one to many and many to many relationships.

django programming - "create" methods in admin, model or view

Baseline: I'm building a django based application that is heavily using the admin interface as it spares me a lot of work in developing own CRUD routines. By now I came across several situations where i have models that hold some general information (say parents) and often have foreignkey-relations to derived models (say childs).
I realized that i sometimes implemented my routines to create child objects within the admin-class, sometimes within the model class(method being called from within some admin routine) or sometimes even within view-classes (e.g. as reaction to POST requests on some custom forms). It feels now, that my design is not very consistent (the effects of changing some model parameters being distributed over a lot of files) and i should refactor before it gets to big a mess.
So what is the best approach? Where should one concentrate methods that create/modify related objects (keeping in mind that i often want to give some feedback-messages related to process) ?
If your code is about a Model class, add it to models.py. This makes sense when the classes have to be added to database (migrations)
If your code is related to views, attach it to views.py. This makes sense when the code handles requests.
If your code is related to admin, attach it to admins.py. This makes sense when the code is related to admin interface.
If your code is generic, used in multiple places, refactor it into a separate file, and import that file elsewhere.
Your use case isn't exactly clear to me, so I'm taking a stab in the dark here - You can have the Models in models.py and create a separate file to create objects for models with child objects containing the code that's related to creating parent-child objects with given data. Then use this as an import in the admin and views wherever applicable.
Something like:
# foo in views.py and admin.py
def foo():
data = {} # get all data
make_parent_child(data) # create parent-child objects

business logic in Django

I'd like to know where to put code that doesn't belong to a view, I mean, the logic.
I've been reading a few similar posts, but couldn't arrive to a conclusion.
What I could understand is:
A View is like a controller, and lot of logic should not put in the controller.
Models should not have a lot of logic either.
So where is all the logic based stuff supposed to be?
I'm coming from Groovy/Grails and for example if we need to access the DB or if we have a complex logic, we use services, and then those services are injected into the controllers.
Is it a good practice to have .py files containing things other than Views and Models in Django?
PS: I've read that some people use a services.py, but then other people say this is a bad practice, so I'm a little confused...
I don't know why you say
we can't put a lot of logic in the controller, and we cannot have the models with a lot of logic either
You can certainly put logic in either of those places. It depends to a great extent what that logic is: if it's specifically related to a single model class, it should go in the model. If however it's more related to a specific page, it can go in a view.
Alternatively, if it's more general logic that's used in multiple views, you could put it in a separate utility module. Or, you could use class-based views with a superclass that defines the logic, and subclasses which inherit from it.
Having a java background I can relate with this question.
I have been working on python for quite some time. Even though I do my best to treat Java as Java and Python as Python, some times I mix them both so that I can get a good deal out of both.
In short
Put all model related stuff in models app, it could be from simply models definition to custom save , pre save hooks .....
Put any request/ response related stuff in views, and some logic like verifying Jon schema, validation request body ... handling exceptions and so on ....
Put your business logic in separate folder/ app or module per views directory/ app. Meaning have separate middle module between your models and views.
There isn't strict rule to organise your code as long as you are consistent.
Project : Ci
Models: ci/model/device.py
Views: ci/views/list_device.py
Business logic:
(1) ci/business_logic/discover_device.py
Or
(2) ci/views/discover_device.py
Short answer: Django is more of a MTV or MVT (Model / Template / View), as described in the official FAQ : https://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names
The business logic has its place in your views, but nothing prevents you from putting it inside a "utils.py", "services.py" or anything to your liking.
If the functionality fits well as a method of some model instance, put it there. After all, models are just classes.
Otherwise, just write a Python module (some .py file) and put the code there, just like in any other Python library.
Don't put it in the views. Views should be the only part of your code that is aware of HTTP, and they should stay as small as possible.

Class Based Views VS Function Based Views

I always use FBVs (Function Based Views) when creating a django app because it's very easy to handle. But most developers said that it's better to use CBVs (Class Based Views) and use only FBVs if it is complicated views that would be a pain to implement with CBVs.
Why? What are the advantages of using CBVs?
The single most significant advantage is inheritance. On a large project it's likely that you will have lots of similar views. Rather than write the same code again and again, you can simply have your views inherit from a base view.
Also django ships with a collection of generic view classes that can be used to do some of the most common tasks. For example the DetailView class is used to pass a single object from one of your models, render it with a template and return the http response. You can plug it straight into your url conf..
url(r'^author/(?P<pk>\d+)/$', DetailView.as_view(model=Author)),
Or you could extend it with custom functionality
class SpecialDetailView(DetailView):
model = Author
def get_context_data(self, *args, **kwargs):
context = super(SpecialDetailView, self).get_context_data(*args, **kwargs)
context['books'] = Book.objects.filter(popular=True)
return context
Now your template will be passed a collection of book objects for rendering.
A nice place to start with this is having a good read of the docs (Django 4.0+).
Update
ccbv.co.uk has comprehensive and easy to use information about the class based views you already have available to you.
When I started with DJango I never used CBVs because of their learning curve and a bit complex structure. Fast forward over two years, I use FBVs only at few places. Where I am sure the code will be really simple and is going to stay simple.
Major benefit of CBVs and Multiple Inheritence that comes along with them is that I can completely avoid writing signals, helper methods and copy paste code. Especially in the cases where the app does much more than basic CRUD operations. Views with multiple inheritance are multiple times easier to debug that a code with signals and helper methods, especially if it is an unknown code base.
Apart from Multiple inheritence CBVs by provide different methods to do dispatching, retrieving templates, handling different request types, passing template context variables, validating forms, and much more out of the box. These make code modular and hence maintainable.
Some views are best implemented as CBVs, and others are best implemented as FBVs.
If you aren’t sure which method to choose, see the following chart:
SOME WORDS FROM TWO SCOOPS
Tip Alternative Apporach - Staying With FBVs
Some developer prefer to err on the side of using FBVs for most views and CBVs only for views that need to be subclassed. That strategy is fine as well.
Class based views are excellent if you want to implement a fully functional CRUD operations in your Django application, and the same will take little time & effort to implement using function based views.
I will recommend you to use function based views when you are not going to implement any CRUD on your site/application means your intension is to simply render the template.
I had created a simple CRUD based application using class based views which is live. Visit http://filtron.pythonanywhere.com/view/ (will/won't be working now) and enjoy. Then you will know the importance of it.
I have been using FBVs in most of the cases where I do not see a real opportunity of extending views. As documented in the docs, I consider going for CBVs if the following two characteristics suit my use-case.
Organization of code related to specific HTTP methods (GET, POST, etc.) can be addressed by separate methods instead of conditional branching.
Object oriented techniques such as mixins (multiple inheritance) can be used to factor code into reusable components.
Function-Based Views(FBVs) are:
Easy to use but the
Code is not reusable by inheritance.
Recommended to use
Class-Based Views(CBVs) are:
Too much learning curve because it's really complicated
Code is reusable by inheritance.
Not recommended to use (FBVs are much beter)

data validation for SQLAlchemy declarative models

I'm using CherryPy, Mako templates, and SQLAlchemy in a web app. I'm coming from a Ruby on Rails background and I'm trying to set up some data validation for my models. I can't figure out the best way to ensure, say, a 'name' field has a value when some other field has a value. I tried using SAValidation but it allowed me to create new rows where a required column was blank, even when I used validates_presence_of on the column. I've been looking at WTForms but that seems to involve a lot of duplicated code--I already have my model class set up with the columns in the table, why do I need to repeat all those columns again just to say "hey this one needs a value"? I'm coming from the "skinny controller, fat model" mindset and have been looking for Rails-like methods in my model like validates_presence_of or validates_length_of. How should I go about validating the data my model receives, and ensuring Session.add/Session.merge fail when the validations fail?
Take a look at the documentation for adding validation methods. You could just add an "update" method that takes the POST dict, makes sure that required keys are present, and uses the decorated validators to set the values (raising an error if anything is awry).
I wrote SAValidation for the specific purpose of avoiding code duplication when it comes to validating model data. It works well for us, at least for our use cases.
In our tests, we have examples of the model's setup and tests to show the validation works.
API Logic Server provides business rules for SQLAlchemy models. This includes not only multi-field, multi-table validations, but multi-table validations. It's open source.
I ended up using WTForms after all.

Categories