My application creates several rows of data per customer per day. Each row is modified as necessary using a form. Several modifications to a row may take place daily. At the end of the day the customer will "commit" the changes, at which point no further changes will be allowed. In each row I have a 'stage' field, stage=1 allows edits, stage=2 is committed, no further changes allows.
How can I update the stage value to 2 on commit?
In my model I have:
#property
def commit_stage(self):
self.stage = 2
self.save()
Is this the correct way to do this? And if so, how to I attach this function to a "commit" button.
I suspect you are confused about what properties do. You should absolutely not attach this sort of functionality to a property. It would be extremely surprising behaviour for something which is supposed to retrieve a value from an instance to instead modify it and save it to the db.
You can of course put this in a standard model method. But it's so trivial there is no point in doing so.
In terms of "attaching it to a button", nothing in Django can be called from the front-end without a URL and a view. You need a view that accepts the ID of the model instance from a POST request, gets the instance and modifies its stage value, then saves it. There is nothing different from the form views you already use.
Related
So I have a list of unique pupils (pupil is the primary_key in an LDAP database, each with an associated teacher, which can be the same for several pupils.
There is a box in an edit form for each teacher's pupils, where a user can add/remove an pupil, and then the database is updated according using the below function. My current function is as follows. (teacher is the teacher associated with the edit page form, and updated_list is a list of the pupils' names what has been submitted and passed to this function)
def update_pupils(teacher, updated_list):
old_pupils = Pupil.objects.filter(teacher=teacher)
for pupils in old_pupils:
if pupil.name not in updated_list:
pupil.delete()
else:
updated_list.remove(pupil.name)
for pupil in updated_list:
if not Pupil.objects.filter(name=name):
new_pupil = pupil(name=name, teacher=teacher)
new_pupil.save()
As you can see the function basically finds what was the old pupil list for the teacher, looks at those and if an instance is not in our new updated_list, deletes it from the database. We then remove those deleted from the updated_list (or at least their names)...meaning the ones left are the newly created ones, which we then iterate over and save.
Now ideally, I would like to access the database as infrequently as possible if that makes sense. So can I do any of the following?
In the initial iteration, can I simply mark those pupils up for deletion and potentially do the deleting and saving together, at a later date? I know I can bulk delete items but can I somehow mark those which I want to delete, without having to access the database which I know can be expensive if the number of deletions is going to be high...and then delete a lot at once?
In the second iteration, is it possible to create the various instances and then save them all in one go? Again, I see in Django 1.4 that you can use bulk_create but then how do you save these? Plus, I'm actually using Django 1.3 :(...
I am kinda assuming that the above steps would actually help with the performance of the function?...But please let me know if that's not the case.
I have of course been reading this https://docs.djangoproject.com/en/1.3/ref/models/querysets/ So I have a list of unique items, each with an associated email address, which can be the same for several items.
First, in this line
if not Pupil.objects.filter(name=name):
It looks like the name variable is undefined no ?
Then here is a shortcut for your code I think:
def update_pupils(teacher, updated_list):
# Step 1 : delete
Pupil.objects.filter(teacher=teacher).exclude(name__in=updated_list).delete() # delete all the not updated objects for this teacher
# Step 2 : update
# either
for name in updated_list:
Pupil.objects.update_or_create(name=name, defaults={teacher:teacher}) # for updated objects, if an object of this name exists, update its teacher, else create a new object with the name from updated_list and the input teacher
# or (but I'm not sure this one will work)
Pupil.objects.update_or_create(name__in=updated_list, defaults={teacher:teacher})
Another solution, if your Pupil object only has those 2 attributes and isn't referenced by a foreign key in another relation, is to delete all the "Pupil" instances of this teacher, and then use a bulk_create.. It allows only 2 access to the DB, but it's ugly
EDIT: in first loop, pupil also is undefined
Ok, this might take a bit of explanation.
I have a class called PurchaceOrder, which has a form with 18 fields. A lot of the time, there will be several PurchaceOrders with the first 12 fields being the same. To facilitate this (and remove the chance of a user making an error when trying to make the 12 fields the same every time) I have a form that allows the user to add more than one PurchaceOrder with the first 12 Fields being carried over from one entry to the next. This is all fine and good, and is working very well.
However; I need a splash page after the user is done adding all of his/her PurchaceOrders, that shows all the entries that were just made. This means I need to track the new entries that are being created, but I can't think of a way to do this. For now I'm just filtering the categories, so that the PurchaceOrders with the first 12 fields being the same as the ones just entered are displayed, but this obviously won't really work (there could be a previous entry that has those 12 fields that are the same). What I'd really like to have is a list of Primary Keys of the entries that were just created. I could then pass this information onto the view that's responsible for the confirmation landing page.
In my current view I have the following:
if form.is_valid():
entry=form.save()
My thinking was that I could then do something like:
pks = [pks, entry.id]
I don't know where I would instantiate the list. If I did it in the view, it would be whipped out every time the page was reloaded.
I'd appreciate any help.
My first thought would be to have a separate class/method/function that keeps track of the PurchaceOrder's in each form. The ID could be tied to the result through a database or array/linked list that is auto-incremented when a new PurchaceOrder is created.
As far as instantiating the list, have it instantiated when the class is first called, or have it as a separate class. After writing that, a separate class makes more sense, which is probably why I posted it that way originally.
After leaving this alone for a long time, I've finally come up with a suitable solution. What I've done is created a url conf that has a regex of (?P<match>/+)/in it. That rexeg will be used to contain an arbitrary number of primary keys separated by /. I use this to store all of the primary keys of the PurchaseOrders that have been created (that is, when I create PurchaseOrder number 15, it redirects me to /new/15, then when I create number 16, it directs me to /new/15/16/, and so on. Then when I'm ready to confirm, I'm sent to /confirm/15/16/ and I can easily access the pk's of the entries I've just created by calling pks=match.split('/'). I can then simply iterate through pks and do something for each object. I think it's an elegant solution, as long as you don't mind your user seeing the primary keys in the url.
I came across this problem on form save the data needs to be persisted somewhere then go through a payment process then on success retrieve the data and save to the proper model.
I have seen this done using session, but with some hacky way to persist file uploads when commit=False and it doesn't seem very pythonic
I am thinking if I have a model class A, and have a child class extending A, such as A_Temp
class A(models.Model):
name = models.CharField(max_lenght=25)
image = models.ImageField()
class A_Temp(A):
pass
class AForm(forms.ModelForm):
class Meta:
model = A_Temp
On model form (A_Temp) save, it stores to A_Temp, and when payment successful, it move the instance to the parent model class A.
Here are the questions:
Has anyone done this before?
How to properly move an instance of a child model class to the parent model class?
Edit:
There are other different ways to do it, such as adding extra fields to the table, yes I would've done that if I am using PHP without a ORM framework, but since the ORM is pretty decent in django, I thought that I might trial something different.
Since I am asking here, means I am not convinced myself about this approach as well. What are your thoughts?
As suggested in the question comments, adding an extra field to your model containing payment state may be the easiest approach. Conceptually it's the same object, it's just that the state changes once payment has been made. As you've indicated, you will need logic to purge out items from your database which never proceed through the required states such as payment. This may involve adding both a payment_state and state_change_time field to your model which indicates when the state last changed. If the state is PAYMENT_PENDING for for too long, that record could be purged.
If you take the approach that unpaid items are stored in a different table as you've suggested, you still have to manage that table to determine when it's safe to delete items. For example, if a payment is never processed, when will you delete record from the A_temp table? Also, having a separate table means that you really only have two states possible, paid and unpaid as determine by the table in which the record occurs. Having a single table with a payment_state may be more flexible in that it allows you to extend the state as required. eg. Let's say you decide you need the payment states ITEM_SUBMITTED, AWAITING_PAYMENT, PAYMENT_ACCEPTED, PAYMENT_REJECTED. This could all be implemented with a single state field. If this was implemented as you've described, you'd need a separate table for each state.
Having said all that, if you're still set on having a separate table structure, you can create a function which will copy the values from an instance of A_temp to A. Something like the following may work, but any relationship type fields such as ForeignKey are likely to require special attention.
def copy_A_temp_to_A(a, a_temp):
for field_name in a._meta.fields:
value = getattr(a, field_name)
setattr(a_temp, field_name, value)
When you need to do the move from A_temp to A, you'd have to instantiate an A instance, then call the copy function, save the instance and delete the A_temp instance from the database.
We have a Dialog and a Comment object. We have a denormalized field, num_comments, on Dialog to keep track of the number of comments. When a new comment is saved (or deleted) we want to increase/decrease this value properly.
# sender=Comment, called post_save and post_delete
def recalc_comments(sender, instance, created=False, **kwargs):
# Comments that will be deleted might not have a dialog (when dialog gets deleted)
if not hasattr(instance, "dialog"):
return
dialog = instance.dialog
dialog.update(
num_comments = sender.public.filter(dialog=dialog).count(),
num_commentators = sender.public.filter(dialog=dialog).aggregate(c=Count('user', distinct=True))["c"],
)
The problem that has started to appear is that the query for num_comments returns zero for the first comment posted. This does not happen every time, and only in cases with aprox. > 1000 comments in the result set (not much, I know...).
Could it be that the Comment has not yet been saved to the database when the count() is performed? To complicate things further we are using Johnny Cache (with memcached) as a layer between the ORM and database.
Any input would be greatly appreciated!
As far as I understood you want to do denormalization of your database scheme for best query performance. In this case I can recommend you application designed specially for this purpose - django-composition
As documentation said:
django-composition provides the abstract way to denormalize data from
your models in simple declarative way through special generic model
field called CompositionField.
Most cases of data denormalization are pretty common so
django-composition has several "short-cuts" fields that handles most
of them.
CompositionField is django model field that provides interface to data
denormalization.
You also can use this shortcut ForeignCountField. It help to count number of objects related by foreignkey.
I have a django model in use on a production application and I need to change the name and data type of the field with zero downtime to the site. So here is what I was planning:
1) Create the new field in the database that will replace the original field
2) Everytime an instance of the Model is loaded, convert the data form the original field and store it into the new field, then save the object (only save object if new field is empty)
3) Over time the original field can be removed once every object has a non-blank new field
What method can I attach too for the 2nd step?
Won't you have to change your business logic (and perhaps templates) first to accomodate the new fieldname?
Unless stuff gets assigned to the field in question at dozens of places in your code, you could (after creation of the field in the database)
1) adapt the code to recognize the old (read) and the new field(name)s (write).
2) change the data in the database from old to new field via locking / .update() call, etc.
3) remove the old field(name) from the model/views/templates completely
Without downtime, I don't see how users of your site will not suffer getting "old" values for a few seconds (depending on how many rows are in the table, how costly the recalc to the new datatype, etc.).
Sounds complex, and effects a lot of production code.
Are you trying to avoid doing this in bulk because of downtime? What volume of data are you working with?
Have you looked at any Django migration tools that are out there. South is a very popular one:
http://south.aeracode.org/
As you seemingly can't afford ANY downtime whatsoever (I wouldn't want your job!!!) you probably don't want to risk overriding the model's constructor method. What you could try instead is catching the post init signal...
https://docs.djangoproject.com/en/1.0/ref/signals/#django.db.models.signals.post_init