Where to put business logic that spans multiple models in Django - django

You don't need to read all this post to help me answer the question, the rest of this post is only the context where the question came, but the general question is:
Where to put business logic that spans multiple models in Django?
some possibilities:
Some View? (I don't think so, it must work in the admin and several views, DRY)
Save methods in model/forms?(how?)
Clean methos in model/forms?(how?)
split the logic and use signals?(how?)
Other?
Context:
I have this models:
Department: Reference different departments in a company (risk, finance,IT,...)
Employee: May belongs to only one department for a period of time and then change to other department.
Project: Each Department can have multiple projects, and a project belongs to multiple departemnts.
Membership: intermediate table between the Employee and Department ManyToMany relationship that includes other fields like join_date and leave_date, important field are fk:Department, fk:Employee
History: intermediate table between Membership and Project that let me know which employee was involved in wish project wen he was working in some department, important fields are fk:Membership, fk:Project.
CurrentProjects: table that relates departments with the projects they are working on currently.
suppose I'm in the Django admin and I go the department Risk, and Risk has currently Project1 and Project2 assigned. when I add a new employee "Jhon Smith" (for example,using an inline form in Department) and press the save button, I want the model History gets updated with this information:
Membership table (only important fields):
pk Department Employee join_date leave_date
20 Risk Jhon Smith xxxx xxxx
History Table (only important fields):
Membership Project
20 Project1
20 project2
I mean when a new employee gets assigned to a new department all the actual projects from that department must be assigned to that Membership employee-department in the table History.
the question is where to put this logic in Django? as you can see this logic involves multiples models, some posibilities are:
In some view (I don think so, it must work in the admin interfase and in other places)
In the clean method of the Membership, Department or Employee model/form?
In the save method of the Membership, Department or Employee model/form?
I have to split the logic and use something like signals? (some example?)
Others?
I'm over complicating everything? =)
Considerations: It would be nice if the code could generate a valueerror at any point in the process and the user/admin could be able to see this error in the unbounded form.

I am just commenting on the aspect of where the logic should live. This all sounds like model logic to me. Django has a slightly mixed concept of MVC. When its purely data relation I believe its all model logic. I would recommend putting the methods as close to the model they affect as possible and simply make the smallest call possible from the triggering model.
If you are very concerned with decoupling the apps, then you could use signals. Instead of Model A knowing it needs to call XYZ during a save, it goes the other way. Model A just emits a signal. XYZ would be responsible for being connected to the signal. You can even make your signal definitions in a completely general project app, in which case neither the triggering or receiving Models know about eachothers actions. It just binds them.
There are some built in signals, such as before and after a save on a model, which means if you are looking for a save trigger you won't have to emit something custom. But lets say at various point of one models logic you need to emit a custom signal like "Name changed", you could emit your own.
Model A
import django.dispatch
name_changed = django.dispatch.Signal(providing_args=["name"])
class ModelA:
...
def foo:
# something happened here
name_changed.send(sender=self, name=the_name)
Model B, C, D
from myApp.modelA import name_changed
name_changed.connect(modelB.handle_name_change, dispatch_uid="my_unique_identifier")
name_changed.connect(modelC.handle_name_change, dispatch_uid="my_unique_identifier")
name_changed.connect(modelD.handle_name_change, dispatch_uid="my_unique_identifier")
Personally I have a habit of creating a utils.py module for apps that need some general "controller model" logic. They are more like actions or helpers.

Maybe the problem is that "history" table you have there. I don't know what kind of information you have in your Project table. But if every project have a start and end date, your history table is handling duplicate information. In this case, if you want to know in which project has worked an employee, you just need to know in which rage of dates this employee have worked for the department and then you need to find the projects of that department that were developed between the previous date range.
I hope you understand my point. If no, please tell me so i can explain it better (maybe with an example).
But as i understand your problem and your models, i think you don't need that history table. It will duplicate information...
So, if your Project model have this information (range of dates) the solution should live in a manager, because it is just a matter of find the information you want that live in multiple tables...
Hope it helps!

Related

Django app where you can send application to authorities

I am currently working to write a web app where people fill out the necessary information, and apply to their mentors.
So, at this point, mentors have a model class that is pretty much like the applicant's, so that they can correct the applicant's info without affecting the applicant's original profile.
I will appreciate any helpful comments. Specifically, I am looking for:
-A similar per-exisiting django app that does more or less so I can browse the source.
-Any special Django feature that allows this that I can not aware of.
-General info on how things like these are done in general.
Thank you.
Ad general info)
You would benefit from doing this in a single model (say ApplicationModel), with fields in pairs - field_name_applicant, field_name_mentor.
Then use a CreateView with its fields property set to only the *_applicant fields for the applicant to fill in the applications initially, and an UpdateView with its fields set to the *_mentor fields for the mentor to correct the applicant fields.
Have ApplicationModel.clean() copy all *_applicant field values to their *_mentor counterpart if the later is not set.
Now you have all your business logic in the model where it belongs; quoting a headline in the introduction of Two Scoops of Django:
Fat Models, Helper Modules, Thin Views, Stupid Templates

How to organize variable administration/views for the same model in a django project?

I have a problem but I don't know the best way to organize the django project. I have the same model for two types of tournaments (it is only an example)
Tournament (type knockout or league)
Match
If the tournament is a knockout I must create all the matchs for the first round but if it is a league I must create all matchs for all the league.
The admin page for the knockout should be a knockout tree and the league a table with the results and the classification
How can I organize the code?
Currently I have a knockout application and a league application and, when the user select "admin" it redirect to an application depending of the tournament type.
Another problem is: I need to run some process when a user create or change the tournament, when the user add or remove teams etc, but the same problem: when the type is knockout I need run X proccess but if it is league run Y proccess.
I need a scalable solution for new types of tournaments but I don't know what is the best arquitecture/organization.
In Django you can subclass model classes, but I'd probably keep things simple and stupid:
create a model for tournament. One of its fields would determine what kind of tournament it is
create a model for match
Tournament class would contain the code to create its associated matches.
I wouldn't worry about scalability at this time too much. Solve the problem you have now. When you have 6+ types of tournaments and the tournament class gets convoluted you'll also have better idea how to split up the logic.

