Django: split forms.py in several files - python

I have a very long forms.py and I'd like to split it to smaller parts with as few as possible changes in the code.
Any ideas?

I can't comment, so I'm writing answer. The other thing you can do is to create a forms
directory(remember about __init__.py) in an app directory and split your forms to formone.py, form2.py,...
Then you can import form like that from myapp.forms.formone import FormOne
Or in the __init__.py you can place code:
from formone import *
from form2 import *
And you can import forms with from myapp.forms import FormOne

The main reason that we put Django form classes into a forms.py file is convention. It makes it easy for others to look at your application and know what kinds of things he or she will find in any given file. It's good to follow conventions, but it's not the law and you're free to organize your code as you please.
Here's what I'd do:
First of all, see if you can reduce the amount of code by factoring out duplicated code. Common validation logic could be pulled into custom validators. Forms that share fields or functionality could inherit from a common parent.
If you have created custom field classes, you could separate all those into a file called something like formfields.py in the application directory, and simply import them into forms.py. Likewise, if you have custom validators, you can take those out and import them.
If none of that reduces filesize enough for you, I would split up my form classes by function into several files, e.g. forms_user.py, forms_products.py, forms_data_entry.py or whatever. That way, it's still obvious what we will find in a given file. You will have to change import statements wherever your old forms are referenced, but those should be the only changes necessary.

If you really want to make as few changes as possible, splitting forms.py into multiple files by function (forms_user.py, forms_product.py) is the easiest.
If you have time to refactor or are starting a new project, the best solution is to make a new django app for each component of your project (e.g. users, projects...) each with its own forms.py file. If a single django app gets too big lots of things stop scaling (models.py, views.py etc.) and maintenance gets harder across the board.

Related

Shifting thinking from CakePHP to Django - a monolithic views file?

I'm trying to get started with Django, and have previously worked with CakePHP, and so my MVC background comes out of that. I'm aware of Django's slightly different MTV architecture, and am fine with the monolithic model files - multiple classes in one file I can handle just fine.
But I'm confused about how to do the views (which are roughly analagous to controllers in MVC, correct?). The examples I've seen just have one views.py that has methods like index(), view(), etc. But if I have a bunch of users that create and own widgets that they can share, for example, I want to have /users/view that runs view() for the users model, and /widgets/view that runs view() for the widgets model.
I don't see any way to separate those out, and don't know what the correct/conventional/right way is to do so. I may just be having trouble wrapping my head around Django's way of doing things, too. Should I have methods in view.py that are user_view and widget_view? That seems very clunky.
Or should I have user_view.py or even user/view.py that contains index() and view()? Could I reference those from the URL routing? How are things generally done with Django and this kind of thing?
This may ultimately be related to (or even solved by) this answer, but I'm asking more as a question of what convention and the right way to think about such things is.
Additionally, shouldn't the docs/examples be clearer on this? I've been impressed by the docs thus far, but I'm pretty sure most web apps will deal with more than one "object," and it seems to me that this would come up pretty often.
Python view files are just Python modules. The views themselves are just functions that can live anywhere you like - the module doesn't even have to be called views.py. The urlconf (in urls.py) can refer to views anywhere at all.
One obvious way of separating things out is into separate applications, which is covered well in the documentation - you can also have separate urls.py files for each app and use include in the main site-level urls.py to include all the sub-files.
But there's nothing to stop you sub-dividing the views in a single app into multiple files - eg by creating a views module, containing a (blank) __init__.py and as many other view files as you like.
Or, if you really do have views associated only with a particular model - and you'd be surprised how seldom that is the case - again, you could make your views classmethods on the model class itself. All a view has to do is to accept a request, and any other parameters, and return a response.

Where should django manager code live?

