Django ORM multiple inner join in query - python

I want to be able to do queries involving multiple inner joins using Django ORM, here's my model (showing only relevant fields)
class Students(models.Model):
class Status(models.IntegerChoices):
preRegistered = 0 #No ha aceptado terminos y condiciones
Enabled = 1
Disabled = 2
Suspended = 3
Test = 4
id = models.AutoField(primary_key=True)
user = models.ForeignKey(Users, on_delete=models.CASCADE)
trainingPath = models.ForeignKey(trainingPaths, on_delete=models.CASCADE)
status = models.IntegerField(choices=Status.choices, default=0)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Students'
class trainingPaths(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=70, blank=False, null=False)
shortName = models.CharField(max_length=10, blank=True)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Training_Path'
class Courses(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=70, blank=False, null=False)
path = models.URLField(max_length=500, blank=True, null=True)
shortName = models.CharField(max_length=6, blank=True)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
course_image = models.URLField(max_length=200, blank=True)
class Meta():
db_table = 'Courses'
class CoursesXTrainingP(models.Model):
id = models.AutoField(primary_key=True)
trainingPath = models.ForeignKey(trainingPaths, on_delete=models.CASCADE)
course = models.ForeignKey(Courses, on_delete=models.CASCADE)
alternativeName = models.CharField(max_length=70, blank=True)
order = models.PositiveIntegerField(blank=False)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Courses_X_Training_Paths'
I want to get the information of the courses that a student has according to the value of the "trainingPath".
this is my SQL query
select
courses.id, courses.`name`, courses.course_image
from
students
join
courses_x_training_paths
on
students.trainingPath_id = courses_x_training_paths.trainingPath_id
join
courses
on
courses_x_training_paths.course_id = courses.id
where
students.trainingPath_id=1;
I have tried several ways and none of them have worked, could you please help me?

You can filter with:
Courses.objects.filter(
coursesxtrainingp__trainingPath_id=1
)
The join on the Students model is not necessary, since we already know that the trainingPath_id is one by filtering on the CoursesXTrainingP model.
Note: normally a Django model is given a singular name, so Student instead of Students.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: modification_date instead of modificationDate.

Related

Django Rest Framework Integrity Error at NOT NULL constraint fail

