Changing django default pk with AutoField to BigAutoField - django

My model has a default pk with AutoField (integer) but later on i discovered that i need to use BigAutoField instead!
And also i have data in then with other models referencing the student model:: how do i change the pk field to BigAutoField and also reflects on other referencing models
class Student(models.Model):
matric_no = models.CharField(max_length=20, unique=True) # first set it to U(random)
password = models.CharField(max_length=128)
session = models.ForeignKey(Session, null=True)
programme = models.ForeignKey(Programme, null=True)
school = models.ForeignKey(School, null=True)
course_comb = models.ForeignKey(CourseComb, null=True)
serial = models.IntegerField(null=True)
current_level = models.CharField(max_length=3, choices=LEVEL_CHOICES, default='100', null=True)
last_login = models.DateField(null=True)
is_active = models.CharField(max_length=1, default=1, choices=((1, 1), (0, 0)))
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(auto_now=True)
a model referencing Student
class Profile(models.Model):
student = models.OneToOneField(Student, on_delete=models.CASCADE)
attachment = models.ImageField(null=True, blank=True, verbose_name="Profile Image")
surname = models.CharField(max_length=255, null=True, verbose_name="Surname")
othernames = models.CharField(max_length=255, null=True, verbose_name="Othernames")
SEX_CHOICES = (
("M", "Male"),
("F", "Female")
)

Set primary_key=True in the field definition:
id = models.BigAutoField(primary_key=True)
If you want to use this in multiple models you could also make an abstract model and let others inherit it:
class BigPkAbstract(models.Model):
id = models.BigAutoField(primary_key=True)
class Meta:
abstract = True
And in your other models:
class SomeModel(BigPkAbstract):
<your model here>
‌

Related

Joining more than 2 tables for reports in django and extract all the fields from the joined table

I am joining the ClientDetails, AssignmentTable and CallDetails table to get a view as to which telecaller a particular client has been assigned to and get the latest call details as well. However I am unable to accomplish that using django ORM.
ISSUE:
I am trying to access the fields inside the assignment table and call table but I am getting only the ids and not the other fields.
Question:
How do I extract all the columns from the assignment and call details table which has the client id as 1?
This is the SQL Query that I am trying to come up with:
SELECT t1.uid, t1.phone_number, t1.client_name, t1.base, t1.location, t2.assigner, t2.bpo_agent, t2.cro_agent, t3.bpo_status_id, t3.cro_status_id, t3.agent_id_id
FROM public.bpo_app_clientdetails t1
LEFT JOIN public.bpo_app_assignmentdetails t2 ON t1.uid = t2.client_id_id
LEFT JOIN public.bpo_app_calldetails t3 ON t1.uid = t3.client_id_id;
Below is the model file:
class ClientDetails(models.Model):
uid = models.AutoField(primary_key=True)
phone_number = PhoneNumberField(unique=True)
client_name = models.CharField(max_length=50, blank=True, null=True)
base = models.CharField(max_length=50, blank=True, null=True)
location = models.CharField(max_length=50, blank=True, null=True)
class Meta:
verbose_name_plural = "Client Contact Detail Table"
def __str__(self):
return f"{self.phone_number}, {self.client_name}"
class AssignmentDetails(models.Model):
uid = models.AutoField(primary_key=True)
client_id = models.ForeignKey(
ClientDetails,
on_delete=models.PROTECT,
related_name='assignment_details'
)
date_and_time = models.DateTimeField(auto_now_add=True, blank=True)
assigner = models.ForeignKey(
User,on_delete=models.PROTECT,
related_name='AssignerAgent',
db_column='assigner',
)
bpo_agent = models.ForeignKey(
User,on_delete=models.PROTECT,
related_name='bpoAgent',
db_column='bpo_agent',
)
cro_agent = models.ForeignKey(
User,on_delete=models.PROTECT,
related_name='croAgent',
db_column='cro_agent',
)
class Meta:
verbose_name_plural = "Client Assignment Detail Table"
def __str__(self):
return f"{self.uid}"
class CallDetails(models.Model):
uid = models.AutoField(primary_key=True)
date_and_time = models.DateTimeField(auto_now_add=True, blank=True)
client_id = models.ForeignKey(
ClientDetails,
on_delete=models.PROTECT,
related_name='call_details'
)
agent_id = models.ForeignKey(EmployeeDetails_lk,on_delete=models.PROTECT)
bpo_status = models.ForeignKey(BpoStatus_lk,on_delete=models.PROTECT, blank=True, null=True)
cro_status = models.ForeignKey(CroStatus_lk,on_delete=models.PROTECT, blank=True, null=True)
required_loan_amt = models.CharField(max_length=50, blank=True, null=True)
remarks = models.CharField(max_length=500, blank=True, null=True)
loan_program = models.ForeignKey(LoanProgram_lk, on_delete=models.PROTECT, blank=True, null=True)
disbursement_bank = models.ForeignKey(Banks_lk, on_delete=models.PROTECT, limit_choices_to={'loan_disbursement_status': True}, blank=True, null=True)
class Meta:
verbose_name_plural = "Client Call Detail Table"
def __str__(self):
return f"{self.uid}"
>>> qry=ClientDetails.objects.values('assignment_details','call_details').filter(uid=1)
>>> qry
<QuerySet [{'assignment_details': 1, 'call_details': None}]>
>>> print(a.query)
SELECT "bpo_app_assignmentdetails"."uid", "bpo_app_calldetails"."uid" FROM "bpo_app_clientdetails" LEFT OUTER JOIN "bpo_app_assignmentdetails" ON ("bpo_app_clientdetails"."uid" = "bpo_app_assignmentdetails"."client_id_id") LEFT OUTER JOIN "bpo_app_calldetails" ON ("bpo_app_clientdetails"."uid" = "bpo_app_calldetails"."client_id_id") WHERE "bpo_app_clientdetails"."uid" = 1
You can use prefetch_related() to achieve this. I just use some sample models here for better understanding.
class Company(models.Model):
name = models.CharField(null=True, blank=True, max_length=100)
class Project(models.Model):
name = models.CharField(null=True, blank=True, max_length=100)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
class Employee(models.Model):
name = models.CharField(null=True, blank=True, max_length=100)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
In your views.py function write the below lines to get the desired results
companies = Company.objects.filter(id=1).prefetch_related('project_set', 'employee_set')
for company in companies:
print(company.project_set.values()) # This will print this company projects
print(company.employee_set.values()) # This will print this company employees
Note: If you use related_name in your ForeignKey relationship, make sure that you access with that name instead of model_set inside prefetch_related()

