Hello I am new to django and wondering what the best practices are for a model I am designing.
I have a field, tn, which needs to increase by one every time a new instance of that class is created. I also have another field, Counter, which needs to increase by 1 every n times tn increases. What is the best practice here? Is it better to have Counter as a separate class or a field within tn?
Depending on which is better how would you go about doing that? Any help is greatly appreciated.
class Tn(models.model):
tn = models.PositiveIntegerField(unique=True, primary_key=True, editable=False)
counter = models.PositiveIntegerField(editable=False
I’m a bit confused.
What are you trying to accomplish?
But if i understood correctly
The tn field should be a AutoField or BigAutoField, this documentation covers them.
But the counter field is always to be the same as the maximum number of tn, if that’s the case, then this should not be a field on the database, but a computed valued. See aggregation and the section Cheat Sheet contains a example using the Max function
Hello thank you for your quick reply, I think I understand about the TN field - I have read that and changed it to:
tn = models.AutoField(primary_key=True)
I want the Counter field to increase every time TN is divisible by 40 without remainder or every 40 tn.
So for example:
TN 1-40, Counter 1
TN 41-80, Counter 2
TN 81-120, Counter 3
etc.
Does this make more sense what I am trying to achieve?
Since this can be computed quickly from tn, I would not make it a separate field. I would compute it on the fly as necessary.
Side note: In a production environment, you may end up with “gaps” in your sequence. There is no guarantee that you will have an instance of your model for every distinct value of tn. You need to decide how important that factor is, and how that affects your Counter.
How would I end up with gaps? with tn defined as this:
tn = models.AutoField(primary_key=True)
Will the tn not just automatically increase.
How would I compute it on the fly? I have this in my models.py file not sure if this is the right way to go:
Because in a production environment, you will have multiple processes running. Process A may get value 345 to assign while process B gets 346. Now, if process A fails for whatever reason, you will not have a 345 in the database. Process C is not going to go back to fill the gap, it’s going to continue on with 347.
How likely this is to happen will depend upon the system load and the reliability of the systems being run (host, database, network between them, network between the server and the user, etc, etc, etc.)
Side note: I’d use if self.tn % 40 == 0: return self.tn//40.
I see - that’s fine, counter doesn’t need to be for EXACTLY 40 a few errors will be ok, also thinking about the number of users at once etc I don’t think it will be a problem. What will happen if an entry of TN gets deleted? Will the Counter value persist?
Hi Ken, I have tried this above and in my admin.py file I get the following error:
Exception Type: FieldError at /admin/stocks/weighbridge/add/
Exception Value: Unknown field(s) (counter_number) specified for Weighbridge. Check fields/fieldsets/exclude attributes of class WeighbridgeAdmin.
I also get a similar error for self.net_weight. How do I use the results of the _counter_number property? as a field?
This is what I’ve got but not sure it is best practices, and it works with the lines commented out but when I try to use them I get a different type of error.
#admin.py
from .models import InloadBook
admin.site.register(InloadBook)
With those lines uncommeted I get this error:
File "C:\Users\georg\onedrive\storeapp\demo0922\stocks\models.py", line 173, in save
if self.tn % 40 == 0:
^^^^^^^^^^^^
Exception Type: TypeError at /admin/stocks/inloadbook/add/
Exception Value: unsupported operand type(s) for %: 'Weighbridge' and 'int'
I get I probably need some sort of clause for the data types but not sure the best way to go about this rather than fudging something that isn’t ideal I’d like to learn how to do it the best way.
Correct, because tn is not a value in Inloadbook. Here, tn is an instance of Weightbridge. (In your earlier example, tn was a value, an AutoField - I don’t understand what you’re trying to do here.)
What does your Weightbridge model look like?
It may even be better if you just tried to explain a little bit of the background and what you’re trying to model with this.
Hey Ken, yes I have moved my Counter field to another class as it makes more sense with the data. The overall picture is I am trying to develop a Weighbridge system that has tickets for when a delivery is made and every 40 loads that are a delivery not a collection (i.e. Inload) need to be grouped together using the Counter field. so the tn is the primary key on the weighbridge class and also the primary key on the inload in a onetoone relationship. the weighbridge class looks like this:
#models.py
class Weighbridge(models.Model):
weighdate = models.DateTimeField(default=now)
tn = models.AutoField(primary_key=True)
PAYMENT_CHOICE = [( "PO",'£'), ('CA', "CASH"), ("AC",'ACC'), ('CH', 'CHEQUE')]
payment = models.CharField(choices=PAYMENT_CHOICE, max_length=20, default='AC')
quality_control = models.BooleanField(default=True, verbose_name='The Vehicle/Trailer has been inspected and is clean & ready for Loading/Tipping') #REMOVE THE DEFAULT
supplier = models.ForeignKey(Supplier,on_delete=models.PROTECT)
variety = models.ManyToManyField(to=Variety, related_name='weighbridge', blank=True)
loading_statement = models.BooleanField(default=True, verbose_name='Loading / Unloading Equipment Clean and Ready for Use.' )
#etc...
Anyway, with this in mind, if self.tn is an instance of Weighbridge, how would you then access the tn attribute of that object? (Again, looking for one statement.)
ok so if I wanted the supplier for that same tn would it be self.tn.supplier ? and we can use self.tn to reference the specific Weighbridge object because it is the primary key?