I want to export a database (15 or 20 tables) with Django (3, 000 rows and one hundred columns), but it takes very long.
I think the solution is to use prefetch_related, but I would like your opinion as it seems very complex to me (so many tables...). If this is the solution, can you show an example with a few different models?
def get_validated_acts(excl_fields_act_ids, excl_fields_act):
qs=Act.objects.filter(validated=2)
#list of acts
acts=[]
for act in qs.iterator():
#list of fields for one act
fields=[]
act_ids=ActIds.objects.get(act=act, src="index")
#ActIds
for field in ActIds()._meta.fields:
if field.name not in excl_fields_act_ids:
fields.append(getattr(act_ids, field.name))
#Act
for field in Act()._meta.fields:
if field.name not in excl_fields_act:
#CodeSect and related
if "code_sect_" in field.name:
temp=getattr(act, field.name)
if temp!=None:
fields.append(temp.code_sect)
fields.append(temp.code_agenda.code_agenda)
else:
fields.extend([None, None])
#Rapporteurs (Person) and related (oeil) or Responsibles (Person) and related (prelex)
elif "rapp_" in field.name or "resp_" in field.name:
temp=getattr(act, field.name)
if temp!=None:
fields.append(temp.name)
country=temp.country
party=temp.party
fields.append(country.country_code)
fields.append(party.party)
if "resp_" in field.name:
#party_family
fields.append(PartyFamily.objects.get(party=party, country=country).party_family)
else:
if "resp_" in field.name:
temp=[None]*4
else:
temp=[None]*3
fields.extend(temp)
else:
#for all the other non fk fields, get its value
fields.append(getattr(act, field.name))
#Act many to many fields
for field in Act()._meta.many_to_many:
#GvtCompo
if "gvt_compo"==field.name:
gvt_compos_country=gvt_compos_party=gvt_compos_party_family=""
#for each country
for gvt_compo in getattr(act, field.name).all():
country=gvt_compo.country
#for each party, add a "row" for each variable (country, party, party family)
for party in gvt_compo.party.all():
gvt_compos_country+=country.country_code+"; "
gvt_compos_party+=party.party+"; "
gvt_compos_party_family+=PartyFamily.objects.get(country=country, party=party).party_family+"; "
#delete last "; "
fields.append(gvt_compos_country[:-2])
fields.append(gvt_compos_party[:-2])
fields.append(gvt_compos_party_family[:-2])
#adopt_cs_contre, adopt_cs_abs, adopt_pc_contre, adopt_pc_abs
else:
countries=""
for country in getattr(act, field.name).all():
countries+=country.country_code+"; "
fields.append(countries[:-2])
#Ministers' attendance fields
instances=MinAttend.objects.filter(act=act)
temp_fields={"country": "", "verbatim": "", "status": ""}
for instance in instances:
temp_fields["country"]+=instance.country.country_code+"; "
temp_fields["verbatim"]+=instance.verbatim.verbatim+"; "
temp_fields["status"]+=Status.objects.get(verbatim=instance.verbatim, country=instance.country).status+"; "
fields.append(temp_fields["country"][:-2])
fields.append(temp_fields["verbatim"][:-2])
fields.append(temp_fields["status"][:-2])
acts.append(fields)
return acts
If it helps, here are some fields of the main model Act:
class Act(models.Model):
titre_en=models.CharField(max_length=1000, blank=True, null=True, default=None)
code_sect_1=models.ForeignKey(CodeSect, related_name='code_sect_1', blank=True, null=True, default=None)
code_sect_2=models.ForeignKey(CodeSect, related_name='code_sect_2', blank=True, null=True, default=None)
code_sect_3=models.ForeignKey(CodeSect, related_name='code_sect_3', blank=True, null=True, default=None)
code_sect_4=models.ForeignKey(CodeSect, related_name='code_sect_4', blank=True, null=True, default=None)
rep_en_1=models.CharField(max_length=200, blank=True, null=True, default=None)
rep_en_2=models.CharField(max_length=200, blank=True, null=True, default=None))
type_acte=models.CharField(max_length=100, blank=True, null=True, default=None)
com_amdt_tabled=models.IntegerField(max_length=3, blank=True, null=True, default=None)
votes_agst_1=models.IntegerField(max_length=3, blank=True, null=True, default=None)
rapp_1=models.ForeignKey(Person, related_name='rapp_1', blank=True, null=True, default=None)
rapp_2=models.ForeignKey(Person, related_name='rapp_2', blank=True, null=True, default=None)
rapp_3=models.ForeignKey(Person, related_name='rapp_3', blank=True, null=True, default=None)
rapp_4=models.ForeignKey(Person, related_name='rapp_4', blank=True, null=True, default=None)
adopt_propos_origine=models.DateField(max_length=10, blank=True, null=True, default=None)
com_proc=models.CharField(max_length=100, blank=True, null=True, default=None)
resp_1=models.ForeignKey(Person, related_name='resp_1', blank=True, null=True, default=None)
resp_2=models.ForeignKey(Person, related_name='resp_2', blank=True, null=True, default=None)
resp_3=models.ForeignKey(Person, related_name='resp_3', blank=True, null=True, default=None)
transm_council=models.DateField(max_length=10, blank=True, null=True, default=None)
adopt_cs_contre=models.ManyToManyField(Country, related_name='adopt_cs_contre')
adopt_cs_abs=models.ManyToManyField(Country, related_name='adopt_cs_abs')
adopt_pc_contre=models.ManyToManyField(Country, related_name='adopt_pc_contre')
adopt_pc_abs=models.ManyToManyField(Country, related_name='adopt_pc_abs')
gvt_compo=models.ManyToManyField(GvtCompo)
This code seems a bit faster (10% faster):
def get_validated_acts(excl_fields_act_ids, excl_fields_act):
tic=time.time()
#querysets
qs_act=Act.objects.defer("id", 'date_doc', "url_prelex", "validated", "validated_attendance").filter(validated=2).prefetch_related("gvt_compo", "adopt_cs_contre", "adopt_cs_abs", "adopt_pc_contre", "adopt_pc_abs").prefetch_related("gvt_compo__party")
qs_actids=ActIds.objects.defer("id", 'src', "url_exists", 'act').filter(src="index")
qs_cs=CodeSect.objects.all().prefetch_related("code_agenda", "config_cons")
qs_pers=Person.objects.all()
qs_party=Party.objects.all()
qs_pf=PartyFamily.objects.all()
qs_minattend=MinAttend.objects.all()
qs_verb=Verbatim.objects.all()
qs_status=Status.objects.all()
#fields names
names_actids=[field.name for field in ActIds()._meta.fields if field.name not in excl_fields_act_ids]
names_act=[field.name for field in Act()._meta.fields if field.name not in excl_fields_act]
names_act_m2m=[field.name for field in Act()._meta.many_to_many]
#list of acts
acts=[]
for act in qs_act:
#list of fields for one act
fields=[]
act_ids=qs_actids.get(act=act)
#ActIds
for field in names_actids:
fields.append(getattr(act_ids, field))
#Act
for field in names_act:
#CodeSect and related
if "code_sect_" in field:
cs_id=getattr(act, field+"_id")
if cs_id!=None:
cs=qs_cs.get(pk=cs_id)
fields.append(cs.code_sect)
fields.append(cs.code_agenda.code_agenda)
else:
fields.extend([None, None])
#Rapporteurs (Person) and related (oeil) or Responsibles (Person) and related (prelex)
elif "rapp_" in field or "resp_" in field:
pers_id=getattr(act, field+"_id")
if pers_id!=None:
pers=qs_pers.get(pk=pers_id)
party=qs_party.get(pk=pers.party_id)
fields.append(pers.name)
fields.append(pers.country_id)
fields.append(party.party)
if "resp_" in field:
#party_family
fields.append(qs_pf.get(party=party, country_id=pers.country_id).party_family)
else:
if "resp_" in field:
temp=[None]*4
else:
temp=[None]*3
fields.extend(temp)
else:
#for all the other non fk fields, get its value
fields.append(getattr(act, field))
#~
#Act many to many fields
for field in names_act_m2m:
#GvtCompo
if "gvt_compo"==field:
gvt_compos_country=gvt_compos_party=gvt_compos_party_family=""
#~ #for each country
for gvt_compo in act.gvt_compo.all():
#for each party, add a "row" for each variable (country, party, party family)
for party in gvt_compo.party.all():
gvt_compos_country+=gvt_compo.country_id+"; "
gvt_compos_party+=party.party+"; "
gvt_compos_party_family+=qs_pf.get(party=party, country_id=gvt_compo.country_id).party_family+"; "
#delete last "; "
fields.append(gvt_compos_country[:-2])
fields.append(gvt_compos_party[:-2])
fields.append(gvt_compos_party_family[:-2])
#~ #adopt_cs_contre, adopt_cs_abs, adopt_pc_contre, adopt_pc_abs
else:
countries=""
for country in getattr(act, field).all():
countries+=country.country_code+"; "
fields.append(countries[:-2])
#~
#Ministers' attendance fields
instances=qs_minattend.filter(act=act)
temp_fields={"country": "", "verbatim": "", "status": ""}
for instance in instances:
temp_fields["country"]+=instance.country_id+"; "
temp_fields["verbatim"]+=qs_verb.get(pk=instance.verbatim_id).verbatim+"; "
temp_fields["status"]+=qs_status.get(verbatim_id=instance.verbatim_id, country_id=instance.country_id).status+"; "
fields.append(temp_fields["country"][:-2])
fields.append(temp_fields["verbatim"][:-2])
fields.append(temp_fields["status"][:-2])
acts.append(fields)
tac=time.time()
print "time", tac-tic
return acts
I use prefetch_related and I store all the objects in memory. Not sure it is such a good idea...
Related
In my project , Each candidate can takepart in some assessments,each assessment has some tests, each test has some questions in it and candidates should answer the questions
at last scores of the questions are saved in question_score and test_score table
I need to get some values of field and use them
I write a method for question_result table, to get them
but i dont know if it is needed to use select_related or not
if it is needed how can i use it ?
Assessment:
class Assessment(BaseModel):
company = models.ForeignKey(
'company.Company',
on_delete=models.CASCADE,
related_name='assessments',
)
title = models.CharField(max_length=255)
job_role = models.ForeignKey(
JobRole,
on_delete=models.PROTECT,
related_name='assessments',
blank=True,
null=True,
)
tests = models.ManyToManyField(
'exam.Test',
related_name='assessments',
blank=True,
through='TestOfAssessment',
)
candidates = models.ManyToManyField(
'user.User',
related_name='taken_assessments',
blank=True,
through='candidate.Candidate'
)
def __str__(self):
return self.title
Test:
class Test(BaseModel):
class DifficultyLevel(models.IntegerChoices):
EASY = 1
MEDIUM = 2
HARD = 3
company = models.ForeignKey(
'company.Company',
on_delete=models.PROTECT,
related_name='tests',
null=True,
blank=True,
)
questions = models.ManyToManyField(
'question.Question',
related_name='tests',
blank=True,
help_text='Standard tests could have multiple questions.',
)
level = models.IntegerField(default=1, choices=DifficultyLevel.choices)
title = models.CharField(max_length=255)
summary = models.TextField()
def __str__(self):
return self.title
Question :
class Question(BaseModel):
company = models.ForeignKey(
'company.Company',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='company_questions',
)
question_text = models.TextField()
def __str__(self):
return truncatewords(self.question_text, 7)
TestResult:
class TestResult(BaseModel):
candidate = models.ForeignKey(
'Candidate',
on_delete=models.CASCADE,
related_name='test_results',
)
test = models.ForeignKey(
'exam.Test',
on_delete=models.CASCADE,
)
test_score = models.DecimalField(default=0.00, max_digits=5, decimal_places=2)
def __str__(self):
return f'{self.candidate.user.email} - {self.test.title}'
Candidate :
class Candidate(BaseModel):
assessment = models.ForeignKey(
'assessment.Assessment',
on_delete=models.CASCADE,
)
user = models.ForeignKey(
'user.User',
on_delete=models.CASCADE,
)
is_rejected = models.BooleanField(default=False)
def __str__(self):
return f'{self.user.email} - {self.assessment.title}'
Company :
class Company(models.Model):
manager = models.ForeignKey('user.User', on_delete=models.CASCADE, related_name='user_companies')
name = models.CharField(max_length=255)
city = models.ForeignKey('company.City', null=True, on_delete=models.SET_NULL)
address = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return self.name
QuestionResult :
class QuestionResult(BaseModel):
test = models.ForeignKey(
'TestResult',
on_delete=models.CASCADE,
related_name='question_results',
)
question = models.ForeignKey(
'question.Question',
on_delete=models.CASCADE,
related_name='results',
)
result = models.TextField(
null=True,
blank=True,
)
answer_score = models.DecimalField(default=0.00, max_digits=5, decimal_places=2)
def __str__(self):
return f'{self.test.candidate.user.email} - {self.question}'
def text_variables(self):
email = self.test.candidate.user.email
company_name = self.test.test.company.name
assessment_name = self.test.candidate.assessment.title
candidate_first_name = self.test.candidate.user.first_name
job_name = self.test.candidate.assessment.job_role
user_fullname = User.full_name
data = dict(
job_name=job_name,
company_name=company_name,
email=email,
assessment_name=assessment_name,
candidate_first_name=candidate_first_name,
job_name=job_name,
user_fullname = user_fullname
)
return data
I wrote the def text_variables(self): method to fill the data dictionary and use it somewhere else
it work properly but i dont know if it needed to use selected_related or not
something like this (it does not work)
def text_variables(self):
question_result_object = QuestionResult.objects.filter(id=self.id).select_related(
"test__candidate","test__test__company","test__candidate__assessment")
email = question_result_object.test.candidate.user.email
company_name = question_result_object.test.test.company.name
assessment_name = question_result_object.test.candidate.assessment.title
candidate_first_name = question_result_object.test.candidate.user.first_name
job_name = question_result_object.test.candidate.assessment.job_role
data = dict(
job_name=job_name,
company_name=company_name,
email=email,
assessment_name=assessment_name,
candidate_first_name=candidate_first_name,
job_name=job_name,
user_fullname = user_fullname
)
return data
the error is :
File "E:\work\puzzlelity\talent-backend\candidate\models.py", line 385, in report_to_candidate_email_text_variables
email = question_result_object.test.candidate.user.email
AttributeError: 'QuerySet' object has no attribute 'test'
[03/Jan/2023 17:59:00] "POST /api/v1/candidatures/183f8432-ea81-4099-b211-3b0e6475ffab/submit-answer/ HTTP/1.1" 500 123319
I dont know how should i use the select_related
It's never required. It optimizes querysets, especially in ListViews.
Consider your Assessment model. It has ForeignKey fields company and job_role. If you simply fetch
assessment = Assessment.objects.get( id=something)
and then refer to assessment.company, that causes a second DB query to fetch the company object. And then a third if you refer to assessment.job_role.
You can reduce these three queries to one by using
assessment = Assessment.objects.select_related(
'company', 'job_role') .get( id=something)
which does a more complex query to retrieve all the data.
Where it matters is in a list view where you iterate over a large number of assessment objects in Python or in a template. For example, if object_list is assessment.objects.all() and there are 300 of them, then
{% for assessment in object_list %}
... stuff ...
{{assessment.company.name }}
...
{% endfor %}
Will hit the DB 300 times, once for each company! If you use select_related, all 300 companies linked to the 300 assessments will be retrieved in a single DB query. which will be very noticeably faster.
I'd strongly recommend installing Django Debug Toolbar in your development project. Then click on the SQL option on any view, and you can see what SQL was required, and in particular how many SQL queries were performed and whether there were batches of repetetive queries which mean there's a trivial optimisation to be made.
Have a stupid issue: When I open the employee model (in django admin), one field (employee_type) value is replaced automatically, idk why...
Example: I create employee, define employee type as manager, save. In DB value is manager. After that, I open employee and see employee type as sewer and if I save, that value will saved in DB.
I created text choices for this field, and In DB field is defined as enum.
I tried to research the issue, value isn't used from DB, always first value from text choices is used.
By the way, I created same fields (enum in DB and text choices in the model) in other model. And all works properly.
How can I fix it???
Models.py with the issue:
class Employee(models.Model):
class EmployeeType(models.TextChoices):
SEWER = 'SEWER', _('Sewer')
MANAGER = 'MANAGER', _('Manager')
UNDEFINED = 'UNDEFINED', _('Undefined')
user = models.OneToOneField(User,
models.CASCADE,
db_column='user',
verbose_name=_('User'),
primary_key=True)
employee_type = models.CharField(db_column='Employee type',
verbose_name=_('Employee type'),
max_length=9,
choices=EmployeeType.choices,
default=EmployeeType.UNDEFINED)
phone = models.CharField(db_column='Phone',
verbose_name=_('Phone'),
max_length=255)
work_xp = models.IntegerField(db_column='Work XP',
verbose_name=_('Work XP'),
blank=True,
null=True)
Another one models.py. With same fields but without issues:
class Order(models.Model):
class OrderStatus(models.TextChoices):
CREATED = 'Created', _('Created')
CANCELLED = 'Cancelled', _('Cancelled')
IN_PROGRESS = 'In progress', _('In progress')
COMPLETED = 'Completed', _('Completed')
PASSED_TO_CLIENT = 'Passed to the client', _('Passed to the client')
RETURNED_FOR_REWORK = 'Returned for rework', _('Returned for rework')
class Urgency(models.TextChoices):
LOW = 'Low', _('Low urgency')
MEDIUM = 'Medium', _('Medium urgency')
HIGH = 'High', _('High urgency')
VERY_HIGH = 'Very high', _('Very high urgency')
class LabourIntensity(models.TextChoices):
LOW = 'Low', _('1-3 days')
MEDIUM = 'Medium', _('4-6 days')
HIGH = 'High', _('7-9 days')
VERY_HIGH = 'Very high', _('10+ days')
class PaymentStatus(models.TextChoices):
PENDING = 'Pending payment', _('Pending payment')
PREPAYMENT_MADE = 'Prepayment made', _('Prepayment made')
PAID = 'Paid', _('Paid')
id_service = models.ForeignKey(Service,
models.SET_NULL,
db_column='id_Service',
verbose_name=_('Service'),
blank=True,
null=True)
status = models.CharField(db_column='Status',
verbose_name=_('Status'),
max_length=20,
choices=OrderStatus.choices,
default=OrderStatus.CREATED)
payment_status = models.CharField(db_column='Payment status',
verbose_name=_('Payment status'),
max_length=15,
choices=PaymentStatus.choices,
blank=True,
null=True)
prepayment = models.DecimalField(db_column='Prepayment',
verbose_name=_('Prepayment'),
max_digits=19,
decimal_places=2,
blank=True,
null=True)
cost = models.DecimalField(db_column='Cost',
verbose_name=_('Cost'),
max_digits=19,
decimal_places=2,
blank=True,
null=True)
start_date = models.DateTimeField(db_column='Start date',
verbose_name=_('Start date'),
blank=True,
null=True)
end_date = models.DateTimeField(db_column='End date',
verbose_name=_('End date'),
blank=True,
null=True)
id_client = models.ForeignKey(Client,
models.SET_NULL,
db_column='id_Client',
verbose_name=_('Client'),
blank=True,
null=True)
id_employee = models.ForeignKey(Employee,
models.SET_NULL,
db_column='id_Employee',
verbose_name=_('Employee'),
blank=True,
null=True)
labour_intensity = models.CharField(db_column='Labour intensity',
verbose_name=_('Labour intensity'),
max_length=9,
choices=LabourIntensity.choices,
default=LabourIntensity.LOW)
urgency = models.CharField(db_column='Urgency',
verbose_name=_('Urgency'),
max_length=9,
choices=Urgency.choices,
default=Urgency.LOW)
materials = models.ManyToManyField(Material, through='OrderMaterials')
comment = models.TextField(db_column='Comment',
verbose_name=_('Comment'),
blank=True,
null=True)
I solved this issue.
In DB a type of field "employee_type" was defined as:
ENUM('Undefined','Sewer','Manager')
But the model has EmployeeType choices with uppercase.
Solution: I changed lowercase to uppercase of the values in the field type in DB:
ENUM('UNDEFINED','SEWER','MANAGER')
Now everything works fine.
I am using django import_export package for export my data into xlsx file.
I am having issue while exporting the data to excel in the format I need.
models.py
class Fans(models.Model):
"""
Model for survey answering people
"""
fan_id = models.AutoField(db_column='FAN_ID', primary_key=True)
first_name = models.CharField(
db_column='FIRST_NAME', max_length=45, blank=True, null=True)
last_name = models.CharField(
db_column='LAST_NAME', max_length=45, blank=True, null=True)
phone = models.CharField(
db_column='PHONE', max_length=45, blank=True, null=True)
email = models.CharField(
db_column='EMAIL', max_length=45, blank=True, null=True)
gender = models.CharField(
db_column='GENDER', max_length=45, blank=True, null=True)
class Responses(models.Model):
"""
Model for responses given by fans
"""
survey = models.ForeignKey(
Surveys, on_delete=models.CASCADE, db_column='SURVEY_ID', related_query_name="part")
fan = models.ForeignKey(Fans, on_delete=models.CASCADE,
db_column='FAN_ID', related_query_name="given", related_name="given")
survey_question = models.ForeignKey(
SurveyQuestions, on_delete=models.DO_NOTHING, db_column='SURVEY_QUESTION_ID',
related_query_name="response")
response = models.CharField(
db_column='RESPONSE', max_length=255, blank=True, null=True)
correct_answer = models.IntegerField(
db_column='CORRECT_ANSWER', blank=True, null=True)
load_id = models.IntegerField(db_column='LOAD_ID', blank=True, null=True)
class SurveyQuestions(models.Model):
"""
Model for surveys questions
"""
survey = models.ForeignKey(Surveys, on_delete=models.CASCADE,
db_column='SURVEY_ID', related_query_name="question")
survey_question_id = models.AutoField(
db_column='SURVEY_QUESTION_ID', primary_key=True)
survey_question_name = models.CharField(
db_column='SURVEY_QUESTION_NAME', max_length=255)
question = models.CharField(
db_column='QUESTION', max_length=255, blank=True, null=True)
response_type = models.CharField(
db_column='RESPONSE_TYPE', max_length=255, blank=True, null=True)
load_date = models.DateField(db_column='LOAD_DATE', auto_now_add=True)
I want to export data of the fans with recorded responses in the following format:
first_name, last_name, phone, email, question1, question2, question3
abc, xyz, 1234566780, abc#gmail.com, response1, response2, response3
Here, the first four fields are directly from Fans model, however the last three column headers represent "question" field from SurveyQuestions model and values come from the "response" field of Responses model.
Till now, I am able to achieve the following format:
first_name, last_name, phone, email, given
abc, xyz, 1234566780, abc#gmail.com, {question1: response1, question2: response2, question3: response3}
given field is json of question-response as key-value pair.
admin.py
class FanResource(resources.ModelResource):
"""
Resource for exporting to excel
"""
given = fields.Field()
class Meta:
model = Fans
fields = ("first_name", "last_name", "email",
"phone", "given")
def dehydrate_given(self, instance):
res = {}
for x in instance.given.values('response', 'survey_question__question'):
res[x['survey_question__question']] = x['response']
return json.dumps(res)
Any help would be appreciated. Thanks in advance!!
14/10/20 UPDATE
Using the answer below, I was able to achieve the format required. Code is as follows:
def after_export(self, queryset, data, *args, **kwargs):
survey_questions = {x["survey_question_id"]: x["question"] for x in SurveyQuestions.objects.filter(
survey=self.survey).values('survey_question_id', 'question')}
for k, v in survey_questions.items():
res = []
for x in queryset:
try:
res.append(x.given.get(survey_question=k).response)
except ObjectDoesNotExist:
res.append(None)
data.append_col(res, header=v)
Now, the issue is that it is taking too long as it is hitting the database for each entry. And other issue is order is not proper (i.e responses are not in same line as per the corresponding fans).
I think the way to achieve this would be to override after_export(), and manipulate the exported dataset. For example:
def after_export(self, queryset, data, *args, **kwargs):
response1 = [i for i in range(data.height)]
data.append_col(response1, header="response1")
response2 = [i for i in range(data.height)]
data.append_col(response2, header="response2")
This will append new columns to the end of the export. In after_export() you will have access to both the data set and the queryset, so hopefully you can manipulate this data to fill the 'response' columns correctly.
Example:
class Room(models.Model):
assigned_floor = models.ForeignKey(Floor, null=True, on_delete=models.CASCADE)
room_nr = models.CharField(db_index=True, max_length=4, unique=True, null=True)
locked = models.BooleanField(db_index=True, default=False)
last_cleaning = models.DateTimeField(db_index=True, auto_now_add=True, null=True)
...
class Floor(models.Model):
assigned_building = models.ForeignKey(Building, on_delete=models.CASCADE)
wall_color = models.CharField(db_index=True, max_length=255, blank=True, null=True)
...
class Building(models.Model):
name = models.CharField(db_index=True, max_length=255, unique=True, null=True)
number = models.PositiveIntegerField(db_index=True)
color = models.CharField(db_index=True, max_length=255, null=True)
...
I want to output all rooms in a table sorted by Building.number.
Data which I want to print for each room:
Building.number, Building.color, Building.name, Floor.wall_color, Room.last_cleaning
Furthermore I want to allow optional filters:
Room.locked, Room.last_cleaning, Floor.wall_color, Building.number, Building.color
With one table it's no Problem for me, but I don't know how I archive this with three tables.
kwargs = {'number': 123}
kwargs['color'] = 'blue'
all_buildings = Building.objects.filter(**kwargs).order_by('-number')
Can you please help me? Do I need write raw SQL queries or can I archive this with the Django model query APIs?
I'm using the latest Django version with PostgreSQL.
No raw sql needed:
room_queryset = Room.objects.filter(assigned_floor__wall_color='blue')
^^
# A double unterscore declares the following attribute to be a field of the object referenced in the foregoing foreign key field.
for room in room_queryset:
print(room.assigned_floor.assigned_building.number)
print(room.assigned_floor.assigned_building.color)
print(room.assigned_floor.assigned_building.name)
print(room.assigned_floor.wall_color)
print(room.last_cleaning)
I have master to child tables, need a solution to render it with below condition.
Master Table Fields:-
Person product categ price image field1 field2
Child Table (User customised):-
User Product categ customprice customfield1 customfield2
Query:-
totalrecords = Master.objects.filter(Person=person1).filter(categ=catogory1)
enabledrecords = Child.objects.filter(user=user).filter(categ=categ1)
product in child is foreign key from Master.
In template I will extract the master fields(in for loop) but if price and customfields exists in child then I need to take child object using product relation, otherwise populate these from master table.
Here the confusion comes,
{% for obj in totalrecords %}
if obj.id in enabledrecords (using product forign key) then
Get en_obj from enabledrecords__product
{{obj.id}} {{en_obj.id}} {%if en_obj.customprice%} {{en_obj.customprice}}
{%else%}{%obj.price%}{%endif%} -->do same for other customfields
if obj.id not in enabledrecords
{{ obj.id }} <p> Product not customized click here to customise </p>
Please advice.
EDIT:
Products(Master Table):-
vendor = models.ForeignKey(Shop,verbose_name='Shop Name')
name = models.CharField('Product Name', max_length=100 )
pfimage = models.ImageField('Image', upload_to='pd/%Y',)
pdctg = models.ForeignKey(PdCtg, null=True, blank=True, verbose_name='Product Category')
mrp =models.DecimalField('MRP (optional)',max_digits=6, decimal_places=2, null=True, blank=True)
ourprice =models.DecimalField('Our Price (optional)',max_digits=6, decimal_places=2, null=True, blank=True)
offer =models.CharField('Offers (optional)',max_length=10, null=True, blank=True)
Child Table:
vendor =models.ForeignKey(Shop,verbose_name='Shop Name')
pdctg = models.ForeignKey(PdCtg,null=True, blank=True,verbose_name='Product Category')
products =models.ForeignKey(Products, verbose_name='Product Name')
pdid =models.CharField('Item ID',max_length=100, null=True, blank=True)
mrp =models.DecimalField('MRP (optional)',max_digits=6, decimal_places=2, null=True, blank=True)
ourprice =models.DecimalField('Our Price (optional)',max_digits=6, decimal_places=2, null=True, blank=True)
offer =models.CharField('Offers (optional)',max_length=10, null=True, blank=True)
Child table may or may not have all rows of master for a given vendor and pdctg