How to write a query based on multiple tables? - django

I want the details of lender whose state,distrtict,religion,profession equals to borrowers details i.e;(state,distrtict,religion,profession)
This is borrowers models.py
class Borrower(models.Model):
district = models.TextField(blank=True)
state = models.TextField(blank=True)
profession = models.TextField(blank=True)
religion = models.TextField(blank=True)
This is Lenders models.py
class LenderStateDistrict(models.Model):
lenderId = models.CharField(max_length=5)
state = models.CharField(max_length=50,**optional)
district = models.CharField(max_length=50,**optional)
class LenderReligion(models.Model):
lenderId = models.CharField(max_length=5)
religion = models.CharField(max_length=50, **optional)
class LenderMultipleProfessions(models.Model):
lenderId = models.CharField(max_length=5)
profession = models.CharField(max_length=50,**optional)
views.py
#api_view(['GET'])
def xyz(request):
borrower1= Borrower.objects.get(id =1)
city = borrower1.district
state = borrower1.state
profession = borrower1.profession
religion = borrower1.religion
I got every requirement for borrower and then how to query based on the three tables i.e; LenderStateDistrict,LenderReligion,LenderMultipleProfessions,if the borrowers district,state,religion,profession equals to the lenders then it should give the details how to query it?

There's a fundamental problem with your models. They are not related to each other. The power of Relational Database Management Systems lies in making relationships!
Django offers ways to define the three most common types of database
relationships: many-to-one, many-to-many and one-to-one.
https://docs.djangoproject.com/en/1.10/topics/db/models/#relationships
At the very least you need to create a foreign key between your borrow and the lender. But it may need to be a ManyToMany relationship if users can borrows from more than one lender

As #e4c5 mentioned that there is a problem with your models, try to relate your models with each other so that writing queries become easier.
Try to implement this way:
class District(models.Model):
field1 = models.CharField(max_length=255)
field2 = models.CharField(max_length=255)
class Religion(models.Model):
field1 = models.CharField(max_length=255)
field2 = models.CharField(max_length=255)
class Profession(models.Model):
field1 = models.CharField(max_length=255)
field2 = models.CharField(max_length=255)
This should be your basic models according to your question, and then you can reference these models in your Lender and Borrower tables, this way:
class Lender(models.Model):
district = models.ForeignKey(District, related_name="lender_district")
profession = models.ForeignKey(Profession, related_name="lender_profession")
religion = models.ForeignKey(Religion, related_name="lender_region")
class Borrower(models.Model):
district = models.ForeignKey(District, related_name="borrower_district")
profession = models.ForeignKey(Profession, related_name="borrower_profession")
religion = models.ForeignKey(Religion, related_name="borrower_region")
This way you can achieve that query that you want. Suppose you want to access the details of Borrower and Lender who belongs to district where field1 = "xyz", for that you have to simply write:
lenders = Lender.objects.filter(district__field1="xyz")
borrowers = Borrower.objects.filter(district__field1="xyz")
And further simple way is:
district = District.objects.get(field1="xyz") # get district
lenders = Lender.objects.filter(district=district) # Get Lenders
borrowers = Borrower.objects.filter(district=district) # Get Borrowers
You can implement ManyToMany relations too if lender and Borrower has more than one District, Religion or Profession.

Related

Merge Django models into a view

