Django generate custom ID - python

I saw this answer but there is no specific answer yet. I want to create custom id that starts with letter. When a new record comes into database I want to change the id to A00001, .... A00002, .... A00010, ...A10000 etc. The id will be always in range 99999- 00001 so how can I do that?
my model is simple:
class Custom(models.Model):
id = models.AutoField(primary_key=True, editable=False)

The AutoField field is a kind of IntegerField field, so you can't use PKs as A00001 .
So, the possible way to achieve the requirement is to change the AutoField to CharField.
Technically you can use "String PK Field" But, you should be aware of the problems/performance issues if you are going to use that.
Here I found one nice SO post that explains the same - Strings as Primary Keys in SQL Database========================================================================
If you still really wish to migrate to String PKs, read the following
First you need to use the CharField instead of AutoField and override the save() method of model
from django.db.models import Max
class Custom(models.Model):
id = models.CharField(primary_key=True, editable=False, max_length=10)
name = models.CharField(max_length=100)
def save(self, **kwargs):
if not self.id:
max = Custom.objects.aggregate(id_max=Max('id'))['id_max']
self.id = "{}{:05d}".format('A', max if max is not None else 1)
super().save(*kwargs)

string as Primary Key not good idea if you plan to do references to the table, so i recommend you to add a property, for example:
class Custom(models.Model):
id = models.AutoField(primary_key=True, editable=False)
#property
def sid(self):
return "A%05d" % self.id
and to do queries you can do processing the input values, for example:
s_input = "A%05d" % 231 # 'A00231'
number = s_input[1:] # '00231'
input_id = int(number) # 231

I also have another way, That i use in my django project. Here are some code
def ids():
no = Employee.objects.count()
if no == None:
return 1
else:
return no + 1
emp_id = models.IntegerField(('Code'), default=ids, unique=True, editable=False)
id = models.CharField(primary_key=True, editable=False, max_length=30)
def save(self, **kwargs):
if not self.id:
self.id = "{}{:08d}".format('ABC', self.emp_id)
super().save(*kwargs)

It's better to create a new field for the custom id in the models and the process in the backend. You can set that as primary_key with unique=True and editable=False:
class Custom(models.Model):
id = models.Autofield(primary_key=True, editable=False, max_length=10)
uid= models.CharField(max_length=100, unique=True)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.set_uid() # calling the set_uid function
def set_uid(self):
if not self.uid: # if uid of the instance is blank
uid = "CUS" + str(self.id + (10 ** 5)) # generating the uid
customer= Custom.objects.get(id=self.id) # getting the instance
customer.uid = uid # allocating the value
customer.save() # saving the instance
def __str__(self):
return self.uid
Can also merge the set_uid() inside the save() where the function is called:
class Custom(models.Model):
id = models.Autofield(primary_key=True, editable=False, max_length=10)
uid= models.CharField(max_length=100, unique=True)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not self.uid: # if uid of the instance is blank
self.uid = "CUS" + str(self.id + (10 ** 5)) # generating the uid and allocating the value
self.save() # saving the instance
def __str__(self):
return self.uid

I tried to use answer of #JPG, but it has a bug.
The bug is becasue it can't auto increment.
I fixed the bug, and this my resultant code:
def save(self, **kwargs):
if not self.id:
max = YourModel.objects.aggregate(
id_max=models.Max('id'))['id_max']
if max is not None:
max += 1
else:
max = 100
self.id = "{:08d}".format(
max) # id from 100 to start
super().save(*kwargs)

Related

How to add prefix value in model for two columns...?

