Best Practices for updating one field based on another

Yes

No. self.tn in this context is the Weighbridge object in the same way that a_weigh_bridge is an instance of Weighbridge as a result of the query: a_weigh_bridge = Weighbridge.objects.get(pk=10). It is not the primary key. (See Model field reference | Django documentation | Django)

One step forward One step Back!
sorry.
so self.tn is the Weighbridge object and then to get any of the objects from that Weighbridge object we just use the form self.tn.field which we need to do because tn is a foreign key to InloadBook? The primary key itself is what then?

So in another place in my code I have this

class Weighbridge(models.Model):
    weight_one = models.IntegerField(verbose_name='1st weight', default=0)
    weight_two = models.IntegerField(verbose_name='2nd weight', default=0)

    net_weight = models.IntegerField(verbose_name='Net Weight', default=1)

    def save(self, *args, **kwargs):
        self.net_weight = self.weight_one - self.weight_two
        #we don't need to do self.tn.weight_one as we're not referencing an object from another class?
        super(Weighbridge, self).save(*args, **kwargs)

we don’t need to do self.tn.weight_one as we’re not referencing an object from another class self.weight_one is sufficient? Equally if this is completely wrong we can ignore it and I will continue to try follow your train of thought.

Within a model method, self is the reference to the current model.

In your InloadBook model methods, self is an instance of InloadBook, self.counter_number is an integer and self.tn is an instance of Weighbridge. In this model (InloadBook), self.tn is an instance of Weighbridge only because it’s defined as a relationship field (OneToOne in this case).

In the Weighbridge model methods, self is an instance of Weighbridge, self.weight_one and self.weight_two are integers.

Yes this makes sense now actually Thank you so much. I feel like some fundamental thing has been grasped now.
So I have updated my code to this:

#models.py, InloadBook class
  def save(self, *args, **kwargs):
        print(type(self.tn.tn), self.tn.tn)

        if self.tn.tn % 40 == 0: 
            self.counter_number = self.tn.tn//40
        else:
            self.counter_number =1
        super(InloadBook, self).save(*args, **kwargs)

But I don’t know how to keep counter_number the same as it was as the previous tn instead of self.counter_number =1.

Thanks Ken so much I feel like I understand a lot more what is going on.

In this case, you don’t need the if. The expression self.tn.tn//40 calulates the current counter_number for all values. (Or, you may wish to use self.tn.tn // 40 + 1 if you want your counter_number to be 1-based instead of 0-based.)

this doesn’t look right: `def save(self, *args, **kwargs):
print(type(self.tn.tn), self.tn.tn)

    self.tn.tn % 40 == 0: 
        self.counter_number = self.tn.tn//40
 
    super(InloadBook, self).save(*args, **kwargs)`

No if. No condition. Only the assignment.

so just self.counter_number = self.tn.tn//40 I understand what you mean about the +1 I might chose a completely random starting number based on where the current historical paper system is.

I’m not sure if I need to close off this thread or if you do or if I just leave it. But you have answered my question (and then more) so thank you very much Ken.
When I get onto building views I’m sure I’ll have more though.

Thank you for your patience and guidance,

You can just leave it if you wish - or mark a response as the Solution - your choice and doesn’t matter much either way.