I am new to Django, but I recently created my first application. I am wondering if I put my logic in the wrong places. From the Django book, I got that logic should but put into the views and data in models. But I have recently read that views should be as small as possible and let models handle the logic. My problem is my views handle all my logic while my models only handle data going to and from my database. Have I messed up when creating this app, and if so, how would I fix it?
Django's philosophy / best practices encourage "fat models thin controllers" (controllers being Views in Django). Having tried both ways, it definitely works better with the "fat models" approach. Keeping the logic as close to the data models makes it more reusable and you can there are many features in Django that work better that way.
One example would be returning a paginated list view. If you need to calculate something for every object in a queryset, you could
loop over it in the view doing the calculation
or you could add a model method then call it on every iteration in the template.
Looping over the queryset in the view will do the calculation on the whole queryset - not good if you are only showing 10 objects from a list of 1000.
Calling a model method from the template, the calculation will only be done on the 10 objects on that page.
Obviously you can add some more code to the view to only do that calculation on the objects on that page, but then thats extra code that isn't needed if you go the other route. If you need the same calculation on another page, keeping the logic in a model method will be reusable without any alteration, while you will need to cut and paste it in the view, or create a new method. While its not a huge difference, lots of small things like this start to add up.
It is better to have "Fat Models, Skinny Views." Many of Django experts will give you this tip. Google this phrase and you will find some resources that are saying "Fat Models, Skinny Views," or "Fat Models, Skinny Controllers." By the way, Django creators named Controllers as Views, and Views as Templates which maybe will cause some misunderstanding while reading articles about MVC which is MTV in Django.
No you haven't mess it up. You can find your solution through experience (years of developing).
So, either using fat models and thin views or the opposite its up to you and your application requirements.
As you learn you'll discover new techniques and methods that will help you extend your "logic" and your app implementation.
At the beggining you'll make mistakes, but that's alright. We need them to become better developers, coders etc.
So my advice is: keep calm and learn (good practices)!
The way to do it is simple. And I would say that it is not actually messed up if your logic lies in views mostly.
The most repetitive functions and logic which you have used in views in multiple functions, you can create a function defined in model and then call that function in views. (you can do it step by step)
For example if it is a social network and you are setting the city of the user. Now as your app grows, possibly there will be many functions and many places through which city is being set. If you are doing it all in views repitively then you would be stuck at some point of time because to make smallest of changes, you might have to edit all the functions.
The good way would be to define set_cities(self, cities) in user model and call it whenever needed like user.set_cities(cities_list). So if you have to trigger other functions everytime city is being set (maybe like sending notifications or updating other tables), you have to define it once only in set_cities().
In any case, all logic cannot be only in models so do not worry much about it. Just keep on trying to simplify the views and keep on shifting any repetition of logic to models.
Related
I am trying to make my Django app follow better practices than it currently does. I hear about fat models and thin controllers a lot (after putting much of my display logic in views.py initially).
Anyway, say I have a moderately complex form, for creating new objects, including foreign keys on the new objects. Assuming there are no validation errors, where should the logic for creating / linking models go? views.py after is_valid() seems the easiest place to put, but I am not sure if that is considered best practice.
In the question title you describe it as "form processing logic", but it sounds from your question text like you really mean inter-model business logic.
If it's form processing logic (cleaning, etc.), that should go on the form.
Since it sounds like you're talking about business logic, it should generally be added to the appropriate model as a model method (Django docs on model methods), then called from either the custom form logic (e.g., on save) or from the view.
Of course, where the code lives depends to a great degree on the structure of relationship between your models. Say you have an author model with a one-to-many relationship to a book model. The author model might have a method that helps you create a new book object, filling in the foreign key relation as it goes. A more complex relationship might require more view code, or at least more thought.
And yes, in general it's a good idea to try to keep your views slimmer and your models fatter.
I'm pretty novice so I'll try to explain in a way that you can understand what I mean.
I'm coding a simple application in Django to track cash operations, track amounts, etc.
So I have an Account Model (with an amount field to track how many money is inside) and an Operation Model(with an amount field as well).
I've created a model helper called Account.add_operation(amount). Here is my question:
Should I include inside the code to create the new Operation inside Account.add_operation(amount) or should I do it in the Views?
And, should I call the save() method in the models (for example at the end of Account.add_operation() or must it be called in the views?)
What's the best approach, to have code inside the models or inside the views?
Thanks for your attention and your patience.
maybe you could use the rule "skinny controllers, fat models" to decide. Well in django it would be "skinny views".
To save related objects, in your case Operation I'd do it in the save() method or use the pre_save signal
Hope this helps
Experienced Django users seem to always err on the side of putting code in models. In part, that's because it's a lot easier to unit test models - they're usually pretty self-contained, whereas views touch both models and templates.
Beyond that, I would just ask yourself if the code pertains to the model itself or whether it's specific to the way it's being accessed and presented in a given view. I don't entirely understand your example (I think you're going to have to post some code if you want more specific help), but everything you mention sounds to me like it belongs in the model. That is, creating a new Operation sounds like it's an inherent part of what it means to do something called add_operation()!
I am using python and django and like it a lot. But than i use it, I catch myself thinking
what i do a lot of work to render result data and write specific actions for it. For example than i pass result set of objects to template
i must render all data and write all possible actions such as sorting by columns,filtering,deletion,edit etc, for each of this i need
to write code in urls.py and views.py, sometimes helps generic view but it's has poor functions.
Is there some solutions to automate this work?
i mean use some interface compontents (such as "model list renderer with column filter and pagination") to wich i need only
"bind my model", all other routing work for drawing common interface action must be allready implemented in these components.
i think i need something like configurable components for fast building html web interface for models (such as model forms do fast generation forms for models).
What do you think can help in this case?
must render all data and write all
possible actions such as sorting by
columns,filtering,deletion,edit etc
Like django.contrib.admin? But I guess it's way to complicated and bloated for your needs.
sometimes helps generic view but it's
has poor functions
And that's the way, I think, you should be going. If you write same views over and over again, just make your own generic views. As an example of more robust views and a source of inspiration I recommend you to look at class-based generic views.
Also consider using model inheritance and custom managers.
Directions from my supervisor:
"I want to avoid putting any logic in the models.py. From here on out, let's use that as only classes for accessing the database, and keep all logic in external classes that use the models classes, or wrap them."
I feel like this is the wrong way to go. I feel that keeping logic out of the models just to keep the file small is a bad idea. If the logic is best in the model, that's where it really should go regardless of file size.
So is there a simple way to just use includes? In PHP-speak, I'd like to propose to the supervisor that we just have models.py include() the model classes from other places. Conceptually, this would allow the models to have all the logic we want, yet keep file size down via increasing the number of files (which leads to less revision control problems like conflicts, etc.).
So, is there a simple way to remove model classes from the models.py file, but still have the models work with all of the Django tools? Or, is there a completely different yet elegant solution to the general problem of a "large" models.py file? Any input would be appreciated.
It's natural for model classes to contain methods to operate on the model. If I have a Book model, with a method book.get_noun_count(), that's where it belongs--I don't want to have to write "get_noun_count(book)", unless the method actually intrinsically belongs with some other package. (It might--for example, if I have a package for accessing Amazon's API with "get_amazon_product_id(book)".)
I cringed when Django's documentation suggested putting models in a single file, and I took a few minutes from the very beginning to figure out how to split it into a proper subpackage.
site/models/__init__.py
site/models/book.py
__init__.py looks like:
from .book import Book
so I can still write "from site.models import Book".
The following is only required for versions prior to Django 1.7, see
https://code.djangoproject.com/ticket/3591
The only trick is that you need to explicitly set each model's application, due to a bug in Django: it assumes that the application name is the third-to-last entry in the model path. "site.models.Book" results in "site", which is correct; "site.models.book.Book" makes it think the application name is "models". This is a pretty nasty hack on Django's part; it should probably search the list of installed applications for a prefix match.
class Book(models.Model):
class Meta: app_label = "site"
You could probably use a base class or metaclass to generalize this, but I haven't bothered with that yet.
Django is designed to let you build many small applications instead of one big application.
Inside every large application are many small applications struggling to be free.
If your models.py feels big, you're doing too much. Stop. Relax. Decompose.
Find smaller, potentially reusable small application components, or pieces. You don't have to actually reuse them. Just think about them as potentially reusable.
Consider your upgrade paths and decompose applications that you might want to replace some day. You don't have to actually replace them, but you can consider them as a stand-alone "module" of programming that might get replaced with something cooler in the future.
We have about a dozen applications, each model.py is no more than about 400 lines of code. They're all pretty focused on less than about half-dozen discrete class definitions. (These aren't hard limits, they're observations about our code.)
We decompose early and often.
I can't quite get which of many possible problems you might have. Here are some possibilities with answers:
multiple models in the same file
Put them into separate files. If there are dependencies, use import to pull in the
additional models.
extraneous logic / utility functions in models.py
Put the extra logic into separate files.
static methods for selecting some model instances from database
Create a new Manager in a separate file.
methods obviously related to the model
save, __unicode__ and get_absolute_url are examples.
Pretty new to this scene and trying to find some documentation to adopt best practices. We're building a fairly large content site which will consist of various media catalogs and I'm trying to find some comparable data / architectural models so that we can get a better idea of the approach we should use using a framework we've never made use of before. Any insight / help would be greatly appreciated!
"data / architectural models so that we can get a better idea of the approach we should use using a framework we've never made use of before"
Django imposes best practices on you. You don't have a lot of choices and can't make a lot of mistakes.
MVC (while a noble aspiration) is implemented as follows:
Data is defined in "models.py" files using the Django ORM models.
urls.py file maps URL to view function. Pick your URL's wisely.
View function does all processing, making use of models and methods in models
Presentation (via HTML templates) invoked by View function. Essentially no processing can be done in presentation, just lightweight iteration and decision-making
The model is defined for you. Just stick to what Django does naturally and you'll be happy.
Architecturally, you usually have a stack like this.
Apache does two things.
serves static content directly and immediately
hands dynamic URL to Django (via mod_python, mod_wsgi or mod_fastcgi). Django apps map URL to view functions (which access to database (via ORM/model) and display via templates.
Database used by Django view functions.
The architecture is well-defined for you. Just stick to what Django does naturally and you'll be happy.
Feel free to read the Django documentation. It's excellent; perhaps the best there is.
first, forget all MVC mantra. it's important to have a good layered structure, but MVC (as defined originally) isn't one, it was a modular structure, where each GUI module is split in these tree submodules. nothing to use on the web here.
in web development, it really pays to have a layered structure, where the most important layer is the storage/modelling one, which came to be called model layer. on top of that, you need a few other layers but they're really not anything like views and controllers in the GUI world.
the Django layers are roughly:
storage/modelling: models.py, obviously. try to put most of the 'working' concepts there. all the relationships, all the operations should be implemented here.
dispatching: mostly in urls.py. here you turn your URL scheme into code paths. think of it like a big switch() statement. try hard to have readable URLs, which map into user intentions. it will help a lot to add new functionality, or new ways to do the same things (like an AJAX UI later).
gathering: mostly the view functions, both yours and the prebuilt generic views. here you simply gather all the from the models to satisfy a user request. in surprisingly many cases, it just have to pick a single model instance, and everything else can be retrieved from relationships. for these URLs, a generic view is enough.
presentation: the templates. if the view gives you the data you need, it's simple enough to turn it into a webpage. it's here where you'll thank that the model classes have good accessors to get any kind of relevant data from any given instance.
To understand django fundementals and the django take on MVC, consult the following:
http://www.djangobook.com/
As a starting point to getting your hands dirty with ...
"...trying to find some comparable data / architectural models"
Here is a quick and dirty way to reverse engineer a database to get a models.py file,
which you can then inspect to see how django would handle it.
1.) get an er diagram that closely matches your target. For example something like this
http://www.databaseanswers.org/data_models/product_catalogs/index.htm
2.) create an sql script from the er diagram and create the database,
I suggest Postgre, as some MySQL
table type will not have forgien key constraints, but in a pinch MySQL or SQLITE
will do
3.) create and configure a django app to use that database. Then run:
python manage.py inspectdb
This will at least give you a models.py file which you can read to see how django attempts
to model it.
Note that the inspect command is intended to be a shortcut for dealing with legacy
database when developing in django, and as such is not perfect. Be sure to read the
following before attempting this:
http://docs.djangoproject.com/en/dev/ref/django-admin/#ref-django-admin