I'm looking for a good example or advice to solve my problem in Django & python. I've simple model like Customer
class Customer(models.Model):
customer_name = models.CharField(max_length=500)
CUSTOMER_CHOICES = [
('pc', 'Private Customer'),
('bc', 'Business Customer'),
]
customer_type = models.CharField(max_length=2, choices=CUSTOMER_CHOICES)
customer_number = models.IntegerField(blank=True)
For all customers, I want to build (and show on page) a specific "Customer Number" based on customer type and a decimal number. I think I might store this value in the Customer table (somethink like this):
|id|customer_name|customer_type|customer_number|
|1 |Private 1 |pc |1 |
|2 |Private 2 |pc |2 |
|3 |Business 1 |bc |1 |
|4 |Private 3 |pc |3 |
|5 |Business 2 |bc |2 |
Of course, when I'll modify the customer name or other value (except customer type and customer number) I don't want to update this number.
I think the bellow code will not work (this is just an example as first thought), because I don't know how the code will work when I'll have two different sessions and when I press the save button at the same time. I don't know this code properly will handle a new object, when we earlier delete e.g. the second row then next we will want to add "new Private Customer".
edited code:
def save(self, *args, **kwargs):
# Get last object by customer type
last_obj = Customer.objects.all().filter(customer_type=self.customer_type).last()
# Checking if we had any entries by customer type
# if not, this element must be first on the list
# next, if new val is None we need to add 1 to the counter
print(last_obj.customer_number)
if last_obj is None:
self.customer_number = 1
else:
if self.customer_number is None:
self.customer_number = last_obj.customer_number + 1
super(Customer, self).save(*args, **kwargs)
Is Django have any tools to do this really nice?
Django doesn't have a single specific tool to achieve your outcome. Here are two options.
1. Save() method
This is basically your approach. But it should be combined with Django's UniqueConstraint.condition (docs) method to make sure the customer_number field is unique for each customer type. Model constraints can be set as a meta option.
class Customer(models.Model):
customer_name = models.CharField(max_length=500)
CUSTOMER_CHOICES = [
('pc', 'Private Customer'),
('bc', 'Business Customer'),
]
customer_type = models.CharField(max_length=2, choices=CUSTOMER_CHOICES)
class Meta:
constraints = [
models.UniqueConstrained(fields=['customer_number'], condition=Q(customer_type='pc'), name='unique_pc_customer'),
models.UniqueConstrained(fields=['customer_number'], condition=Q(customer_type='bc'), name='unique_bc_customer'),
]
If the constraint is violated, an IntegrityError is raised. You can handle the error in your model save() method.
def save():
try:
#Set your customer_number
except IntegrityError:
#Handle the error as you wish
2. Separate models You could define two additional models, one for pc one for bc. Those models would then be related to your Customer model one-to-one. The id of your pc model instance and bc model instance would be your customer number.