Fetch data from multiple tables in django views - django

In Django views, I want to fetch all details(Workeraccount.location,Workeravail.date, Workerprofile.*) for any particular wid=1.
SQL Query:
select * from Workeraccount,Workeravail,Workerprofile where Workerprofile.wid=1 and Workerprofile.wid=Workeravail.wid and Workeraccount.wid=Workerprofile.wid;
The corresponding models are as follows:
class Workeraccount(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid', unique=True)
location = models.ForeignKey(Location, db_column='location')
class Meta:
managed = False
db_table = 'workerAccount'
class Workeravail(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid')
date = models.DateField()
class Meta:
managed = False
db_table = 'workerAvail'
class Workerprofile(models.Model):
wid = models.SmallIntegerField(primary_key=True)
fname = models.CharField(max_length=30)
mname = models.CharField(max_length=30, blank=True, null=True)
lname = models.CharField(max_length=30)
gender = models.CharField(max_length=1)
age = models.IntegerField()
class Meta:
managed = False
db_table = 'workerProfile'`

You can do this:
workprofile = Workerprofile.objects.filter(id=1).first()
all_worker_avails = workprofile.workeravail_set.all()
all_workeraccounts = workprofile.workeraccount_set.all()
As Workeraccount and Workeravail are related through Workerprofile, you can get one queryset easily - you will need two separate ones.
You can also do the following:
all_worker_avails = Workeravail.objects.filter(wid=workprofile)
...

Here is how you can do it with only one database call:
workprofile = Workerprofile.objects.get(pk=1)
.select_related('workeravail_set', 'workerprofile_set')
This will fetch all the data for you at once, which can then be used with:
workprofile.workerprofile_set.location #Gets the Workeraccount.location
workprofile.workeravail_set.date #Gets the Workeravail.date
workprofile.fname #Example of Workerprofile.*
As an aside, if you want a shorter way to reference the foreign objects than the "*_set" method, you can set a related_name like
class Workeraccount(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid', unique=True, related_name='waccount')
...
And then replace workeraccount_set with waccount

Related

How to add nested field after creating the ModelSerializer? Not in the class

Basically i want to have fk_inventory as a nested field in StorageRackSerializer but as you guys can see I also need to use StorageRackSerializer in InventorySerializer.
How can i set the field after creating the serializer class?
I have tried creating a fk_inventory field and set it to None and tried to set to InventorySerializer afterwards but didn't work.
class Inventory(models.Model):
inventory_id = models.AutoField(primary_key=True)
fk_building = models.OneToOneField(Store, on_delete=models.CASCADE, unique=True, related_name='inventory')
def __str__(self):
return f"{self.inventory_id}"
class StorageRack(models.Model):
storage_rack_id = models.AutoField(primary_key=True)
quantity = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(50)])
fk_inventory = models.ForeignKey(Inventory, on_delete=models.CASCADE, related_name="storage_racks")
fk_product_id = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, related_name="storage_racks")
def __str__(self):
return f"{self.storage_rack_id}"
class StorageRackSerializer(serializers.ModelSerializer):
fk_product_id = ProductSerializer(read_only=True)
fk_inventory = None
class Meta:
model = StorageRack
fields = ('storage_rack_id', 'quantity', 'fk_inventory', 'fk_product_id')
class InventorySerializer(serializers.ModelSerializer):
fk_building = StoreSerializer()
storage_racks = StorageRackSerializer(many=True)
class Meta:
model = Inventory
fields = ('inventory_id', 'fk_building', 'storage_racks')
StorageRackSerializer.fk_inventory = InventorySerializer()
You can add a field 'fk_inventory' in the validated data from SorageRackSerializer
validated_data = StorageRackSerializer(data=data)
validated_data['fk_inventory'] = InventorySerializer().data

I want to list all elements from abstract class Product and its categories (Smartphones, Tv ) etc

class ProductSerizer(serializers.ModelSerializer):
category = serializers.PrimaryKeyRelatedField(queryset=Category.objects)
title_of_product = serializers.CharField(required=True)
slug = serializers.SlugField(required=True)
image_of_product = serializers.ImageField(required=True)
description_of_product = serializers.CharField(required=True)
price_of_product = serializers.DecimalField(max_digits=12, decimal_places=2, required=True)
class Product(models.Model):
class Meta:
abstract = True
category = models.ForeignKey(Category, verbose_name="category", on_delete=models.CASCADE)
title_of_product = models.CharField(max_length=225,verbose_name="Title",null=True)
slug = models.SlugField(unique=True)
image_of_product = models.ImageField(verbose_name="Image", null=True)
description_of_product = models.TextField(verbose_name = "Descripwtion", null = True)
price_of_product = models.DecimalField(max_digits=10,decimal_places=2, verbose_name="Price", null=True)
and I want to list all elements from categories, but I cannot serialize this class. How should I do ?
Take a look at this thread, which talks about abtract models and how to serialize them

Django multiple table join on using ORM

I am trying to join multiple table using django ORM .i have tried several different way but no luck.
from django.db import models
from compositefk.fields import CompositeForeignKey, CompositeOneToOneField
class Company(models.Model):
code = models.DecimalField(db_column='Code', max_digits=38, decimal_places=0)
srccode = models.SmallIntegerField(db_column='SrcCode')
est = models.DateTimeField(db_column='Est')
rownum = models.BigIntegerField(db_column='RowNum')
class Meta:
manage = False
unique_together = (('code', 'srccode'),)
db_table = 'Company'
class Floor(models.Model):
code = models.DecimalField(db_column='Code', max_digits=38, decimal_places=0)
srccode = models.SmallIntegerField(db_column='SrcCode')
depcode = models.DecimalField(db_column='DepCode', max_digits=38, decimal_places=0)
depsrccode = models.SmallIntegerField(db_column='Depsrccode')
floorname = models.CharField(db_column='FloorName')
rownum = models.BigIntegerField(db_column='RowNum')
company = CompositeForeignKey(Company,on_delete=models.CASCADE,to_fields={'code':'code','srccode': 'srccode'})
department= CompositeOneToOneField(Department,on_delete=models.CASCADE,to_fields={'depcode':'depcode','depsrccode': 'depsrccode'})
class Meta:
manage = False
unique_together = (('depcode', 'depsrccode','floorname'),)
db_table = 'floor'
class SubCompany(models.Model):
code = models.DecimalField(db_column='Code', max_digits=38, decimal_places=0)
srccode = models.SmallIntegerField(db_column='SrcCode')
subname = models.CharField(db_column='SubName')
rownum = models.BigIntegerField(db_column='RowNum')
location = models.CharField(db_column='Location')
department = models.CharField(db_column='Department')
company = CompositeForeignKey(Company,on_delete=models.CASCADE,to_fields={'code':'code','srccode': 'srccode'})
class Meta:
manage = False
unique_together = (('code', 'srccode','subname','rownum'),)
db_table = 'SubCompany'
basically i am trying to get data as per below row sql
SELECT Location, Department, Subname, t.* from [Floor] t join [SubCompany] s on t.code = s.code and t.srccode = s.srccode;"
what is the equilant Django Orm of above SQL query.?
is there any alternative solution apart from raw sql in django.?
Thanks

Nested serializers in drf throws error with one to one field

My input json is :
{
"availability": "Current",
"drive_type": [{
"drive_name": "drive1",
"requirements": {
"performance_unit": "by_iops",
}
}]
}
I am getting error Cannot assign "
OrderedDict([('performance_unit', 'Basic')])":
"DriveType.requirements" must be a "Requirements" instance
.I am not able to figure it out to map in create method for one to one fields in tables
Below are my models.py
class ProductLine(models.Model):
availability = models.CharField(max_length=20, blank=True, null=True)
class Meta:
db_table = "product_line"
class DriveType(models.Model):
drive_name = models.CharField(max_length=20, blank=True, null=True)
product_line = models.ForeignKey(ProductLine, related_name="drive_type")
class Meta:
db_table = "drive_type"
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name="requirements")
class Meta:
db_table = "requirements"
Serializers.py :
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer(many = True)
class Meta:
model = DriveType
fields = (
"drive_name","workload_type")
class ProductLineSerializer(serializers.ModelSerializer):
drive_type = DriveTypeSerializer(many=True)
class Meta:
model = ProductLine
fields = ('availability', "drive_type")
def create(self, validated_data):
print("validate_data",validated_data)
drive_type_data = validated_data.pop("drive_type")
product_line = ProductLine.objects.create(**validated_data)
for drive_data in drive_type_data:
drive_type = DriveType.objects.create(product_line=product_line, **drive_data)
return product_line
You have one to one relationship of DriveType and Requirements
So remove many = True from DriveTypeSerializer for RequirementsSerializer
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer()
class Meta:
model = DriveType
fields = ("drive_name","workload_type")
Your input json has only one object of requirements not a list

Django Nonetype object has no attribute 'id'

I want create product element and redirect to him page
def newprodcreate(request, c_id):
if models.company.objects.get(email = request.user.username).id == int(c_id):
name = request.POST['newprodname']
comp = models.company.objects.get(id = int(c_id))
prod = models.product()
prod.name = name
prod.comp_id = int(c_id)
prod.address = comp.address
prod.lat = comp.lat
prod.lng = comp.lng
prod.phone = comp.phone
prod.cur_id = 2
prod.save()
return HttpResponseRedirect("/p/" + str(prod.id))
the element created in database, but prod.id is Null
model:
class product(models.Model):
class Meta:
db_table = "product"
id = models.IntegerField(primary_key=True)
crdate = models.DateTimeField(default = datetime.now())
comp_id = models.IntegerField()
categ = models.CharField(max_length=200, default="")
img = models.FileField(upload_to=MEDIA_ROOT +"/product/", max_length=200)
name = models.CharField(max_length=200)...
Dear michael in django ORM for creating autho field or serial field which used for id primary key or etc we use Autofield instead of integer field .
id = models.AutoField(primary_key=True)
your model in corrected state:
class product(models.Model):
class Meta:
db_table = "product"
id = models.AutoField(primary_key=True)
crdate = models.DateTimeField(default =
datetime.now())
comp_id = models.IntegerField()
categ = models.CharField(max_length=200, default="")
img = models.FileField(upload_to=MEDIA_ROOT. +"/product/", max_length=200)
name = models.CharField(max_length=200)...
For django models There will be a default field with name "id" which is auto increment field. you have override that id with IntegerField that is id = models.IntegerField(primary_key=True)
So you have to provide id explicitly every time when you create product object
Better solution is to change id IntegerField to AutoField
id = models.AutoField(primary_key=True)
Then your id will be created automatically no need to pass id every time you create new object.