i'm trying to post a transaction via django rest framework, however it shows error in django log as below:
IntegrityError at /api/item_trans/
NOT NULL constraint failed: chemstore_itemtransaction.bin_code_id
it has no problem if I post the same data from the Django admin web.
therefore I suppose the problem has happened at DRF
any help is welcome, thank you
models.py
class BinLocation(models.Model):
bin_code = models.CharField(max_length=10, unique=True)
desc = models.CharField(max_length=50)
def __str__(self):
return self.bin_code
class Meta:
indexes = [models.Index(fields=['bin_code'])]
class ItemMaster(models.Model):
item_code = models.CharField(max_length=20, unique=True)
desc = models.CharField(max_length=50)
long_desc = models.CharField(max_length=150, blank=True)
helper_qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
def __str__(self):
return self.item_code
class Meta:
verbose_name = "Item"
verbose_name_plural = "Items"
indexes = [models.Index(fields=['item_code'])]
class ItemTransaction(models.Model):
# trace_code YYMMDDXXXX where XXXX is random generated
trace_code = models.CharField(max_length=20, unique=False)
item_code = models.ForeignKey(
ItemMaster, on_delete=models.CASCADE, related_name='+', blank=False, null=False)
datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
action = models.CharField(
max_length=1, choices=ACTION, blank=False, null=False)
bin_code = models.ForeignKey(
BinLocation, related_name='+', on_delete=models.CASCADE, blank=False, null=False)
remarks = models.TextField(blank=True)
def __str__(self):
return f"{self.trace_code} {self.datetime} {self.item_code} {dict(ACTION)[self.action]} {self.qty} {self.unit} {self.bin_code}"
serializers.py
class ItemMasterSerializer(serializers.ModelSerializer):
class Meta:
model = ItemMaster
fields = '__all__'
class ItemTransactionSerializer(serializers.ModelSerializer):
item_code = serializers.SlugRelatedField(
slug_field='item_code',
read_only=True
)
bin_code = serializers.SlugRelatedField(
slug_field='bin_code',
read_only=True,
allow_null=False
)
class Meta:
model = ItemTransaction
fields = '__all__'
You might need to use 2 fields, one for reading data and the other for creating and updating your data with its source to the main. In your case you could try this:
class ItemTransactionSerializer(serializers.ModelSerializer):
item_code_id = ItemMasterSerializer(read_only=True)
item_code = serializers.PrimaryKeyRelatedField(
queryset=ItemMaster.objects.all(),
write_only=True,
source='item_code_id'
)
bin_code_id = BinLocationSerializer(read_only=True
bin_code = serializers.PrimaryKeyRelatedField(
queryset= BinLocation.objects.all(),
write_only=True,
source='bin_code_id'
)
Since you have null=False in both of your ForeignKeys, DRF expects the corresponding ID. You seem to be getting the error NOT NULL constraint because you are not passing the ID in DRF. So you need to fix that for both bin_code_id and the item_code_id.

How to make an inner join query with same table using Django's ORM

The query to be implemented with ORM is as follows,
SELECT t2.*
FROM sub_menu AS t1
INNER JOIN sub_menu AS t2 ON (t1.sub_menu_id = t2.parent_sub_menu_id)
WHERE t1.sub_menu_id = 1;
The model is as follows,
class SubMenu(models.Model):
sub_menu_id = models.AutoField(primary_key=True)
menu = models.ForeignKey('commons.MainMenu', related_name='sub_menus', on_delete=models.CASCADE)
parent_sub_menu_id = models.IntegerField(blank=True, null=True)
name = models.CharField(max_length=50)
en_name = models.CharField(max_length=50, blank=True)
ord = models.IntegerField()
api = models.CharField(max_length=255, blank=True)
api_method = models.CharField(max_length=7, blank=True)
api_detail = models.CharField(max_length=255, blank=True)
menu_type_cd = models.CharField(max_length=5, blank=True)
menu_auth_type_cd = models.CharField(max_length=5)
is_common = models.BooleanField(default=False)
is_ns = models.BooleanField(default=False)
spc_auth = models.BooleanField(default=False)
spc_auth_cd = models.CharField(max_length=5, blank=True)
create_dt = models.DateTimeField(auto_now_add=True)
update_dt = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'sub_menu'
unique_together = ('api', 'api_method',)
Not using a raw method, Is it possible to implement with Django's ORM?
Thank you.
You should do the relationship correctly on your model: https://docs.djangoproject.com/en/3.0/ref/models/fields/#module-django.db.models.fields.related. Then the parent_sub_menu should be:
class Submenu:
parent_sub_menu = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
Then run generate & DB migration. The query below should work.
And never declare relationship like you are doing right now, use Model instead via the documentation I sent.
Django does it for you already. You can just filter the related field.
https://docs.djangoproject.com/en/3.0/topics/db/queries/#lookups-that-span-relationships
SubMenu.objects.filter(parent_sub_menu__sub_menu_id=1)

Django rest framework raw queries select not working

I want to use a raw query in order to make a JOIN in a many to many relationship, and show it in the Django Rest Framework.
But the "SELECT" part of the query is not working, and it shows whatever the serializer has in "fields" and thus the JOIN is also not working.
serializers.py:
class UserTestSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
views.py:
class UserTestQuery(viewsets.ModelViewSet):
queryset = User.objects.raw('SELECT * ' +
'FROM users_user ' +
'INNER JOIN sysadmin_works_as ON users_user.user_id = sysadmin_works_as.employee_id;')
serializer_class = UserTestSerializer
I want to show a join in the API with these 3 models, so I must use raw SQL. Why is it not working?
And the models I'm using are:
class User(AbstractUser):
first_name = None
last_name = None
username = None
user_id = models.AutoField(primary_key=True)
email = models.EmailField(_('email address'), unique=True)
national_id_number = models.CharField(max_length=30)
f_name = models.CharField(max_length=100)
l_name = models.CharField(max_length=100)
star_count = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True,null=True)
is_superuser = models.BooleanField(default = False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
updated_at = models.DateTimeField(auto_now=True,null=True)
deleted_at = models.DateTimeField(blank = True, null=True)
date_joined = models.DateTimeField(auto_now_add=True,null=True)
app_role = models.ForeignKey(App_roles,related_name='employee',on_delete=models.SET_NULL,blank=True,null=True) #Un Rol_de_Aplicacion le pertenece a muchos usuar
class Works_as(models.Model):
work_id = models.AutoField(primary_key=True)
started_at = models.DateTimeField(auto_now_add=True)
updates_at = models.DateTimeField(auto_now=True)
r_created_at = models.DateTimeField(auto_now_add=True)
r_updated_at = models.DateTimeField(auto_now=True)
r_deleted_at = models.DateTimeField(auto_now=False,blank=True,null=True)
employee = models.ForeignKey(User,related_name='works_as',on_delete=models.SET_NULL,blank=True,null=True)
position = models.ForeignKey(Position,related_name='works_as',on_delete=models.SET_NULL,blank=True,null=True)
class Position(models.Model):
position_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
deleted_at = models.DateTimeField(blank=True,null=True)
upper_position = models.ForeignKey('self',on_delete=models.SET_NULL,blank=True,null=True)
department = models.ForeignKey(Department,related_name='positions',on_delete=models.SET_NULL,blank=True,null=True)
hierarchy_level = models.OneToOneField(Employee_Hierarchy,related_name='position',on_delete=models.SET_NULL,blank=True,null=True)

Multiple foreign keys to the same id. Django. Design Patterns

I really can't figure out why I can't point by Foregin Key the exactly same id multiple times.
I'm trying to use Django ORM to the database that already exists.
And it looks like this:
I wanted to create model according to that:
class TestID(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=250)
test_case_id = models.CharField(max_length=250, unique=True)
module = models.CharField(max_length=50)
full_description = models.TextField()
class Meta:
db_table = "TestID"
class TestCaseRun(models.Model):
id = models.AutoField(primary_key=True)
soft_version = models.CharField(max_length=50)
automated_test_case_version = models.CharField(max_length=50, unique=True)
start_time = models.DateTimeField()
end_time = models.DateTimeField()
checksum = models.CharField(max_length=250)
result = models.CharField(max_length=50)
test_case_id = models.ForeignKey(TestID, db_column='test_case_id')
class Meta:
db_table = "TestCaseRun"
class TestStep(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=250, null=False)
result = models.CharField(max_length=50)
description = models.CharField(max_length=250)
start_time = models.DateTimeField()
end_time = models.DateTimeField()
test_case = models.ForeignKey(TestCaseRun, db_column='id')
class Meta:
db_table = "TestStep"
class single_check(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=250)
comparison = models.CharField(max_length=5, null=False)
expected = models.CharField(max_length=50, null=False)
actual = models.CharField(max_length=50, null=False)
result = models.CharField(max_length=50)
comment = models.CharField(max_length=250)
event_time = models.DateTimeField()
test_step_id = models.ForeignKey(TestStep, db_column='id')
class Meta:
db_table = "single_check"
class action(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=250)
type = models.CharField(max_length=5, null=False)
result = models.CharField(max_length=50)
comment = models.CharField(max_length=250)
event_time = models.DateTimeField()
test_step_id = models.ForeignKey(TestStep, db_column='id')
class Meta:
db_table = "action"
class logs(models.Model):
id = models.AutoField(primary_key=True)
msg = models.CharField(max_length=350)
type = models.CharField(max_length=5, null=False)
result = models.CharField(max_length=50)
comment = models.CharField(max_length=250)
event_time = models.DateTimeField()
test_step_id = models.ForeignKey(TestStep, db_column='id')
class Meta:
db_table = "logs"
When I try to run that code I get errors:
ERRORS:
web_report.TestStep: (models.E007) Field 'test_case' has column name 'id' that is used by another field.
HINT: Specify a 'db_column' for the field.
web_report.action: (models.E007) Field 'test_step_id' has column name 'id' that is used by another field.
HINT: Specify a 'db_column' for the field.
web_report.logs: (models.E007) Field 'test_step_id' has column name 'id' that is used by another field.
HINT: Specify a 'db_column' for the field.
web_report.single_check: (models.E007) Field 'test_step_id' has column name 'id' that is used by another field.
HINT: Specify a 'db_column' for the field.
And I really can not figure out why I can't point by Foregin Key the exactly same id multiple times. Imho nothing is wrong with this design. But I'm beginner in relational database design.
It looks like you are using the db_column argument incorrectly. This is the field on the model that you are linking from, not the column on the model that you are linking to. You cannot use db_column='id', because there is already a primary key id for each model.
Taking your TestStep model as an example:
class TestStep(models.Model):
id = models.AutoField(primary_key=True)
...
test_case = models.ForeignKey(TestCaseRun, db_column='id')
Your diagram shows that it is the test_case_id column that links to the TestCase model. So you should have:
test_case = models.ForeignKey(TestCaseRun, db_column='test_case_id')
or because that is the default, simply
test_case = models.ForeignKey(TestCaseRun)

django join query

Im new to django. I have this model, In tblperson, only the forgein keys of type and status are saved. How do I join all tables to display their value not their forgein key? For example.
TblPerson.objects.raw('SELECT * FROM "Tblperson" INNER JOIN "Tblstatus" ON ("TblPerson"."Status" = "Tblstatus"."ID")'):
Thanks.
class TblPerson(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'ID')
Type = models.IntegerField(null=True, db_column=u'Type', blank=True)
Status = models.IntegerField(null=True, db_column=u'Status', blank=True)
class Meta:
db_table = u'tblPerson'
class Tblstatus(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'statStatusID')
Status = models.CharField(max_length=25, db_column=u'statStatus', blank=True)
class Meta:
db_table = u'tblStatus'
class Tbltype(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'typTypeID')
Type = models.CharField(max_length=25, db_column=u'typType', blank=True)
class Meta:
db_table = u'tblType'
The power of Django is in the ORM, which means you should be writing very little SQL if at all.
class Person(models.Model):
#don't use this because id is generated automatically
#ID = models.AutoField(primary_key=True, db_column=u'ID')
type = models.ForeignKey(Type)
status = models.ForeignKey(Status)
#Type,Status analogous
#filter like this
selected = Person.objects.filter(type=SomeType)
for p in selected:
print p.id,p.type,p.status
I would suggest you to re-write your models. So, that your TblPerson has a many to one relationship with Tblstatus
class TblPerson(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'ID')
Type = models.IntegerField(null=True, db_column=u'Type', blank=True)
Status = models.ForeignKey(Tblstatus, null=True, db_column=u'Status', blank=True)
class Meta:
db_table = u'tblPerson'
class Tblstatus(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'statStatusID')
Status = models.CharField(max_length=25, db_column=u'statStatus', blank=True)
class Meta:
db_table = u'tblStatus'
Using this you would be able to query for TblPerson objects for which Tblstatus exists like this
TblPerson.objects.filter(Status__isnull=False)

Categories

Resources