This is a pretty simple django patterns question. My manager code usually lives in models.py, but what happens when models.py is really huge? Is there any other alternative pattern to letting your manager code live in models.py for maintainability and to avoid circular imports?
A question may be asked as to why models.py is so huge, but let's just assume it's size and breadth of utility is justified.
I prefer to keep my models in models.py and managers in managers.py (forms in forms.py) all within the same app. For more generic managers, I prefer to keep them in core.managers if they can be re-used for other apps. In some of our larger apps with models/modelname.py that will contains a manager and the model code which doesn't seem bad.
Your best bet with a large set of models is to use django modules to your advantage, and simply create a folder named models. Move your old models.py into this models folder, and rename it __init__.py. This will allow you to then separate each model into more specific files inside of this model folder.
You would then only need to import each model into your __init__.py's namespace.
So, for instance, you might want to separate it into:
yourapp/
models/
__init__.py # This file should import anything from your other files in this directory
basic.py # Just an example name
morespecificmodels.py # Just an example name
managers.py # Might want to separate your manager into this
Then your __init__.py can just be:
from basic import * # You should replace * with each models name, most likely.
from managers import YourManager # Whatever your manager is called.
This is the structure that I use when my model files get huge, however I try to separate things into more pluggable apps as often as possible - so this is rarely used by me.
Hope this helps.
I always place mine in managers.py. If you have a circular import issue remember that a) You can reference the model class for a manager at self.model, and b) You can do imports inside of functions.
What I did when building Django apps was to create a [modelname].py file with just the specific model code, manager code and sometimes form code and used an __init__.py file to import then all in the models directory. This helped me atleast in keeping it managable.

Reusing a Django app within a single project

In trying to save as much time as possible in my development and make as many of my apps as reusable as possible, I have run into a bit of a roadblock. In one site I have a blog app and a news app, which are largely identical, and obviously it would be easier if I could make a single app and extend it where necessary, and then have it function as two separate apps with separate databases, etc.
To clarify, consider the following: hypothetically speaking, I would like to have a single, generic news_content app, containing all the relevant models, views, url structure and templatetags, which I could then include and extend where necessary as many times as I like into a single project.
It breaks down as follows:
news_content/
templatetags/
__init__.py
news_content.py
__init__.py
models.py (defines generic models - news_item, category, etc.)
views.py (generic views for news, archiving, etc.)
urls.py
admin.py
Is there a way to include this app multiple times in a project under various names? I feel like it should be obvious and I'm just not thinking clearly about it. Does anybody have any experience with this?
I'd appreciate any advice people can give. Thank you.
What's the actual difference between blogs and news? Perhaps that difference ought to be part of the blog/news app and you include it just once.
If you have a blog page with blog entries and a news page with news entries and the only difference is a field in the database (kind_of_item = "blog" vs. kind_of_item = "news") then perhaps have you have this.
urls.py
(r'^/(?P<kind>blog)/$', 'view.stuff'),
(r'^/(?P<kind>news)/$', 'view.stuff'),
views.py
def stuff( request, kind ):
content= news_blog.objects.filter( kind=kind )
return render_to_response( kind+"_page", { 'content': content } )
Perhaps you don't need the same app twice, but need to extend the app to handle both use cases.
In this case you could create the common piece of code as a Python module instead of a whole new application.
Then for each instance you would like to use it, create an app and import the bits from that module.
I'm not 100% sure I understand your question, so I'm going to list my understanding, and let me know if it is different from yours.
You want to have a "news" and a "blog" section of your website with identical functionality.
You want to have "news" and "blog" entries stored separately in the database so they don't end up intermingling.
If this is the case, I'd suggest making an API to your views. Something like this:
views.py:
def view_article(request, article_slug,
template_name='view_article.html',
form_class=CommentForm,
model_class=NewsArticle,
success_url=None,
):
urls.py:
(r'^news/(?P<article_slug>[-\w]+)/$', 'view_article', {}, "view_news_article"),
(r'^blog/(?P<article_slug>[-\w]+)/$', 'view_article', {'model_class': BlogArticle}, "view_blog_article"),
This makes your app highly reusable by offering the ability to override the template, form, model, and success_url straight from urls.py.

models.py getting huge, what is the best way to break it up?

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.

Separating Models and Request Handlers In Google App Engine

I'd like to move my models to a separate directory, similar to the way it's done with Rails to cut down on code clutter. Is there any way to do this easily?
Thanks,
Collin
I assume you're using the basic webkit and not Django or something fancy. In that case just create a subdirectory called models. Put any python files you use for your models in here. Create also one blank file in this folder called __init__.py.
Then in your main.py or "controller" or what have you, put:
import models
at the top.
You just created a python package.
Brandon's answer is what I do. Furthermore, I rather like Rails's custom of one model per file. I don't stick to it completely but that is my basic pattern, especially since Python tends to encourage more-but-simpler lines of code than Ruby.
So what I do is I make models a package too:
models/
models/__init__.py
models/user.py
models/item.py
models/blog_post.py
In the main .py files I put my basic class definition, plus perhaps some helper functions (Python's module system makes it much safer to keep quickie helper functions coupled to the class definition). And my __init__.py stitches them all together:
"""The application models"""
from user import User
from item import Item
from blog_post import BlogPost
It's slightly redundant but I have lots of control of the namespace.

Categories

Resources