Filter A foreignkey child model instance in a form field based on the parent value selected in another field in the same field

Filter A foreignkey child model instance in a form field based on the parent value selected in another field in the same field
class Agents(models.Model):
id = models.AutoField(primary_key=True)
admin = models.OneToOneField(CustomUser, on_delete = models.CASCADE)
address = models.TextField()
gender = models.CharField(max_length=50)
numero_telephone = models.CharField(max_length=50)
departement_id = models.ForeignKey(Departements, on_delete=models.CASCADE, default=1)
role_id = models.ForeignKey(Roles, on_delete=models.CASCADE, default=1)
profile_pic = models.FileField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = models.Manager()
class Projets(models.Model):
id = models.AutoField(primary_key=True)
projet_name = models.CharField(max_length=255)
departement_id = models.ForeignKey(Departements, on_delete=models.CASCADE, default=1) #need to give defauult course
manager_id = models.CharField(max_length=255, null=True,blank=True)
membres_id = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = models.Manager()

how to write a signal to change a field in a model after another filed from another model is changed

I have a user model that has to go through several tasks such as completing their information, taking some tests, and interviews. So I added a progress level field that shows the user status at the moment. this is my model:
class User(AbstractUser):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
isPreRegistered = models.BooleanField(default=False)
role = models.CharField(max_length=25, null=True, choices=USER_ROLE_CHOICES, default=USER_ROLE_CHOICES[0][0])
role_id = models.CharField(max_length=10, default='applicant')
username = models.CharField(unique=True, max_length=13)
first_name = models.CharField(max_length=32, null=True, default=None)
last_name = models.CharField(max_length=64, null=True, default=None)
gender = models.CharField(max_length=10, null=True)
personalInfo = models.OneToOneField(PersonalInfo, on_delete=models.CASCADE, null=True)
contactInfo = models.OneToOneField(ContactInfo, on_delete=models.Case, null=True)
eliteInfo = models.OneToOneField(EliteInfo, on_delete=models.CASCADE, null=True)
progress_level = models.CharField(max_length=25, null=True, choices=USER_PROGRESS_LEVELS, default=USER_PROGRESS_LEVELS[0][0])
and there are multiple models which are connected to the user model using a foreign key relation.
this is one of the models I added here for instance:
class PsychologicInfo(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
final_assessment = models.TextField(null=True, blank=True)
is_approved = models.CharField(max_length=64, blank=True)
is_interviewed = models.BooleanField(default=False)
I want to write a signal or a save method that does something like this:
if the is_interviewed field was True, change that progress_level to USER_ROLE_CHOICES[1][0]
I have no idea how to do this so thanks for the tips
You can override the .save() method of PsychologicInfo
class PsychologicInfo:
...
def save(self):
super().save()
if self.is_interviewed:
self.user.role = USER_ROLE_CHOICES[1][0] # or enter value here
self.user.save()
or you can use Django signals.

How to join Objects in Django with Foreign Keys 2 tables deep

I have 2 models each with foreign keys to 2 tables. I'm trying to join the 1st table to the 3rd.
Here are my models:
Model 1:
class AppBillingBil(models.Model):
id_bil = models.AutoField(primary_key=True)
idtrp_bil = models.ForeignKey(AppTradingPartnerTrp, models.DO_NOTHING, db_column='idtrp_bil', blank=True,
null=True)
idcst_bil = models.ForeignKey(AppCustomerCst, models.DO_NOTHING, db_column='idcst_bil')
idbtp_bil = models.ForeignKey(AppBillingTypeBtp, models.DO_NOTHING, db_column='idbtp_bil')
class Meta:
db_table = 'app_billing_bil'
ordering = ['id_bil']
Model 2:
class AppCustomerCst(models.Model):
id_cst = models.AutoField(primary_key=True)
is_active_cst = models.BooleanField()
name_cst = models.CharField(max_length=50, blank=True, null=True)
Model 2:
class AppTradingPartnerTrp(models.Model):
id_trp = models.AutoField(primary_key=True)
tpid_trp = models.CharField('TPID', max_length=50, blank=True, null=True)
name_trp = models.CharField('Name', max_length=50)
Final Model Needed:
class AppCustomerTpRel(models.Model):
id_rel = models.AutoField(primary_key=True)
idcst_rel = models.ForeignKey(AppCustomerCst, models.DO_NOTHING, db_column='idcst_rel')
idtrp_rel = models.ForeignKey(AppTradingPartnerTrp, models.DO_NOTHING, db_column='idtrp_rel')
cust_vendor_rel = models.CharField(max_length=50, blank=True, null=True)
I need to join on the following criteria:
idtrp_bil__id_trp = idtrp_rel
idcst_bil__id_cst = idcst_rel
And I need to be able to use the cust_vendor_rel field from AppCustomerTpRel in a filter query on AppBillingBil
After reading the docs here: https://docs.djangoproject.com/en/3.0/topics/db/queries/#spanning-multi-valued-relationships I tried this, and was successful:
idcst_bil__appcustomertprel__cust_vendor_rel
I realized I needed to include the target model name in the value grab.

Django filtered queryset in foreignkey lookup

I have a standard model with a foreignkey, in this case from biology: Seed to Taxon. The taxon model includes both Animal and Plant Taxon, and has a category column which is either zoology or botany
When I add a new Seed I get the expected dropdown list, but it supplies the zoology and botany options. How do I filter it so only the botany options are shown? I'm assuming this filter can be applied somewhere in the model? I've tried adding .filter() and .exclude() but they do nothing here.
class Taxon(models.Model):
taxon_id = models.AutoField(primary_key=True)
taxon = models.CharField(max_length=50, blank=True, null=True)
common_name = models.CharField(max_length=50, blank=True, null=True)
taxon = models.CharField(max_length=50, blank=False, null=False)
genus = models.CharField(max_length=50, blank=True, null=True)
category = models.CharField(max_length=50, blank=True, null=True)
# family_name = models.CharField(max_length=50, blank=True, null=True)
def __str__(self):
return str(self.taxon)
class Meta():
managed=False
db_table = 'kap\".\"taxon_manager'
ordering = ["genus","taxon"]
verbose_name_plural = "taxon"
class Seed(models.Model):
seed_id = models.AutoField(primary_key=True)
fraction_id = models.ForeignKey(Fraction, db_column='fraction_id', blank=True, null=True, on_delete = models.PROTECT)
taxon_id = models.ForeignKey(Taxon, db_column='taxon_id', blank=True, null=True, on_delete = models.PROTECT, related_name='seed_taxon')
weight_type = models.CharField(max_length=50)
weight = models.DecimalField(max_digits=10, decimal_places=3)
quantity_type = models.CharField(max_length=50)
quantity = models.IntegerField()
def __str__(self):
return str(self.taxon_id)
class Meta():
managed=False
db_table = 'kap\".\"seed'
ordering = ["taxon_id","fraction_id"]
verbose_name_plural = "seeds"
If the category field in your Taxon model is a choice between "zoology" and "botany", then I would make them choices like so:
class Taxon(models.Model):
ZOOLOGY = 0
BOTANY = 1
CATEGORY_CHOICES = (
(ZOOLOGY, 'Zoology'),
(BOTANY, 'Botany'),
)
<your other fields>
category = models.CharField(max_length=50, choices=CATEGORY_CHOICES, blank=True, null=True)
Then, if you want to filter inside your seed model, you could change your taxon_id field so that it includes limit_choices_to:
taxon_id = models.ForeignKey(
Taxon,
db_column='taxon_id',
limit_choices_to={'category': Taxon.BOTANY},
blank=True,
null=True,
on_delete = models.PROTECT,
related_name='seed_taxon'
)
I haven't explicitly tested this case, but something like the above should work. If you want to filter in other places, then the filter that Juan mentioned in the comment looks good.
Hope this helps.