I am attempting to merge and pull data from three Django models into a view. Players and Events relate to each other in the Details model (a player can attend many events) using models.ForeignKey.
In other platforms I would have written a DB View to join tables and the application would query that view.
From what I understand Django does not support data views within Models.
Looking for help on how I would approach this in Django.
class Players(models.Model):
firstName = models.CharField(max_length=255)
lastName = models.CharField(max_length=255)
highSchool = models.CharField(max_length=255)
gradYear = models.IntegerField()
slug = models.SlugField(default="", null=False)
class Events(models.Model):
title = models.CharField(max_length=255)
location = models.CharField(max_length=255)
date = models.DateField()
class Details(models.Model):
event = models.ForeignKey(Events, on_delete=models.CASCADE)
player = models.ForeignKey(Players, on_delete=models.CASCADE)
height = models.IntegerField(default=None, blank=True)
weight = models.IntegerField(default=None, blank=True)
def playerdetail(request,slug):
playerinfo = Details.objects.get(id=1)
template = loader.get_template('playerdetail.html')
context = {
'playerinfo': playerinfo,
}
return HttpResponse(template.render(context, request))
You are actually doing what you needed to do with the code you provided.
When you are invoking a query on a model that connects those two entities (Players,Events), it performs the join when you try to access each of these properties through the foreign key fields.
For example, for accessing the player information (which makes the Django ORM perform the join operation in the background):
# Get the first name of the player
first_name = playerinfo.player.firstName
For filtering and showing in other places, you can use the notation field__subfield
For more information, please read the examples of this website:
https://books.agiliq.com/projects/django-orm-cookbook/en/latest/index.html

Django tables connection

I have 3 django tables connected like this:
Is there anyway to make a query for table Table that will get id_equip from table equip?
models.py
class Vendor(models.Model):
vendor_name = models.CharField(max_length=50)
def __str__(self):
return self.vendor_name
class Equipment(models.Model):
equipment_name = models.CharField(max_length=50)
id_vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
def __str__(self):
return self.equipment_name
class Table(models.Model):
table_name = models.CharField(max_length=100)
id_vend = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
id_equip = models.ManyToManyField(Equipment)
This part of the django docs is relevant and helpful, I definitely recommend your review at least that section and ideally the whole page.
Your models are already denormalized as evidenced by Table.id_equip which relates to Equipment so you could do:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(table.id_equip.all().values_list('id', flat=True))
If you wanted to go through the vendor I'd suggest:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(Equipment.objects.filter(vendor_set__table_set=table).values_list('id', flat=True))
I would recommend that you don't name your relationship fields with id_. With an ORM, these fields should represent the instances of the Model they are mapping to. For example:
class Table(models.Model):
name = models.CharField(max_length=100)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
equipment = models.ManyToManyField(Equipment)
If you're trying to create the model on top of an existing table, you can make use of the db_column parameter when defining the field.
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, db_column="id_vend")

Django intermediate table with a many-to-many field instead foreign key?

