I have created this model:
class Process(models.Model):
name = models.CharField('Process name', max_length=50, unique=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, max_length=50, null=True, verbose_name='Process owner')
I want to create multiple processes and from those build a hierarchy. Here is a hierarchy model:
class Hierarchy(models.Model):
mainprocess = models.ForeignKey(Process, on_delete=models.CASCADE, related_name='mainprocess', verbose_name='Main process name')
subprocess = models.ForeignKey(Process, on_delete=models.CASCADE, related_name='subprocess', verbose_name='Sub process name')
order = models.IntegerField('Process order', default=1)
EDIT: Got it work with code above and now I can build some type of hierarchy, but there are some issues:
I would like to restrict so that subprocess can be under only one main process. If i create a two different hierarchies with same subprocess it gives an unique contrstraint violation on the subprocess id, so I guess it works now.
I would like to restrict so that main process and sub process cannot be same. Now I can create it, but is there a way to do this in the model itself or do I restrict this on the client side when hierarchy is created?
What would be the right way to build this type of model/hierarchy? This might be very basic issue, but I couldn't find any related issues to apply a solution from, so any help would be appreciated.
EDIT: what i want to accomplish with the hierarchy model is to keep track on the process tree like for example:
1 Process (main process)
1.1 process (sub process)
1.1.1 process (sub process)
1.2 process (sub process)
1.2.1 process (sub process)
2 Process (main process)
2.1 process (sub process)
2.2 process (sub process)
n Process (main process)
n.1 process (sub process)
n.1.1 process (sub process)
n.1.1.1 process (sub process)
n.2 process (sub process)
Related
I have a model like
class Tasks(models.Model):
title = models.CharField(max_length=100,null=True,blank=True)
Now I want to return a list of all tasks which are same . like Two tasks A and B are considered similar if all the words in the task A exist in task B or vice versa.
how I can achive this in django orm or any other way to do this ?
I'm not able to test this solution right now, but just to give some actual example to what I was saying in the comments, here's my suggestion:
Add this into your Tasks model
class Tasks(models.Model):
title = models.CharField(max_length=100, null=True, blank=True)
#staticmethod
def find_common_tasks(title, pk=0):
tasks = Tasks.objects.filter(title__contains=title)
return tasks.exclude(pk=pk) if pk > 0 else tasks
Now you could call the method like this, for example:
task = Tasks.objects.get(pk=1)
Tasks.find_common_tasks(pk=task.pk, title=task.title)
or just Tasks.find_common_tasks(title="Some title").
Assuming the following models schema,
Parent model:
class Batch(models.Model):
start = models.DateTimeField()
end = models.DateTimeField()
One of many child models:
class Data(models.Model):
batch = models.ForeignKey(Batch, on_delete=models.ON_CASCADE)
timestamp = models.DateTimeField()
My goals is the following: to have a start field of parent model that is always updated when any child model is modified.
Basically, if the timestamp of a newly data instance is older than the start field I want the start field to be updated to that instance timestamp value. In the case of deletion of the data instance which is the oldest time reference point I want batch start field to be updated to the second oldest. Vice-versa for the end field.
One of the possible way to do this is to add post or pre-save signal of relative models and Update your necessary fields according to this. Django official documentation for signal, link. I want to add another link, one of the best blog post i have seen regarding django signal.
Edit for André Guerra response
One of easiest way to do a get call and bring Batch instance. What i want to say
#receiver(post_save,sender=Data)
def on_batch_child_saving(sender,instance,**kwargs):
batch_instance = Batch.objects.get(pk=instance.batch)
if (instance.timestamp < batch_instance.start):
batch_instance.start = instance.timestamp
batch_instance.save()
elif (instance.timestamp > batch_instance.end):
batch_instance.end = instance.timestamp
batch_instance.save()
Based on Shakil suggestion, I come up with this: (my doubt here was on how to save the parent model)
#receiver(post_save,sender=Data)
def on_batch_child_saving(sender,instance,**kwargs):
if (instance.timestamp < instance.batch.start):
instance.batch.start = instance.timestamp
instance.batch.save()
elif (instance.timestamp > instance.batch.end):
instance.batch.end = instance.timestamp
instance.batch.save()
I have a simple app that creates a Log entry for that day for each Child of a Parent when something happens to the Child.
So, for example, a Parent contains three Children.
Each time a Child is interacted with, I create an entry in the Log table to log the action. The Log is organized by day. So I could have 3 entries for three Children on Tuesday and 4 entries for the same three Children on Wednesday.
I want to write a query that checks to see if the Child exists in the Log for that day. So when the page loads, or is refreshed, I set a template variable that indicates that it does exist on the log.
I've been thinking that the following query will sort out what I need. But I'm having a hard time figuring out the missing parts.
Models:
class Child(models.Model):
description = models.TextField()
class Log(models.Model):
child = models.ForeignKey(Child, related_name="child_log")
day = models.DateField(auto_now_add=True, editable=False)
class Parent(models.Model):
parent_children = models.ManyToManyField(Child, blank=True, null=True)
Queryset:
today = date.today()
children = Child.objects.filter(parent=parent.id) <= parent.id comes from request kwargs
child_list = Child.objects.filter(id__contains=children.id)
does_exist = Log.objects.filter(child=child_list.id).filter(day=today)
But then I want to add that does_exist status to each Child in the template. That way I can show a different state if the Child has been logged or not.
Think of it like a todo list with todo items that can be done repeatedly in a day. If it's been done in a day, we need to show that it has been done. If it hasn't, then we can show that it hasn't.
I hope that is clear enough. Any suggestions are welcome.
Hm... If I understand correctly, try this
{% for child in childs %}
{% if child.child_log.today.exists %}
#do your staff
...
And write manager to Log:
class LogManager(models.Manager)
def today(self)
return self.get_query_set().filter(day=datetime.datetime.today())
...
class Log(models.Model):
child = models.ForeignKey(Child, related_name="child_log")
day = models.DateField(auto_now_add=True, editable=False)
objects = LogManager()
I have two basic models, a Command and a Flow. Flows can contain a series of commands or other nested Flows. So any given Flow can have a list of children that are either Step or Flow types. (This is similar to Files and Directories you might model in a file system.)
I've tried to model this using ContentTypes, Generic relations, and mptt (which doesn't allow for generic content types AFAIK) but have had no success. Here are my basic models:
class Step(models.Model):
parent = models.ForeignKey('Step', null=True)
name = models.CharField( max_length=100 )
start_time = models.DateTimeField(null=True)
end_time = models.DateTimeField(null=True)
state = models.CharField( max_length=1, default='u' )
class Flow(Step):
type = models.CharField( max_length=1 )
def getChildren(self):
# todo: the steps returned here need to be sorted by their order in the flow
return Step.objects.filter(parent_id=self.parent_id)
def run(self):
for child in self.getChildren():
print("DEBUG: run method processing a {0}".format(child.__class__.__name__) )
# if this is a flow, run it
# else if it's a command, execute it
class Command(Step):
exec_string = models.TextField()
I want to be able to create Flows in my app, query the children, then process each child differently depending on its type (commands get executed, flows get recursively processed.)
I would appreciate any correction of my code above which would make this possible or even comments that I'm approaching this problem the complete wrong way for Django.
Edit: I should add that I'm using Python 3.3 and Django dev (to be named 1.6)
I finally found an answer via some great help on IRC here and wanted to share it in case anyone else had the same problem.
The only thing I had to ultimately change was Flow.getChildren().
def getChildren(self):
# Get a list of all the attrs relating to Child models.
child_attrs = dict(
(rel.var_name, rel.get_cache_name())
for rel in Step._meta.get_all_related_objects()
if issubclass(rel.field.model, Step) and isinstance(rel.field, models.OneToOneField)
)
objs = []
for obj in self.children.all().select_related(*child_attrs.keys()):
# Try to find any children...
for child in child_attrs.values():
sobj = obj.__dict__.get(child)
if sobj is not None:
break
objs.append(sobj)
return objs
If anyone has a cleaner solution I'd love to see it, especially since this seems like a lot of work for something it seems like the framework should handle more directly.
The thing that jumps out at me is "return Step.objects.filter(parent_id=self.parent_id)". I believe it should be "return Step.objects.filter(parent__pk=self.parent.pk)"
I need some help with sending email when an order is placed. To illustrate the problem, following is the abstract code:
class Order(models.Model):
user = models.ForeignKey(User)
class OrderItem(modes.Model):
order = models.ForeignKey(Order, related_name='items')
item = models.CharField(max_length=255)
unit_price = models.DecimalField()
qty = models.IntegerField()
item_amount = models.DecimalField()
def email_order_on_save(sender, instance, **kwargs):
# Need order.items.all() here
pass
post_save.connect(email_order_on_save, sender=Order)
Most of the problems on SO and google seem to deal with one child object at a time; such as this.
Listening to OrderItem would release 5 signals if 5 orders items saved from admin inlines. I can't seem to get my head around this problem. One way, I think (not sure if possible), could be listening to last of all(5) OrderItem's post_save signals.
Any help appreciated.
I'm guessing you're trying to solve this in the wrong place. Sending an email when the order is completed and saving the Order model are at different levels of abstraction.
I think sending the email should be triggered by some condition in the view that has more information about whether the order is completely saved or not. Think for example of what will happen if an order needs updating (say it's status changes)? Should the email be sent then too?
Create your own custom signal and send it at the point when you have the data you need saved. Pass in as parameters whatever data structures you need.
Listen for your custom signal in your callback function email_order_on_save and make appropriate decisions based on the parameters about sending or not the e-mail.
You could create your model as follows
ORDER_STATE = (
(1, 'Completed'),
(2, 'Processing'),
)
class Order(models.Model):
user = models.ForeignKey(User)
state = models.IntegerField(choices = ORDER_STATE)
You could have many states for the order. The state "Completed" could represent that the order processing is complete. You could change the state of your order in your views.
In the signal handler, you could check for the state of the order and then send mail, if the order is in completed state.
I think you can have a problem with signals, OrderItem with inlines will not send save signal, read this