How to create calculated fields?

Django noob here. I did the tutorial from beginning to end and I started a project on my own.

I have trouble setting up the Django model for a strange attractor (fractal). The model expects the user to enter a specific string (parameters), which will be used to build a special strange attractor. This attractor has some attributes that should be stored in the database. The trouble is I cannot refer to the value of the parameters field without some reference to the class. I have isolated the problem in the create function but I still cannot call this function.

The order of events should be:

  • user enters the parameters
  • parameters are read and used to build a strange attractor (attractor)
  • the attractor is used to fill the calculated fields
  • all fields are committed to the database

Anyone some idea how to set this up correct or point me to an example?

```
class StrangeAttractor(models.Model):
  parameters = models.CharField('Coefficient String', max_length=200)
  pretty = models.IntegerField('Pretty')

# create a Quadratic map from the coefficients
def create(self):
    instance = self.objects.first() # get(id=1)
    value = instance.parameters
    self.attractor = Quadratic(value, 10000)

# define helper functions to extract the attributes of 
# the strange attractor
def get_status(self):
    return self.attractor.status

def get_lyapunov(self):
    return self.attractor.lyapunov

def get_fractal_dim(self):
    return self.attractor.fractal_dimension()

def get_coverage(self):
    return self.attractor.coverage

def get_distance(self):
    return self.attractor.distance

def get_date(self):
    now = datetime.now()
    return now.strftime("%Y-%m-%d %H:%M:%S")

status = property(get_status) # models.CharField('Status', max_length=40)
lyapunov = property(get_lyapunov) # models.FloatField('Lyapunov 2')
fract_dim = property(get_fractal_dim) # models.FloatField('Fractal Dimension')
coverage = property(get_coverage) # models.FloatField('Coverage')
distance = property(get_distance) # models.FloatField('Distance')
disc_date = property(get_date) # models.DateTimeField('Discovery Date')

The Model defines the structure of the data - your model fields are going to be instances of models.CharField, models.FloatField, models.IntegerField, etc. The model field definitions themselves do not define what goes in those fields, other than possibly a default value.

The Model definition is a “template” to be used when creating instances of that model.

So, fields like status are going to be defined as:
status = models.CharField(max_length=40)

Then, your view is going to accept the input from a form, and create the instance of the model, using whatever functions necessary to calculate those values.

Now, the functions being called to calculate values can be physically located in the model - and called when the instance of the model is being saved. (See Models | Django documentation | Django)

You mentioned that you worked your way through the Django tutorial. It would probably help if you reviewed part 2, both the model definitions and the section on Playing with the API.

Also see the docs for the create method.

Thanks very much for your answer and pointing to the logic of Model. Funny, replaying the whole tutorial with my own application is what I am doing and I am in part 2.

And I didn’t know that create is the name of an existing function. I have a lot to do :-). I might be getting back on this connection between Model and View, but I first want to find out. Thanks really for your help.

I followed the links you supplied and I hope I can explain my problem better:

My model is:

        class StrangeAttractor(models.Model):
            coefficients = models.CharField('Coefficient String', max_length=200)
            pretty = models.IntegerField('Pretty')
            status = models.CharField('Status', max_length=40)
            lyapunov = models.FloatField('Lyapunov 2')
            fract_dim = models.FloatField('Fractal Dimension')
            coverage = models.FloatField('Coverage')
            distance = models.FloatField('Distance')
            disc_date = models.DateTimeField('Discovery Date')
            image = models.image = models.BinaryField(blank=True)

And here is how I want to use it:

        In [1]: from sa.models import StrangeAttractor
        
        In [2]: sa = StrangeAttractor(coefficients='INRRXLCEYLFHYAPFSTPHHJMYRYJFBNM')
        
        In [3]: sa
        Out[3]: <StrangeAttractor: INRRXLCEYLFHYAPFSTPHHJMYRYJFBNM>

But I cannot save the model because all calculated fields are not computed, that’s basically all fields except coefficients and pretty. These calculated fields are not editable, just viewable.

As soon as sa = StrangeAttractor(coefficients='INRRXLCEYLFHYAPFSTPHHJMYRYJFBNM') is entered all fields should be calculated. That i couldn’t find in all the documentration I read thus far.

You need to define your functions to create the values.
You then assign those values to the fields either within your view or within the save method of your model.

Again, review the Playing with the API examples to see how an object is created with a field assigned a value by a function call:
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

(where pub_date is defined earlier as:)
pub_date = models.DateTimeField('date published')

Also note later in that same example, where the field question_text is subsequently modified and the modified object is saved.
>>> q.question_text = "What's up?"
>>> q.save()

While the mechanics are slightly different between doing this in the view or in the model, the essence is the same. It’s up to you to define how / where those functions are called to calculate those values and assign them to the appropriate fields.

You can see an example of updating a field of an instance of a model in the view in tutorial step 4.

That’s exactly where I am. My point is when one enters:

>>> q = Question(question_text="What's new?")

the pubication date could be calculated automatically. And what I gather from your answer that’s not possible. I must calculate all the fields outside the model and then call the model, e.g.:

>>> do a lot of calculations, wherever
>>> sa = StrangeAttractor(coefficients='INRRXLCEYLFHYAPFSTPHHJMYRYJFBNM', value1, value2, ... value7, pub_date, image)

I tried to do that in __init__ but that was no success either.

Pity, but thanks for making this clear to me and saving me quite some work :-)!

Really close, except the parameters are named and not positional. It would need to be more like:

>>> sa = StrangeAttractor(
    coefficients='INRRXLCEYLFHYAPFSTPHHJMYRYJFBNM', 
    field_a = value1, 
    field_b = value2, 
    field_c = value3,
    ... 
)

Or, if you don’t want to assign temporary values to every named field:

>>> sa = StrangeAttractor(
    coefficients='INRRXLCEYLFHYAPFSTPHHJMYRYJFBNM', 
    field_a = function_to_calculate_value_1(parameter),
    field_b = function_to_calculate_value_2(parameter), 
    field_c = function_to_calculate_value_3(parameter), 
    ... 
)

That’s correct - the __init__ method is intended to initialize the Model class, not the instances of the model - something entirely different.
Even if you did use the appropriate method in this case (it’s a different function), you probably still wouldn’t want to use it, because that would only be called when the instance is first initialized - which means if you edited the coefficients field after the object was created, it would not recalculate those other parameters.

And that latter reason is one reason why you don’t want to tie these calculations to the initialization of the model, but rather on the setting (or changing) of the coefficients field.

Thank you so much explaining why some things should be done or better avoided. That helps a lot in understanding Django, which is somewhat daunting in all its possibilities :-).