I am trying to display data from two different models. The two models have a one-to-many relationship but I am not sure why it is not displaying the data from the MembersPresent model. Here are my models
and view
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
def __str__(self):
return self.mode_of_meeting
class MembersPresent(models.Model):
flyminute = models.ForeignKey(fly_minute, on_delete=models.CASCADE)
name = models.CharField(max_length=25)
status = models.CharField(max_length=25)
email = models.EmailField(max_length=25)
phone = models.IntegerField()
def __str__(self):
return self.name
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id)
return render(request, 'minute_report.html', locals())
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.flyminute.name}}</td>
<td>{{rpt.flyminute.status}}</td>
<td>{{rpt.flyminute.email}}</td>
<td>{{rpt.flyminute.phone}}</td>
</tbody>
{%endfor%}
You need to use 'prefetch_related()'
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
This has a similar purpose to select_related, in that both are designed to stop the deluge of database queries that is caused by accessing related objects, but the strategy is quite different.
models.py
class MembersPresent(models.Model):
flyminute = models.ForeignKey(
fly_minute,
related_name='memberspresent_set', # this will be the default name, incase of need of change provide a new one
on_delete=models.CASCADE
)
...
views.py
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id).prefetch_related('memberpresent_set')
return render(request, 'minute_report.html', locals())
For further control, you can use Prefetch along with prefetch_related()
Note:
locals() returns a dict of all the locally defined variables in the current scope and this may result in exposing sensitive info. Instead of that create a custom dict and return it.
...
context = {
'report': report,
...
}
return render(request, 'minute_report.html', context)
You are referencing and querying in the opposite way. Your fly_minute model doesn't contain MembersPresent model as the Foreign Key. You are filtering the fly_minute model and trying to access MembersPresent model. So, you should change your fly_minute to in this way:
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
member = models.ForeignKey(MembersPresent, on_delete=models.CASCADE)#add this line and remove fly_minute in MembersPresent model
def __str__(self):
return self.mode_of_meeting
Then in template file change it to in this way:
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.member.name}}</td>
<td>{{rpt.member.status}}</td>
<td>{{rpt.member.email}}</td>
<td>{{rpt.member.phone}}</td>
</tbody>
{%endfor%}
I guess it works
Thanks, I ended up using fetch-related and had to make adjustments to my template.
<tr>
<th>Name</th>
<th>Status</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
{%for rpt in report%}
{%for rpts in rpt.memberspresent_set.all%}
<tbody>
<tr class="table-active">
<td>{{rpts.name}}</td>
<td>{{rpts.status}}</td>
<td>{{rpts.email}}</td>
<td>{{rpts.phone}}</td>
</tbody>
{%endfor%}
{%endfor%}
Related
I am trying to display multiple uploaded file URLs but I'm not sure how to do it. I am a form that the users can use to upload multiple files that are working perfectly but now I want to be able to display these files. For instance, a company can have more than one file.
class InternationalCompany(models.Model):
International_company_Name = models.CharField(max_length=50)
International_company_Id = models.CharField(max_length=50)
options = (
('Yes', 'Yes'),
('No', 'No'),
)
Does_it_have_a_Financial_Dealers_License = models.CharField(max_length=20, choices=options, null=True)
Register_Office = models.TextField(max_length=500, null=True)
Beneficial_owner = models.CharField(max_length=100, null=True)
Beneficial_owner_id = models.FileField(upload_to='passport/pdf/',null=True)
expire_date = models.DateField(null=True)
BO_Phone_number = models.IntegerField(null=True)
BO_Email_Address = models.EmailField(null=True)
BO_Residential_Address = models.TextField(max_length=200, null=True)
def __str__(self):
return self.International_company_Name
class SupportDocuments(models.Model):
Supporting_Documents = models.FileField(upload_to='support_doc/pdf/', null=True)
internationalcompany = models.ForeignKey(InternationalCompany, on_delete=models.CASCADE)
def __str__(self):
return self.Supporting_Documents.url
I try something like this but it only displayed one url of the file instead of the multiple urls for the files that are associate with that company.
{%for company in doc%}
<tr>
<td></td>
<td>{{company.internationalcompany.Beneficial_owner}}</td>
<td>{{company.Supporting_Documents.url}}</td>
</tr>
{%endfor%}
I have also try out this but it doesn't display anything.
{%for company in doc.Supporting_Documents.all%}
{{company.url}}
{%endfor%}
def supporting_doc(request, company_id):
doc = SupportDocuments.objects.filter(id=company_id)
return render(request, 'supporting_doc.html', locals())
First of all, it might be better to use context rather than locals() as discussed here
Second, the way you get the doc queryset is wrong. id=company_id The id of SupportingDocuments is different from company_id. What you really need to do is internationalcompany.id=company_id.
so views.py:
def supporting_doc(request, company_id):
documents = SupportDocuments.objects.filter(internationalcompany.id=company_id)
context = { "documents": documents}
return render(request, 'supporting_doc.html', context)
in template:
{% for doc in documents %}
{{ doc.internationalcompany.Beneficial_owner}}
{{ doc.Supporting_Documents }}
{% endfor %}
On a side note, it may be better to use all lowercases in fields. This way, it is easy to distinguish fields and models.
I have a model where one field is a ForeignKey so that each child object is linked to a parent object.
In my (jinja2) templates, I list some attributes from a subset of objects from the child model, including one of the parents' attributes. The page loads very slowly, so I am wondering if there is a faster way to do the following:
views.py
class TransactionView(LoginRequiredMixin, ListView):
model = Transactions
context_object_name = 'transaction_list'
template_name = 'bank/transactions.html'
def get_queryset(self):
return Transactions.objects.filter(owner_id=self.request.user)
template.html
<tbody>
{% for transaction in transaction_list %}
<tr>
<td>{{transaction.source_document.service_provider}}</td>
<td>{{transaction.account}}</td>
<td>{{transaction.tnsx_date}}</td>
<td>{{transaction.end_bal}}</td>
<td>{{transaction.amount}}</td>
<td>{{transaction.category}}</td>
</tr>
{% endfor %}
</tbody>
models.py
class Transactions(models.Model):
def __str__(self):
return str(self.tnsx_uuid)
owner = models.ForeignKey(
User,
on_delete=models.CASCADE,
db_index=True,
editable=True,
)
source_document = models.ForeignKey(
Document,
on_delete=models.CASCADE,
editable=True,
)
tnsx_uuid = models.UUIDField(default=uuid.uuid4, unique=True)
account = IBANField(enforce_database_constraint=True)
currency = models.CharField(max_length=4, blank=False, null=False)
currency_assumed = models.BooleanField(null=False)
<etc>
As iklinac suggested, using .prefetch_related() increases the speed of the query dramatically.
change views.py to the following:
class TransactionView(LoginRequiredMixin, ListView):
model = Transactions
context_object_name = 'transaction_list'
template_name = 'bank/transactions.html'
def get_queryset(self):
return Transactions.objects.filter(owner_id=self.request.user).prefetch_related('source_document')
I have a Tourguide model with a many to many relationship with Places. Both models are defined as :
class Tourguide(models.Model):
id = models.AutoField(db_column='ID', primary_key=True, unique=True)
title = models.CharField(db_column='Title', max_length=255, blank=True)
places = models.ManyToManyField(Place, db_column='placesdj')
places_app = models.CharField(max_length=255, db_column='places')
created_on = models.DateTimeField(db_column='Created_On', default = now)
class Meta:
managed = False
db_table = 'tourguide'
def __str__(self):
return self.title
class Place(models.Model):
place_id = models.AutoField(db_column='ID', primary_key=True)
place_name = models.CharField(db_column='Place_Name', max_length=255)
address_line_1 = models.CharField(db_column='Address_Line_1', max_length=255)
address_line_2 = models.CharField(db_column='Address_Line_2', max_length=255)
area = models.CharField(db_column='Area', max_length=255)
class Meta:
managed = False
db_table = 'Place'
def __str__(self):
return self.place_name
THE PROBLEM
When I try to print the places in a tourguide using :
{% for place in tour.places.all %}
<tbody>
<td>{{ forloop.counter }}</td>
<td>id: {{place.place_id}}, {{ place.place_name }} </td>
<td> {{ place.description }} </td>
</tbody>
{% endfor %}
The order of the places is all random and not the same as the order I inputed it as. I want to print the places in the same order that I placed them in. My view for listing the tourguides and places within them is as so.
def tour_list(request, template_name='tourguides/tour_list.html'):
tourguide_list = Tourguide.objects.all()
paginator = Paginator(tourguide_list,6)
page = request.GET.get('page')
tourguides = paginator.get_page(page)
data = {}
data['tourguides'] = tourguides
return render(request, template_name, data)
Update
I have an array of place id's in the tourguide table, is there a way i can use that?
Relational databases do not sort rows by default, and since they are internally stored in all kinds of weird data structures, there is no "input order" either.
As a workaround, you can use the automatically generated place_id field as a sort key as it is pretty much guaranteed to go up as new entries are created. You can add a default sorting to your Place class, for example:
class Place(models.Model):
...
class Meta:
...
ordering = ('place_id',)
That would guarantee that any queries that will return a Place queryset will be ordered by place_id by default (i.e. unless you have an explicit .order_by() clause).
I have read every answer for this question but none of them solved my problem completely. I hope someone can help me understand what is wrong in my code. I have a field in my model and I want all the values in that field to be displayed in a dropdown in my form. I was able to achieve that but when I try to save, it says "Select a valid choice. That choice is not one of the available choices." Any help would be greatly appreciated.
models.py
class Item(models.Model):
Product = models.ForeignKey("Product", related_name = "Items")
Name = models.CharField(max_length=1000, blank=True, null=True)
Tag = models.CharField(max_length=1000, blank=True, null=True)
forms.py
class ItemForm(ModelForm):
items = Item.objects.values_list('Name', flat=True)
item_choices = [(item, item) for item in items]
Name = forms.ModelChoiceField(items, widget=forms.Select())
class Meta:
model = Item
fields = ['Name', 'Tag']
views.py
def newknowledgebase(request):
itemformset = modelformset_factory(Item, form=ItemForm, extra=2)
items = itemformset(queryset=Item.objects.none(), prefix='items', )
if request.method=='POST':
items = itemformset(request.POST, queryset=Item.objects.none(), prefix='items', )
item = request.POST.get('items')
for form in items:
form.fields['Name'].choices = [(item, item)]
if items.is_valid():
items.save()
context = {
'items':items,
}
return render(request, 'newknowledgebase.html', context )
html file
<div id="items" class="panel-collapse collapse">
<table class="table table-bordered">
<tbody>
{{ items }}
</tbody>
</table>
</div>
Try this
Name = forms.ChoiceField(item_choices, widget=forms.Select())
Here's what I currently have:
class Sessions(models.Model):
sessionId = models.AutoField(primary_key=True)
class Ip(models.Model):
ipId = models.AutoField(primary_key=True)
class Affiliation(models.Model):
affiliationId = models.AutoField(primary_key=True)
ip = models.ForeignKey("Ip", null=False, db_column="ipId")
session = models.ForeignKey("Sessions", null=False, db_column="sessionId")
Now I want to find the Sessions QuerySet which returns ipId=x. Basically this is what I'm trying:
Sessions.objects.filter(affiliation__ip=x)
Is there any way I can do this in django?
Found the answer!
psobjs = Affiliation.objects.filter(ipId=x)
queryset = Sessions.objects.filter(sessionId__in=psobjs.values('sessionId'))
Refactor your code
Apologize, Please bear with me and learn from it.
You don't have to explicitly specify the id in Django. unless your class is unmanaged. Django automatically use id or pk to refer to it.
class Sessions(models.Model):
pass
Model naming usually Singular Session.
class Session(models.Model):
pass
Watch out for conflict model name, Session is already used internally by Django django.contrib.sessions.models.Session. Use alternative name such as ClientSession would be better.
class ClientSession(models.Model):
pass
Use ManyToManyField (optional), it is just a helper to simplify your queryset.
class ClientSession(models.Model):
client_source = models.ManyToManyField('IP', through='Affiliation')
Use GenericIPAddressField
class IP(models.Model):
address = models.GenericIPAddressField()
You have no additional attribute in Affiliation, thus you can consider removing it.
class ClientSession(models.Model):
client_source = models.ManyToManyField('IP')
Final Model
class ClientSession(models.Model):
client_source = models.ManyToManyField('IP')
class IP(models.Model):
address = models.GenericIPAddressField()
Answer
Querying Session is very straight forward with the current Model.
x = 1 # Some ID
ClientSession.objects.filter(ips__id=x)
I think if you use a related_name in Affiliation model like this:
class Sessions(models.Model):
sessionId = models.AutoField(primary_key=True)
class Ip(models.Model):
ipId = models.AutoField(primary_key=True)
class Affiliation(models.Model):
affiliationId = models.AutoField(primary_key=True)
ip = models.ForeignKey("Ip", null=False, db_column="ipId")
session = models.ForeignKey(
"Sessions", null=False,
db_column="sessionId",
related_name="affiliation_session"
)
Now you can filter:
Sessions.objects.filter(affiliation_session__ip_id=X)
You can use select_related for optimization if necessary
I want to show a report where I want customer_name, mobile_no, from Details table and status from Status table. You can see my model
class Details(models.Model):
customer_name = models.CharField(max_length=100,unique=True)
mobile_no = models.IntegerField()
class Status(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=25)
purchase = models.ForeignKey(Details, null=True, on_delete=models.SET_NULL)
Solution
Step1: Add the following code to your view. [views.py]
def customer_report(request):
status_obj = Status.objects.all()
return render('reports/customer_report.html', {'status_obj':status_obj})
Step2: Add the following code at your template side [report.html]
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Mobile No</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for data in status_obj %}
<tr>
<td>{{data.purchase.customer_name}}</td>
<td>{{data.purchase.mobile_no}}</td>
<td>{{data.status}}</td>
</tr>
{% endfor %}
</tbody>
</table>