I have 2 models in my application:
User
Tower
My goal is to associate many towers to a user using an intermediate table because I need to add a period of time.
So I have something like this in my models:
class Tower(models.Model):
name = models.CharField(max_length=128)
class User(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField('Tower', through='Dates')
class Dates(models.Model):
user = models.ForeignKey('User', on_delete=models.CASCADE)
tower = models.ForeignKey('Tower', on_delete=models.CASCADE)
begin_date = models.DateTimeField()
end_date = models.DateTimeField()
But my goal was to have the field tower in class Dates to a many-to-many like this:
tower = models.ManyToManyField('Tower', blank=True)
So that i can associate many towers to a user in a certain period. But unfortunately django says that i need to use forgeignkey to Tower and User classes.
Have any solution for this? To apply directly the many-to-many field in the intermediate table? Or I must create a new class, sort of a GroupTower, that have a many-to-many field to the Tower class? Something like this:
class Tower(models.Model):
name = models.CharField(max_length=128)
class GroupTower(models.Model):
tower = models.ManyToManyField('Tower', blank=True)
class User(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField('Tower', through='Dates')
class Dates(models.Model):
user = models.ForeignKey('User', on_delete=models.CASCADE)
tower = models.ForeignKey('GroupTower', on_delete=models.CASCADE)
begin_date = models.DateTimeField()
end_date = models.DateTimeField()
Thanks in advance.
There is so many ways that you can design the database.
An example:
class Tower(models.Model):
name = models.CharField(max_length=128)
class User(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField('UserTower')
class UserTower(models.Model):
user = models.ForeignKey('User', on_delete=models.CASCADE)
tower = models.ManyToManyField('Tower')
begin_date = models.DateTimeField()
end_date = models.DateTimeField()
In this design you can add many UserTower instances to a user and each UserTower instance can have many towers.
Now if you query the members for a user:
User.objects.get(pk=1).members.all()
You will have members grouped by periods of time if you saved them this way but it requires you to write some codes to avoid duplicates for begin_date, begin_date and user.
And now if you need towers:
user_members = User.objects.get(pk=1).members.all().values_list('tower', flat=True)
towers = Tower.objects.filter(pk__in=user_members).distinct()
This design is okay only if you really don't want duplicates with same begin_date and begin_date which i can't find a reason for.
You can still have all the features if you add multiple instances with same begin_date, begin_date and user but different tower.

Can't figure out join statement in Django

I'm trying to figure out how to execute the following sql join statement in Django without resorting to just raw sql. Is there a way to do it?
Select * from playertable, seasontable where player.id = season.player_id
Here are my models. Just to clarify, I used abbreviated table names in the above query for clarify
class Player(models.Model):
name = models.CharField(max_length=200)
team = models.CharField(max_length=3)
position = models.CharField(max_length=3)
class PlayerSeason(models.Model):
player = models.ForeignKey(Player)
year = models.IntegerField()
games_played = models.IntegerField()
goals = models.IntegerField()
assists = models.IntegerField()
points = models.IntegerField()
plusminus = models.CharField(max_length=200)
pim = models.IntegerField()
ppg = models.IntegerField()
shg = models.IntegerField()
gwg = models.IntegerField()
otg = models.IntegerField()
shots = models.IntegerField()
shooting_percentage = models.DecimalField(max_digits=5, decimal_places=2)
toi = models.CharField(max_length=200)
sftg = models.DecimalField(max_digits=5, decimal_places=2)
face_off = models.DecimalField(max_digits=5, decimal_places=2)
How should I do this with a Django QuerySet?
If all you wanted to do was to get all the players associated with a given season you could make use of Django's backwards relationships
When you use a ForeignKeyField to a model, in this case Season, the that model instances get an attribute which allows you to get a queryset of all the related objects.
In your example you could use season.player_set.all().
You can pass an optional parameter related_name to the ForeignKeyField that allows you to change the name of the season attribute.
Is there a way to do it?
No. Django's ORM deals with one model at a time, and you are getting columns from two tables. Perform a query on either of the models and then access the appropriate field to get the related model.

constructing a joined django query

I'm interacting with a legacy db on another system, so the models are written in stone and not very django-ey.
My models.py:
class Site(models.Model):
site_code = models.CharField(max_length=30, primary_key=True)
name = models.CharField(unique=True, max_length=300)
class Document(models.Model):
id = models.IntegerField(primary_key=True)
site_ref = models.ForeignKey(Site)
description = models.CharField(max_length=1500)
class DocumentStatusCategory(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=90)
class DocumentStatus(models.Model):
id = models.IntegerField(primary_key=True)
document = models.ForeignKey(Document)
status = models.ForeignKey(DocumentStatusCategory)
changed_by = models.ForeignKey(User)
created_at = models.DateTimeField()
In my views.py I want to retrieve a queryset with all the Document objects that belong to a specified Site (say site_ref=mysite) which do not have any related DocumentStatus objects with status=4.
Any idea how I can do this as a single (non-sql intensive) line?
Document.objects.filter(site_ref=mysite).exclude(documentstatus__status_id=4)
Document.objects.filter(site_ref=site_obj).exclude(documentstatus_set__in=DocumentStatus.objects.filter(status_id=4))
Not exactly one query, but I don't think that's achievable without going down to raw sql. Two queries isn't bad though I suppose.
I should mention that the above assumes that the reverse relation between Document and DocumentStatus is documentstatus_set. You can explicitly state what the reverse relation is like so:
# inside the DocumentStatus model definition
document = models.ForeignKey(Document, related_name='document_statuses')
Then the query becomes:
Document.objects.filter(site_ref=site_obj).exclude(document_statuses__in=DocumentStatus.objects.filter(status_id=4))