How to structure complex Django project? - python

I have a Django project which is getting more and more complex. I started off with the traditional files: models, views, and forms.py. The issue I have right now is that those files are getting bigger and bigger and I'd like to break them into manageable parts. What are the best practices around that?
In addition, I am wondering if it is best practice to add class method to a model in Django? For instance, I have a Vote class on which I would like to add methods to get the number of votes for a specific user, content, etc?

I find refactoring can really help. Are there a lot of similar views that just have different templates or querysets? Make a more generic view that accepts multiple template names, records, etc.
Anything that requires extensive calculations gets moved to a utils.py in the same directory.
Class methods are for actions that affect a single record; managers are for dealing with filtering records or creating a record.
If you're already taking the step of making separate models, views, etc. folders and breaking views and models into separate files, that suggests to me that you could separate them out into separate apps. I like that as an option much better.

I certainly use class methods, and I have found that where there are similar operations to be performed on classes, it is possible (and easy) to factor the classmethods into base classes (use the self parameter of your class method to write generic code).
Probably the best way to manage broken-up views, etc is to replace each file you want to break up with its own package, and put whatever you need to (if anything) into that package's __init__.py module.

On using model managers vs class methods. doing it this way, your code is easier for others to read, and you can combine this kind of code with other filter/select_related/order_by. Below is a simple example, but as the logic gets more complicated Managers make a great addition to your setup and for very little code, give you a lot of good connective tissue in your app.
I agree with Jordan that you may need more than one app and if you have a large code base now, the lines to break everything up by should be more apparent to.
class VoteManager(models.ModelManager):
def by_user(self, user):
return self.filter(user=user)
def by_content(self, content)
return self.filter(content=content)
class Vote(models.Model)
user = models.ForeignKey(User)
content = models.ForeignKey(Content)
...
objects = VoteManager()

Related

Should a function in a models.py ever reside outside of a class?

In my models.py, I have a couple classes, and a couple manager classes.
I have some methods that are general methods used by the model, but not necessarily a part of it.
For example:
def profile_photo_upload_loc(instance, filename):
return "profile_photo/%s/%s" % (instance.user, filename)
class Profile(models.Model):
profile_photo = models.ImageField(
upload_to=profile_photo_upload_loc,
null=True,
blank=True,
width_field='width_field',
height_field='height_field',
verbose_name='Profile Image',
)
Is it okay to have standalone functions outside of classes in the models file? When is it appropriate and when should the functions be inside the class?
the standalone functions are those functions which can be used in multiple models, like the function you have written can be used in other model image upload,
function those which are written inside a model class are the ones which can only be used with that models instance and not with other models,
if you try to use a function with other model instance it will give an error
Django and python, in general, are much more permissible with this kind of liberal approach.
I myself prefer to keep inside model methods that pertain only to it. Like "what is the age of this person?" You take his birthday and counts. Simple as that, but you can use a more Java approach and keep all methods and other business rules and logic into services. I've found that it is best to emulate a Java project when dealing with a python project that I believe that may grow big, but keeping most scripts self-contained and communicating with a good API.
Also, I keep a testing process for each script because python won't tell you that you wrote one extra L when calling the method canceled(), or if the method still exists inside a class in another file that will be executed passing the function and parameters by reference.

Converting existing python classes into Django Models

I have a small program with a command line interface that uses a number of python classes with thorough implementations. I want to scrap the command line interface and wrap the app within a Django app, but I'm just learning Django and I'm unfamiliar with the conventions.
I have a number of classes, in-memory storage structures, getters/setters etc and I'd like to convert them into Django models so that I can persist them to the database and interact with them around the django app. Is there a general approach for doing something like this?
Should I just inherit the django.db.models.Model class in my existing classes and set them up for direct interaction? Or is there a better, more general/conventional way to do this?
I would like to be able to use all of this code in other apps, not necesarilly Django ones, so I don't really want to modify my existing classes in a way that would make them only work with Django. I thought of creating the models separately and then a sort of middle-man class to manage interaction of the actual in-memory class with the django model class, but that just seems like more places I have to make changes when I extend/modify the code.
Thanks for any help ahead of time...
Personally, I would modify your existing classes to extend models.Model and maintain separate versions of these classes for use outside of Django.
This will keep your classes lean and maintainable within their respective environments.
You could also create a new class that extends both models.Model and your python model through multiple inheritance. However this will result in duplicate fields for the same data.
If you would like, post an example Model as a new question and tag me in a link to it here, and I can help you convert it.
One of greatest django strengths is its ORM, if you want import i recommend you use it, and yes you would probably need rewrite the part that interacts with the database, but if you already have isolated this functions in a Models folder~classes, the modification won't be really hard
Although in your case i would recommending checking out Tornado/Aiohttp Since looks like you are just trying to create a interface for your functions