I am trying to add a Prefix(CLI, CID) into the two columns in one table but its working for me only the Primary Key but other field is not generating the CID00001 like this....
this is my model.py
class Prefix(models.Model):
cdClientID = models.CharField(primary_key=True, editable=False, max_length=200)
cdClientNumber = models.CharField(editable=False, max_length=200)
class Meta:
unique_together = (('cdClientID', 'cdClientNumber'),)
def save(self, *args, **kwargs):
if not self.cdClientID:
prefix = 'ATT{}'.format('')
prev_instances = self.__class__.objects.filter(cdClientID__contains=prefix)
if prev_instances.exists():
last_instance_id = prev_instances.last().cdClientID[-4:]
self.cdClientID = prefix + '{0:08d}'.format(int(last_instance_id) + 1)
else:
self.cdClientID = prefix + '{0:08d}'.format(1)
super(Prefix, self).save(*args, **kwargs)
here its genrating the only clientID its PK and how can i generate the clientnumber also CLN00001 with autoIncrement
tnx in advance...
Not sure how this is going to work in actual web servers, but it seems to work in Django shell. Take your code:
class Prefix(models.Model):
cdClientID = models.CharField(primary_key=True, max_length=200)
The reason why I removed editable=False is because you need to do something like the following:
>>> str = 'CLN' + 1
>>> p = Prefix.objects.create(cdClientID=str)
You need to parse number formats later on to get the leading zeros, but this is briefly how you do this.
Reference

How can I change django model field value automatically with method?

class AssignedTask(Task):
deadline = models.DateField()
amount = models.IntegerField(blank=True)
priority = models.FloatField()
def priority_set(self):
delta = self.deadline - timezone.now().date()
self.priority = delta.days / self.importance
self.save()
def __str__(self):
return self.title
I want to set a value of the 'priority' field when data AssignedTask is created, but the priority field always returns null when I create data with a mutation in graphQL API.
Overwrite the save method
def save(self):
self.priority_set()
super().save()

The instant type changes to int in Foreign Key in Django

This is my models.py in django
class Site(models.Model):
# Site ID
siteID = models.CharField(max_length=255, null=True, unique = True)
def __str__(self):
return "{} ".format(self.siteID,)
class EndDevice(models.Model):
edevID = models.CharField(max_length=255)
siteID = models.ForeignKey(Site, on_delete=models.CASCADE)
deviceCategory = models.BigIntegerField()
And this is the method to post in views.py:
class RegisterSite(generics.ListAPIView):
'''
GET site/
POST site/
'''
queryset = Site.objects.all()
serializer_class = DataSerializer
# POST Regisger Site
def post(self, request, *args, **kwargs):
a_site = Site.objects.create(
siteID=request.data["siteID"],
# edevID=request.data["edevID"]
)
return Response(
data=DataSerializer(a_site).data,
status=status.HTTP_201_CREATED
)
class RegisterDevice(generics.ListAPIView):
'''
GET device/
POST device/
'''
queryset = EndDevice.objects.all()
serializer_class = DeviceSerializer
def post(self, request, *args, **kwargs):
siteID, created = Site.objects.get_or_create(
siteID=request.data["siteID"],
)
a_site = EndDevice.objects.create(
edevID=request.data["edevID"],
siteID = siteID,
deviceCategory=request.data["deviceCategory"],
)
return Response(
data=DeviceSerializer(a_site).data,
status=status.HTTP_201_CREATED
)
So what I am trying t do here is use the siteID from class Site for class EndDevice. But when I enter/ chose the value of siteID in Enddevice it changes to integer value. I checked the data base and it shows me int as its (siteID in EndDevice) characteristics. I was wondering how could I get the real value of siteID instead of an integer value.And I can accept character values while posting for class Site.
If the question is vague or unclear, please update me.
Thanks
EDIT
enter image description here
The serializer looks like:
class DataSerializer(serializers.ModelSerializer):
class Meta:
model = Site
fields = ("siteID",)
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = EndDevice
fields = ("edevID", "siteID", "deviceCategory")
Q:
when I enter/ chose the value of siteID in Enddevice it changes to integer value
Well the reason why it gets converted to int is because you haven't specified your own primary key field so Django uses its default primary key as Id field which is an integer field.
A:
Inside of Site model change this:
siteID = models.CharField(max_length=255, null=True, unique = True)
to this:
siteID = models.CharField(max_length=255, primary_key = True)
Now what that does is that it sets siteID as your primary_key instead of django's default Id.
See the docs

Error initialising model with UUIDField django

