tags:

views:

254

answers:

7
from django.db import models
from django.contrib.auth.models import User

class Product(models.Model):
name = models.CharField(max_length = 127)
description = models.TextField()
code = models.CharField(max_length = 30)
lot_no = models.CharField(max_length = 30)
inventory = models.IntegerField()
commited = models.IntegerField()
available = models.IntegerField()
reorder = models.IntegerField()
created_date = models.DateField(auto_now_add = True)
comment_user = models.ForeignKey(User, null=True)
comment_txt = models.TextField()

def __unicode__(self):
    return self.code + " - " + self.name + " - " + self.lot_no + " - " + str(self.created_date)

@property
def available(self):
    return self.inventory - self.commited

Im trying to have available calculated by (inventory - self) when a person enters in the data for inventory and commited in django admin template. But I'm not sure how.

Thanks, Jon

+3  A: 

Try overriding the save method on the model:

def save(self, *args, **kwargs):
    "update number available on save"
    self.available = self.inventory - self.committed

    super(Product, self).save(*args, **kwargs)

You could also put logic in there that would do something if self.available became negative.

Seth
Don't put calculated fields in the database like this. Use a property instead.
Ignacio Vazquez-Abrams
how do I use a property as such Ignacio thats were I'm confused
Jon
should probably be: super(Product, self).save(*args, **kwargs)
stefanw
A: 

I dont understand how to override the save method

Jon
Jon, please post follow-ups either as comments to your question, or by editing your question - don't post them as answers.
Dominic Rodger
A: 

The property is actually removing the available integer field off the admin page it seems

Jon
that was well as its not doing the math when I used the property
Jon
A: 

See the Django documentation for model properties

Matthew Talbert
+1  A: 

You've bound both a Django field and a vanilla Python property to the same name on your model. One of these attributes is masking the other, which is why you're getting unexpected behavior in the Django admin. This is almost certainly not what you want.

Override the save method and remove your def available property entirely.

Ignacio is trying to help you keep your data normalized by not storing information in your DB twice. It's a good practice to follow in the general case, but there are many times when you want to store calculated values in your DB. This seems like a practical use of data duplication.

Don Spaulding
+1  A: 

Don is correct that you have the name available duplicated, because you have both a field and a property. Drop the field.

This is what I said when I gave you the solution to this problem in your original question - I explicitly said "drop the existing 'available' field". Following half a solution is never going to work.

However I fundamentally disagree with Seth and Don who recommend overriding the save() function to calculate this value. That is a totally unnecessary duplication of data. The property is the correct solution.

Daniel Roseman
well using just the available property will not allow for users to see how much is available when entering in new data which is not what I want.
Jon
I think it's possible to see it, even in the standard admin (though I can't recall how at the moment)
Agos
Both approaches (drop the property and override save() or drop the field) are valid approaches. Daniel's dislike for of "totally unnecessary duplication of data" could be restated as a dislike for denormalizing too early in a project. Denormalization by adding redunant data can be a very effective way to improve performance. In this case, it probably too early for denormailzation but you may have other reasons for going with just the field.
istruble
A: 

It seems like you may have two problems; the overlapping available property+field and availability not showing up as you expect in the admin.

Choose one way (property or field) to represent the availability and go with it. Don and Seth have shown a way to do it using a field and Daniel and Ignacio have suggested going with a property.

Since you really want this field to show up in the admin just go with the field; give it a helpful help_text="...", remove the @property, and override save().

class Product(models.Model):
    # ...
    availability = models.IntegerField(help_text="(updated on save)")

    # Use Seth's save()
    def save(self, *args, **kwargs):
        self.availability = self.inventory - self.commited
        super(Product, self).save(*args, **kwargs)

This is not the best way to do things in terms of normalized data but it will probably be the simplest solution to your current problem.

If you are using trunk instead of Django-1.1.1, you can also use readonly_fields in the admin.

istruble
thank you how does the property field actually work in this case? I was thinking the definition of a property is to place it on an object such as the integer field and the math will be calculated and returned as committed and inventory were filled out?
Jon
one last thing when I set available to editable false it doesnt show the field?
Jon
Ack! You are right. Forget my editable=False idea. I was thinking that it would work the same way that readonly_fields = ('availability',) works in trunk. You should still see the help_text under the input field in your admin. Updating the post to include only help_text.
istruble
thank you so much is there anyway I can make the field readonly? I also had one more question about a completely different thing. It would be easier if I could email you or something. Thank you so much. I really appreciate it
Jon
If you are tracking trunk, you can use readonly_fields in your admin. If you are not, you can still take a look at the code in trunk that displays the read only fields and do something similar yourself. It is best to create a new question for your other question, that way you get more people looking at it and everyone on stackoverflow can all benefit from the answer.
istruble