Django Multi Combination Model Joins - python

Currently experiencing a problem where my models aren't joining on the foreign key properly,
Doctors can only have one toolset, essentially I need to return [DoctorName, Category, Type, Subtype, Syringe, Bandage]
ToolSetCategoryID, ToolSetTypeID, ToolSetSubTypeID all join on each other's respective tables and all join back to ToolSets
an example of the models would be:
class Doctor(models.Model):
DoctorID = models.AutoField(db_column='DoctorID', primary_key=True)
ToolSetID = models.ForeignKey("ToolSets", db_column='ToolSetID', on_delete=models.CASCADE)
DoctorName = models.CharField(db_column='DoctorName', max_length=100)
class Meta:
managed = False
db_table = 'tblDoctors'
default_permissions = ['add','edit','delete']
class ToolSetCategories(models.Model):
ToolSetCategoryID = models.AutoField(db_column='ToolSetCategoryID', primary_key=True)
Category = models.CharField(db_column='Category', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSetCategories'
default_permissions = ['add','edit','delete']
class ToolSetTypes(models.Model):
ToolSetTypeID = models.AutoField(db_column='ToolSetTypeID', primary_key=True)
ToolSetCategoryID = models.ForeignKey("ToolSetCategories",db_column='ToolSetCategoryID',on_delete=models.CASCADE)
Type = models.CharField(db_column='Type', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSetTypes'
default_permissions = ['add','edit','delete']
class ToolSetSubTypes(models.Model):
ToolSetSubTypeID = models.AutoField(db_column='ToolSetSubTypeID', primary_key=True)
ToolSetTypeID = models.ForeignKey("ToolSetTypes",db_column='ToolSetTypeID',on_delete=models.CASCADE)
ToolSetCategoryID = models.ForeignKey("ToolSetCategories",db_column='ToolSetCategoryID',on_delete=models.CASCADE)
SubType = models.CharField(db_column='SubType', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSetSubTypes'
default_permissions = ['add','edit','delete']
class ToolSets(models.Model):
ToolSetID = models.AutoField(db_column='ToolSetID', primary_key=True)
ToolSetCategoryID = models.ForeignKey("ToolSetCategories",db_column='ToolSetCategoryID',on_delete=models.CASCADE)
ToolSetTypeID = models.ForeignKey("ToolSetTypes",db_column='ToolSetTypeID',on_delete=models.CASCADE)
ToolSetSubTypeID = models.ForeignKey("ToolSetSubTypes",db_column='ToolSetSubTypeID',on_delete=models.CASCADE)
Syringe = models.CharField(db_column='Syringe', max_length=100)
Bandage = models.CharField(db_column='Bandage', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSets'
default_permissions = ['add','edit','delete']

I've found either the fix or a workaround.
I had to filter the conditions I would've used in a join instead of using a join.
You can use Django's built in function F in order to reference a fields dynamic data to filter against (such as filtering field data against another field's data).
Not the best looking solution but is working for now, if anyone can find a more efficient way of doing this please post an answer below.
from django.db.models import F
Doctor.objects.using("test").filter(DoctorID=DoctorID).filter(
ToolSetID__ToolSetTypeID__ToolSetCategoryID=F("ToolSetID__ToolSetCategoryID"),
ToolSetID__ToolSetSubTypeID__ToolSetTypeID=F("ToolSetID__ToolSetTypeID"),
ToolSetID__ToolSetSubTypeID__ToolSetCategoryID=F("ToolSetID__ToolSetCategoryID"),
)

Related

How to get data from other table in django with Foreign Key(New to Django)

I have Two table MeterDetail,EnergyData
class MeterDetail(models.Model):
metername = models.CharField(max_length=20)
meter_id = models.IntegerField()
meter_type = models.CharField(max_length=20)
meter_purpose = models.CharField(max_length=20)#auto_now_add=True
meter_location = models.CharField(max_length=20)
class Meta:
db_table = 'meterdetails'
def __str__(self):
return str(self.meter_id)
class EnergyData(models.Model):
last_kwh = models.FloatField()
date_time_recorded = models.DateTimeField(default=timezone.now)#auto_now_add=True
meter_id = models.ForeignKey(MeterDetail,on_delete=models.CASCADE,related_name="meter_details")
class Meta:
db_table = 'energydata'
get_latest_by = "date_time_recorded"
def __str__(self):
return str(self.last_kwh)
I want to get data from second table using first object.
I tried in shell
t= MeterDetail.objects.get(meter_id=1)
am unable to read this below one
t.energydata_set.all()
giving error: AttributeError: 'MeterDetail' object has no attribute 'energydata_set'
You have to use t.meter_details.all() instead of t.energydata_set.all()
Here, the meter_details is the related_name to get the reverse objects.
What is related_name used for in Django?

Serialize m2mfield('self')

I have this model in models.py:
class Foo(models.Model):
bar = models.ManyToManyField('self')
How can I serialize it?
I was using one of solutions from this topic: Django rest framework nested self-referential objects But none of them working with M2M, either causes in infinity cycle of serialization. Solution where I'm using a row of serializers works good except it's limited by copy&paste (sounds really sad :) )
Generic model mostly looks like a comment's tree. I hope such a problem was already solved before but haven't found how yet.
I don't think you will get a straight solution to this, so try this
class FooBaseSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = Foo
class FooSerializer(FooBaseSerializer):
bar = FooBaseSerializer(many=True)
NOTE: As a Software Engineer, I love to use Architectures and I have deeply worked on Layered Approach for Development so I am gonna be Answering it with Respect to Tiers.
I would suggest the use of a Bridge Table for M2M relationships to Normalize Stuff. Anyhow serializing many of the Items would require to
serializer = SerializerNameGoesHere(AllFilteredObjectsfromModel, many=True)
would serializer m2m.
Here's an Example in Layered Approach!
As i understood the Issue, Here's the Solution
models.py
class Member(models.Model):
member_id = models.AutoField(primary_key=True)
member_name = models.CharField(max_length =
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length = 20)
fk_member_id = models.ForeignKey('Member', models.DO_NOTHING,
db_column='fk_member_id', blank=True, null=True)
class Membership(models.Model):
membershipid = models.AutoField(primary_key=True)
fk_group_id = models.ForeignKey('Group', models.DO_NOTHING,
db_column='fk_member_id', blank=True, null=True)
join_date = models.DateTimeField()
serializers.py
import serializer
class AllSerializer(serializer.Serializer):
group_id = serializer.IntegerField()
group_name = serializer.CharField(max_length = 20)
join_date = serializer.DateTimeField()
CustomModels.py
imports...
class AllDataModel():
group_id = ""
group_name = ""
join_date = ""
BusinessLogic.py
imports ....
class getdata(memberid):
alldataDict = {}
dto = []
Member = models.Members.objects.get(member_id=memberid) #or use filter for Name
alldataDict["MemberId"] = Member.member_id
alldataDict["MemberName"] = Member.member_name
Groups = models.Group.objects.filter(fk_member_id=Member)
for item in Groups:
Custommodel = CustomModels.AllDataModel()
Custommodel.group_id = item.group_id
Custommodel.group_name = item.group_name
Membership = models.Membership.objects.get(fk_group_id=item.group_id)
Custommodel.join_date = Membership.join_date
dto.append(Custommodel)
serializer = AllSerializer(dto,many=True)
alldataDict.update(serializer.data)
return alldataDict

Django: ID Null after Save

I Got this Models in models.py:
class Boats(models.Model):
id = models.BigIntegerField(primary_key=True)
created = models.DateTimeField(default=timezone.now, blank=True)
name = models.CharField(max_length=30)
class Meta:
managed = True
db_table = 'boats'
ordering = ['name']
class Clients(models.Model):
id = models.BigIntegerField(primary_key=True)
created = models.DateTimeField(default=timezone.now, blank=True)
code = models.CharField(max_length=100)
class Meta:
managed = True
db_table = 'clients'
ordering = ['name']
==========================
In the views.py; my function do it like that:
f = NewBoatForm(request.POST)
if f.is_valid():
nBoat = f.save()
print 'ID:'+str(nBoat.id)
cBoat = ClientsBoats()
cBoat.client = client
cBoat.boat = nBoat
cBoat.save()
But django fails with this error:
ValueError: save() prohibited to prevent data loss due to unsaved related object 'boat'.
I print the ID but it's Null. Can someOne help me.
You've overridden the primary key field, id, to be something other than an AutoField. Don't do that.
Normally you wouldn't define it at all, and let Django do it automatically. If you are really really sure that a standard integer field is not big enough, you can use BigAutoField. But I doubt you will have more than 2147483647 boats in your database.

How to limit # queries made when Django model property is based on ManyToManyField

I'm building a read API for an existing (legacy) SQL database using Django Rest Framework. The problem is that way too many queries are made.
I want to select a Widget and its (about 40) related widgets, including the widget_technology for each of the related widgets. The technology of a widget depends on the presence or absence of a certain tag (I realize it's suboptimal database design but it's legacy...). The problem is that this results in 40+ queries (one per related widget).
Is there any way to fix it?
I've been looking at prefetch_related('widget_tags') in the DRF part of the code, but that doesn't seem to help.
Here is the main table:
class Widgets(models.Model):
widget_id = models.AutoField(primary_key=True)
widget_slug = models.CharField(unique=True, max_length=70)
widget_name = models.CharField(max_length=70)
widget_tags = models.ManyToManyField('Tags', through='IsTag')
related_widgets = models.ManyToManyField('Widgets', through='Similar', related_name='similar')
#property
def widget_technology(self):
if self.widget_tags.filter(tag_slug='tech_1').exists():
return 'TECH_1'
elif self.widget_tags.filter(tag_slug='tech_2').exists():
return 'TECH_2'
class Meta:
managed = False
db_table = 'widgets'
For completeness, here are the other tables:
class Similar(models.Model):
first_widget = models.ForeignKey(
Widgets, models.DO_NOTHING, primary_key=True, related_name='similar_first_widget'
)
second_widget = models.ForeignKey(
Widgets, models.DO_NOTHING, related_name='similar_second_widget'
)
score = models.IntegerField()
class Meta:
managed = False
db_table = 'similar'
unique_together = (('first_widget', 'second_widget'),)
class IsTag(models.Model):
is_tag_widget = models.ForeignKey(Widgets, models.DO_NOTHING, primary_key=True)
is_tag_tag = models.ForeignKey('Tags', models.DO_NOTHING)
class Meta:
managed = False
db_table = 'is_tag'
unique_together = (('is_tag_widget', 'is_tag_tag'),)
class Tags(models.Model):
tag_id = models.AutoField(primary_key=True)
tag_slug = models.CharField(max_length=100)
class Meta:
managed = False
db_table = 'tags'
EDIT: Adding the View
class WidgetDetail(APIView):
def get_object(self, slug):
try:
return Widgets.objects.get(widget_slug=slug)
# tried this but didn't solve the issue:
# return Widgets.objects.prefetch_related('related_widgets', 'related_widgets__widget_tags').get(widget_slug=slug)
except Widgets.DoesNotExist:
raise Http404
def get(self, request, slug, format=None):
widget = self.get_object(slug)
serializer = FullWidgetSerializer(widget)
return Response(serializer.data)
and the serializers:
class FullWidgetSerializer(serializers.ModelSerializer):
# special cases
widget_tags = SimpleTagSerializer(many=True, read_only=True)
related_widgets = SimpleWidgetSerializer(many=True, read_only=True)
class Meta:
model = Widgets
fields = (
'widget_slug', 'related_widgets', 'widget_tags', 'widget_technology')
class SimpleWidgetSerializer(serializers.ModelSerializer):
class Meta:
model = Widgets
fields = ('widget_slug', 'widget_technology')

Django select_related query

I have the following two models:
class StraightredFixture(models.Model):
fixtureid = models.IntegerField(primary_key=True)
home_team = models.ForeignKey('straightred.StraightredTeam', db_column='hometeamid', related_name='home_fixtures')
away_team = models.ForeignKey('straightred.StraightredTeam', db_column='awayteamid', related_name='away_fixtures')
fixturedate = models.DateTimeField(null=True)
fixturematchday = models.ForeignKey('straightred.StraightredFixtureMatchday', db_column='fixturematchday')
hometeamscore = models.IntegerField(null=True)
awayteamscore = models.IntegerField(null=True)
soccerseason = models.ForeignKey('straightred.StraightredSeason', db_column='soccerseasonid', related_name='fixture_season')
def __unicode__(self):
return self.fixtureid
class Meta:
managed = True
db_table = 'straightred_fixture'
class UserSelection(models.Model):
userselectionid = models.AutoField(primary_key=True)
campaignno = models.CharField(max_length=36,unique=False)
user = models.ForeignKey(User, related_name='selectionUser')
teamselection1or2 = models.PositiveSmallIntegerField()
teamselectionid = models.ForeignKey('straightred.StraightredTeam', db_column='teamselectionid', related_name='teamID')
fixtureid = models.ForeignKey('straightred.StraightredFixture', db_column='fixtureid')
class Meta:
managed = True
db_table = 'straightred_userselection'
I am using the following query:
prevWeekTeams = UserSelection.objects.select_related().filter(soccerseason=1025,fixturematchday=5,user=currentUserID).order_by('teamselection1or2')
When it is run I get the following error:
Cannot resolve keyword 'soccerseason' into field. Choices are: campaignno, fixtureid, fixtureid_id, teamselection1or2, teamselectionid, teamselectionid_id, user, user_id, userselectionid
I knew it would not work but I can't quite understand how to refer to the soccerseason within the fixture table. Any help would be appreciated. Many thanks, Alan.
PS
If you require the other two models that are linked to just let me know.
You just need to filter on field of foreign model with that format
field-that-reference-to-foreign-model__foreign-model-field in your case fixtureid__soccerseason. The docs where it describes at best.
What you should do is
prevWeekTeams = UserSelection.objects.filter(fixtureid__soccerseason=1025,fixtureid__fixturematchday=5,user=currentUserID).order_by('teamselection1or2')

Categories

Resources