Python/Django - Where do I have to make methods that perform like DML?

'Methods that perform like DML' means methods that change data in the database.
Is there a standard or guideline for that?
Below are my own guesses.
Collect all functions in file of which name is like 'data_access.py'
Contain functions in each class of models.py
There is no standard. No one will blame even if I make them in views.py
Above all are wrong.
A common philosophy in Django is "fat models, thin views", so preferably you would put as much of this DML functionality as functions on your model classes. Since models.py already defines the structure of your data, it makes sense to put functions that manipulate your data in the same file as much as possible.

What are the advantages of declaring methods in classes instead of functions?

This is the normal/right way to do in a Django project:
in models.py
class Reservation():
def cancel_reservation(self):
# ....
#classmethod
def get_client_reservations(cls):
The alternative way that I found in a company codebase:
in models.py
class Reservation():
# There is no method here except __unicode__
and in manage_reservations.py
def cancel_reservation(reservation):
# ...
def get_client_reservations():
# ...
I'd like to have an exshaustive list of the consequences of choosing the first way instead of the second one.
It's a coding style. "Object" in OOP is data and methods, together. The object has everything you need to hold the data and manipulate it. There is no "right" answer, more opinion and style.
So you can write:
r = Reservation.objects.get(pk=1)
r.get_client_reservation()
Rather then:
from . import get_client_reservation
get_client_reservation(r)
But the truth is that Python modules are a very good solution to keep things together, and it's easier to debug than a complex inheritance chain.
In django the OOP is essential because the framework lets you easily subclass components and customise only what you need, this is hard to do without objects.
If you need a specific form, with specific fields, then you can write it as a simple module with functions. But if you need a generic "Form" that everybody can customise (or a model, authentication backend etc), you need OOP.
So bottom line (IMHO): if Reservation is at the bottom of the pyramid, the end line of data and code, no big difference, more personal preference. If it's in the top and you are going to need ReservationThis and ReservationThat, OOP is better.
This isn't a technical answer, but try doing a git blame on that code, and seeing who wrote the methods, and ask them why they chose to do it like that. In general it's better to keep the methods on the class (for multiple reasons) - for example being able to do dir(r) (where r is a reservation) and seeing all the methods on r. There may be a reason though (that we can't know unless we saw the code)
You shoud put a method inside a class if the it's related with the class, for example if it needs some class variable or if it logically belongs with the class

Can django lazy-load fields in a model?

One of my django models has a large TextField which I often don't need to use. Is there a way to tell django to "lazy-load" this field? i.e. not to bother pulling it from the database unless I explicitly ask for it. I'm wasting a lot of memory and bandwidth pulling this TextField into python every time I refer to these objects.
The alternative would be to create a new table for the contents of this field, but I'd rather avoid that complexity if I can.
The functionality happens when you make the query, using the defer() statement, instead of in the model definition. Check it out here in the docs:
http://docs.djangoproject.com/en/dev/ref/models/querysets/#defer
Now, actually, your alternative solution of refactoring and pulling the data into another table is a really good solution. Some people would say that the need to lazy load fields means there is a design flaw, and the data should have been modeled differently.
Either way works, though!
There are two options for lazy-loading in Django: https://docs.djangoproject.com/en/1.6/ref/models/querysets/#django.db.models.query.QuerySet.only
defer(*fields)
Avoid loading those fields that require expensive processing to convert them to Python objects.
Entry.objects.defer("text")
only(*fields)
Only load the fields that you actually need
Person.objects.only("name")
Personally, I think only is better than defer since the code is not only easier to understand, but also more maintainable in the long run.
For something like this you can just override the default manager. Usually, it's not advised but for a defer() it makes sense:
class CustomManager(models.Manager):
def get_queryset(self):
return super(CustomManager, self).get_queryset().defer('YOUR_TEXTFIELD_FIELDNAME')
class DjangoModel(models.Model):
objects = CustomerManager()

Categories