How to save a related, inline django model when parent is saved in the admin?

In my models, I have an Event class, a Volunteer class, and a Session class. The Session class has a foreign key field for an Event and a Volunteer, and is a unique coupling of both, as well as a date and time. Taken together, Volunteer and Event I think technically have a ManyToMany relationship.
Using the pre-packaged Django admin, I edit Volunteers and Events with their own admin.ModelAdmin classes respectively. Sessions are edited inline in the Events ModelAdmin.
When I add a new Session to an event in the admin interface, with a Volunteer, I need the Volunteer's hours field to be automatically updated, to reflect however many hours the newly added session lasted (plus all past sessions). Currently, I just have a calculate_hours function in the Volunteer model, which iterates over all sessions each time it is called and finds the sum of the hours. I tried to call it with a custom save function in Session, but it appears never to be called after the Event save function. I would try it in Event, but I have no way to isolate which Volunteers need their hours recalculated. The hours field IS updated if I manually go over to the Volunteer admin page, edit, and then save the Volunteer, but this is pretty unacceptable.
I see that there are many questions on SO about Django problems when saving inline objects on the admin site, particularly with ManyToMany fields. I'm not sure, after reading many of these questions, if what they say applies in my case--maybe I need to receive a signal somewhere, or include a custom save in a special place, or call save_model in my admin.ModelAdmin class... I just don't know. What is the best way to go about this?
Code can be found here: Models.py, Admin.py
First of all, the relationship you're describing is what called a ManyToMany "through" (you can read about it in the documentation here).
Secondly, I don't understand why you need the 'hours' to be a field at all. Isn't a function enough for this? why save it in the database in the first place? you can just call it every time you need it.
Finally, it seems to me you're doing a lot of extra work that I don't understand - why do you need the volunteer time boolean field? If you link a volunteer with an event isn't that enough to know that he was there? And what's the purpose of "counts_towards_volunteer_time"? I'm probably missing some of the logic here, but a lot of that seems wasteful.

Should I use a constraint?

I'm developing a Twitter-like system, and have a model to record who follows who. There are two fields and both fields are foreign keys and point to the User model.
Clearly you wouldn't want a follower-followee record duplicated, so I'm using the unique_together attribute in the inner Meta class, in order that the follower-followee pair is unique. Trying to violate this throws IntegrityError and 500 status code.
This feels like a "second line of defence" as my view and template code doesn't give a user the chance to follow someone twice.
Should I/can I do something similar to ensure you can't follow yourself?
The view and template that lists all users (each with a button to click to follow that user) does not list the currently logged in user, so there should be no opportunity to follow yourself. But I don't have anything equivalent to unique_together.
Dude, no.
I don't know why you're doing this, but assuming it isn't for a uni project with a lunatic professor, you're wasting your time.
That is, if he's not a lunatic he's not going to try and hack the following/followee . And so what if he does?
If its for a startup-idea, then spend less time solving this (trivial) problem and more time working on whatever business model or marketing or whathaveyou thing you need to do.
A little bug isn't going to be a show stopper.
If you're being contracted out, leave it as a bug and get the conteact extended to fix it :)
If you just want to fix this, just do a check in the model or the validation that the follower isn't the same as the followee

Creating an order in Django

Hi everyone I have a few questions about the django admin.
First the relevant details. I currently have Client, Printer, Cartridge, and Order models.
The Printer model has a ManyToManyField to the Cartridge model, which would allow you to select all the cartridges that can be used with that printer.
The Cliente has a ManyToManyField to the printers which they own.
1) I want to create an Order through the Django admin which lets your specify the Client, a dicount, and multiple cartridges through a ManyToManyField. This is getting kinda tricky because I have to do it through another table that specifies whether it's a new Cartridge or a refill.
2) I want the admin to filters the Cartridges to only show the ones that belong to the printers that they own.
3) Also I would like to have a field that holds the total price of their order, but it should calculate it based on how many cartridges they have added to the order. I don't know if this should be done by adding more of the same cartridge to the order or by having another field in the related table that specifies the quantity.
Can this be done in the admin or do I need to use a form? And if so how would I go about adding this to the admin? It seems difficult and probably something I will have to do in multiple parts since in order to filter the list of cartridges I have to know the client beforehand.
As far as I can see, no, it's not really possible. The development version has some methods for limiting foreign keys, but it doesn't seem to me that limiting based on the customer is possible, since it depends on separate foreign keys.
The best suggestion, if you're really bent on doing it in the admin form, would be to use Javascript to do it. You would still have to make AJAX calls to get lists of what printers customers had and what cartridges to show based on that, but it could be done. You would just specify the JS files to load with the Media class.
But I think that's more work than it's worth. The easiest way I would see to do it would be with Form Wizards. That way, you'd have a step to select the customer so on the next step you know what cartridges to show.
Hope that helps!
I've worked similar problems, and have come to the conclusion that in many cases like this, it's really better to write your own administration interface using forms than it is to try and shoehorn functionality into the admin which is not intended to be there.
As far as 3) goes, it depends on what your product base looks like. If you're likely to have customers ordering 50 identical widgets, you probably do want a quantity field. If customers are more likely to be ordering 2 widgets, one in red, one in blue, add each item separately to the manytomany field and group them in your order interface.