Problem :
So, I have been trying to make an object of the model Trade with an initial value to the identifier from my custom function gen_rand_string().
But the problem is when, I am initialising it.
If I remove the initializer and set the UUIDField to NULL, it works out to be fine.
This is the error, I am getting :
TypeError at /admin/account/trade/add/
int() argument must be a string or a number, not 'Trade'
My Trade class :
class Trade(models.Model):
NEW_TRADE = 'N'
CANCELLED_TRADE = 'C'
PENDING_TRADE = 'P'
STATUS_OF_TRADE = (
(NEW_TRADE, "New"),
(CANCELLED_TRADE, "Cancelled"),
(PENDING_TRADE, "Pending")
)
TYPE_BUY = 'B'
TYPE_SELL = 'S'
TYPE_OF_TRADE = (
(TYPE_BUY, "Buy"),
(TYPE_SELL, "Sell")
)
user = models.OneToOneField('UserProfile', related_name='trades')
identifier = models.UUIDField(null=False, editable=False)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
finished_at = models.DateTimeField(auto_now_add=True)
amount = models.DecimalField(max_digits=19, decimal_places=10, null=False)
type = models.CharField(max_length=2, choices=TYPE_OF_TRADE, null=False)
status = models.CharField(max_length=2, choices=STATUS_OF_TRADE, default=PENDING_TRADE, null=False)
def __init__(self, *args, **kwargs):
self.identifier = gen_rand_string()
super(Trade, self).__init__(self, *args, **kwargs)
class Meta:
ordering = ('created_at',)
def __unicode__(self):
return self.identifier
def __str__(self):
return self.identifier
My gen_rand_string() :
def gen_rand_string(purpose=''):
if purpose:
return purpose + '_' + get_random_string(length=64 - len(purpose))
else:
return get_random_string(length=64)
Suggestions :
I am making a random string for each trade in not a better way, would someone suggest somewhat better option, or something they would have it in their place.
I am using python 2.7 which is the reason of my initialisation of the object in a different way
Thanks.
You are discouraged from overriding __init__ for Django models. You use your gen_rand_string as the field's default:
identifier = models.UUIDField(null=False, editable=False, default=gen_rand_string)
However you probably don't need to define your own gen_rand_string method - just use uuid.uuid4, as in docs for UUIDField.
identifier = models.UUIDField(null=False, editable=False, default=uuid.uuid4)
problem is with your init function syntax.
def __init__(self, *args, **kwargs):
super(Trade, self).__init__(self, *args, **kwargs)
self.identifier = gen_rand_string()

Django: Creating editable default values for model instance based on foreignkey existance

I'm playing around in Django, and wondering if there is a way to loop through instances of two different models I have created?
/ models.py:
class Tran(models.Model):
name = models.CharField(max_length=300)
description = models.CharField(max_length=2000)
type = models.ForeignKey(TransactionType)
def __str__(self):
return self.name
class DocLink(models.Model):
trann = models.ForeignKey(Transaction)
t_link = models.CharField(max_length=2000)
t_display = models.CharField(max_length=1000)
p_display = models.CharField(max_length=300)
p_link = models.CharField(max_length=2000)
def __str__(self):
return self.link
What I want to do:
Look through each of the Tran instances and create a default value for the links/displays in the DocLink table instead of doing it manually.
Is there anyway I can be pointed in the right direction?
If you want to set links/displays default value in DocLink instance based on trann field you can override model's save method.
For example following code shows how to set t_link if it doesn't have a value:
class DocLink(models.Model):
trann = models.ForeignKey(Transaction)
t_link = models.CharField(max_length=2000)
t_display = models.CharField(max_length=1000)
p_display = models.CharField(max_length=300)
p_link = models.CharField(max_length=2000)
def __str__(self):
return self.link
def save(self, *args, **kwargs):
if not self.t_link:
pass # TODO set self.t_link based on trann
super(DocLink, self).save(*args, **kwargs)
Also you can change model's trann field to:
trann = models.ForeignKey(Transaction, related_name="doclinks")
And then access to all DocLinks of a Tran with:
# t is an instance of Tran class
t.doclinks.all()
So you can loop through this list and do what you want.

Categories