for joining many models with each other, I did , for example :
Message.objects.filter(conversation__recipient__user=request.user)
when I want to use it in the template side , it doesn't show me anything. example:
{{row.conversation.recipient.user.username}}
this is my code:
model:
class Conversation(models.Model):
user = models.ForeignKey(User)
def __unicode__(self):
return self.user
class Message(models.Model):
conversation = models.ForeignKey(Conversation)
title = models.CharField(max_length=50)
body = models.CharField(max_length=500)
parent = models.IntegerField(default=0)
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.title
class Recipient(models.Model):
user = models.ForeignKey(User)
conversation = models.ForeignKey(Conversation)
is_read = models.BooleanField(default=False)
view:
def admin_index(request):
rows = Message.objects.filter(conversation__recipient__user=request.user)
return render(request,'message/admin/index.html',{'rows':rows})
template:
{% for i in rows %}
{% if not i.conversation.recipient.is_read %}
<tr class="set_bold">
{% else %}
<tr>
{% endif %}
<td>name:{{i.conversation.recipient}}</td>
<td class="col-md-0"><input type="checkbox"></td>
<td class="col-md-2">{{i.conversation.user.username}}</td>
<td>{{i.title}}</td>
<td>{{i.created|date:"y-m-d"}} <small>({{i.created|timesince}})</small></td>
</tr>
{% empty %}
<tr>
<td colspan="4">{% trans "dont have any message" %}</td>
</tr>
{% endfor %}
So how can I get access to recipient models in views and templates via Message model?
Thanks
As Recipient model has ForeignKey with Conversation model, there are many recipients for a conversation. So conversation objects will have receipient_set as queryset. You need to iterate over it and get either first/last or all objects to display.
So your template code needs to change as
{% for i in rows %}
{%for recp in i.conversation.recipient_set.all %}
{# do something with each recipient object
{% if not recp.is_read %}
<tr class="set_bold">
{% else %}
<tr>
....
{%endfor%}
{%endfor%}
Related
When I am filtering for my search bar I am getting this error. I am not sure what I am doing wrong here
Watching this tutorial: https://www.youtube.com/watch?v=llbtoQTt4qw&t=3399s
views.py
class pplList(LoginRequiredMixin,ListView):
model = People
context_object_name = 'people'
def get_context_data(self, **kwargs):
search_input = self.get.GET.get('search-area') or ''
if search_input:
context['people'] = context['people'].filter(name__icontains=search_input)
return context
people_list.html
{%if request.user.is_authenticated %}
<p>{{request.user}}</p>
Logout
{% else %}
Login
{% endif %}
<hr>
<h1>Interviewee Dashboard {{color}}</h1>
Add Candidates
<form method="get">
<input type = 'text' name = 'search-are'>
<input type = 'submit' value = 'Search'>
</form>
<table>
<tr>
<th> Item</th>
<th> </th>
</tr>
{% for people in people %}
<tr>
<td>{{people.name}}</td>
<td>View</td>
<td>Edit</td>
<td>Delete</td>
</tr>
{% empty %}
<h3>No items in list</h3>
{% endfor %}
</table>
There are some minor mistakes such as it should be self.request.GET.get('search-area'), also you haven't called the super() method, so try this view:
class pplList(LoginRequiredMixin,ListView):
model = People
context_object_name = 'people_list'
def get_context_data(self, **kwargs):
context=super().get_context_data(**kwargs)
search_input = self.request.GET.get('search-area', False)
if search_input:
context['people']= People.objects.filter(name__icontains=search_input)
return context
In the Html, the field name search-are and you are accessing in the view as self.request.GET.get('serach-area', False) kindly change its name to search-area` in the input tag of Html.
Also, class based views are generally written in PascalCase as they are classes of Python and requires their name to be written as model name as prefix and actual view name as suffix, so it should be PeopleListView.
I'm hoping I can get a little guidance.
I'm trying to return data from 3 related tables in my template. In SQL, this is a simple approach, but the Django requirements have me stumbling.
I'd like to display information similar to this:
WaiverAdult.first_name CheckIn.checkintime
WaiverMinor.first_name CheckIn.checkintime
WaiverAdult.first_name CheckIn.checkintime
WaiverMinor.first_name CheckIn.checkintime
WaiverMinor.first_name CheckIn.checkintime
Here are a simplified representation of the models with the relationships defined.
class WaiverAdult(models.Model):
first_name = models.CharField(max_length=50, blank=True)
class WaiverMinor(models.Model):
first_name = models.CharField(max_length=50, blank=True)
parent = models.ForeignKey(WaiverAdult, on_delete=models.CASCADE)
class CheckIns(models.Model):
adult = models.ForeignKey(WaiverParent, on_delete=models.CASCADE, blank=True, null=True)
minor = models.ForeignKey(WaiverChild, on_delete=models.CASCADE, blank=True, null=True)
checkintime = models.DateTimeField(auto_now_add=True)
Here is my simplified view:
class WaiverListView(ListView):
waiver_adults = WaiverAdult.objects.all().prefetch_related(
'waiverminor_set').order_by('created')
queryset = waiver_adults
context_object_name = "waiver_list"
template_name = 'waiver/waiver_list.html'
And, this is my template.
{% for adult in waiver_list %}
<tr>
<td>{{adult.first_name}}</td>
<td>insert the adult checkin time here</td>
</tr>
{% for child in adult.waiverminor_set.all %}
<tr>
<td>{{child.first_name}}</td>
<td>insert the child checkin time here</td>
</tr>
{% endfor %}
{% endfor %}
I would be very appreciative of details in the explanations as I really want to understand how this all works.
Firstly, for every Foreign key you are creating I suggest you to add a related_name this way you specify the name of reverse relation ship between the children model and parent model in your case for example, your code should be:
class WaiverAdult(models.Model):
first_name = models.CharField(max_length=50, blank=True)
class WaiverMinor(models.Model):
first_name = models.CharField(max_length=50, blank=True)
parent = models.ForeignKey(WaiverAdult, on_delete=models.CASCADE,related_name='minor_of_adult')
and let's explain how does it work, you want to know and get all the minors of some adult, what you should do is specify the adult, and get all minor related to that adult, in code context (try it in django shell, using python manage.py shell):
adult = WaiverAdult.objects.get(first_name='cbirch') #specifying the adult
adult.minor_of_adult.all() #notice how we access the minor using the related_name
same thing apply to the last model CheckIns.
With the models you have created it is possible to have multiple checkin times per parent and child so you need to loop through the list. Also your foreign keys refer to WaiverParent and WaiverChild whilst the actual model names are WaiverAdult and WaiverMinor. You could try the following template:
{% for adult in waiver_list %}
<tr>
<td>{{adult.first_name}}</td>
<td>
{% for checkin in adult.checkins_set.all %}
{{ checkin.checkintime }}
{% endfor %}
</td>
</tr>
{% for child in adult.waiverminor_set.all %}
<tr>
<td>{{child.first_name}}</td>
<td>
{% for checkin in child.parent.checkins_set.all %}
{{ checkin.checkintime }}
{% endfor %}
</td>
</tr>
{% endfor %}
{% endfor %}
I have two models in my django application (Client and Installment). My models.py is given below:
models.py
from django.db import models
from django.utils import timezone
from django.urls import reverse
# Create your models here.
class Client(models.Model):
name = models.CharField(max_length = 100)
dob = models.SlugField(max_length = 100)
CNIC = models.SlugField(max_length = 100)
property_type = models.CharField(max_length = 100)
down_payment = models.IntegerField()
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('client_details',kwargs={ 'pk' : self.pk})
class Installment(models.Model):
client = models.ForeignKey(Client, null=True, on_delete=models.CASCADE)
installment_month = models.CharField(max_length = 100)
installment_amount = models.IntegerField()
installment_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.installment_month
def get_absolute_url(self):
return reverse('installment_confirmation')
And to show the client details I have a view called 'clientDetailView' and is shown below:
view.py
class ClientDetailView(DetailView):
model = Client
model = Installment
And the template for this is called 'client_details.html' is also given below:
<!DOCTYPE html>
{% extends "property_details/base.html" %}
{% block content %}
<body>
<legend class="border-bottom mb-4"><h3>{{ object.name }}</h3></legend>
<article class="media content-section">
<div>
<p class="text-muted">Client CNIC: {{ object.CNIC }}</p>
<p class="text-muted">Date of Birth: {{ object.dob }}</p>
<p class="text-muted">Type of Property: {{ object.property_type }}</p>
<p class="text-muted">Date of Agreement: {{ object.date_posted|date:"F d, Y" }}</p>
</div>
</article>
<legend class="border-bottom mb-4"><h5>Installment History</h5></legend>
<article class="media content-section">
<div>
<!--<p class="text-muted">Installment Month: {{ object.installment_month }}</p>-->
<table id="installmentTable" style="width:100%">
<tr>
<th style="width:200px">Date</th>
<th style="width:400px">Installment Month</th>
<th style="width:100px">Amount</th>
</tr>
{% for installment in installments %}
<tr>
<td>{{ installment.installment_date }}</td>
<td>{{ installment.installment_month }}</td>
<td>{{ installment.installment_amount }}</td>
</tr>
{% endfor %}
</table>
</div>
</article>
<a class="btn btn-outline-info" type = "submit" href="{% url 'add_installment' object.id %}" >Add New Installment</a>
</body>
{% endblock %}
Up to this point, When I click on the client name, it shows all the details of the client. But I also want to see the installment details of that particlar client in the form of table on the same 'client detail' page.
For that, I made a table and tried to access the fields of installment model.
But it doesn't show anything about installments.
I have a doubt that I am accessing the fields of client model using object.name, object.dob etc. And to print installments and I am also using object.installment_month etc.
How django can differenciate between two objects?
And I also tried to import both models in 'clientDetailView' as you can see above. but it gives the following error:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/8/
Raised by: property_details.views.ClientDetailView
No installment found matching the query
This is driving me mad (I really have looked everywhere - but I know it must be easy and I'm just being a tad think)
How do I add a filter to a child of a parent (one to many)? The code below provides a list of companies in a table, then on the same page/ table, each company has a list of "charges" which is attributed to that company; thanks to the ForeignKey and using "charge_set" it works great. However, I would like to add a filter to the "charges" for status (so exclude "outstanding" status)
In ROR I would have simply placed the following
<% company.charges.where(status: "Outstanding").each do |charge| %>
AIUI, I can't do this with Python/ Django in the view; so how would I go about adding a simple filter to the child of the parent within this loop?
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
class Charge(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
charge_id = models.CharField(max_length=100)
status = models.CharField(max_length=100)
from django.shortcuts import render
from companies.models import Company, Charge, Filing
from django.http import HttpResponse
def watch_list(request):
companies = Company.objects.order_by('-data_date')
return render(request,'company_watch/watch_list.html',{'companies':companies})
{% for company in companies %}
<tr>
<td>{{company.name}}</td>
<td>
<ul>
{% for charge in company.charge_set.all %}
<li>{{charge.charge_id}}</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
You can just grab the company and filter the children. If you want to the children on the backend:
company = Company.objects.get('...')
outstanding_children = Charge.objects.filter(company = company, status = "Outstanding")
If you want to display the children on the frontend:
{% for company in companies %}
<tr>
<td>{{company.name}}</td>
<td>
<ul>
{% for charge in company.charge_set.all %}
{% if charge.status == "Outstanding" %}
<li>{{charge.charge_id}}</li>
{% endif %}
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
Right now I am using Class-based delete view, and my URL contains two arguments which are the primary keys of my 2 models: Post and Lesson. However, I am encountering an Attribute Error: Generic detail view LessonDeleteView must be called with either an object pk or a slug in the URLconf.
These are my two models Lesson and Post:
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(default = 'default0.jpg', upload_to='course_image/')
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=6)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField(default = 0)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk' : self.pk})
class Lesson(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to="lesson/pdf")
date_posted = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(Post, on_delete=models.CASCADE, null=False, blank=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('lesson_upload', kwargs={'pk': self.pk})
This is my URLs.py:
path('post/<int:post_id>/lesson_uploaded/<int:lesson_id>', LessonDeleteView.as_view(), name='lesson_delete'),
Right now this is how I am trying to insert the parameters in my html template:
{% block content %}
<div id="main">
<table class="table mb-0">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Download</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for l in Lesson %}
<tr>
<td>
{% if l.file %}
{{ l.title }}
{% else %}
<h6>Not available</h6>
{% endif %}
</td>
<td>{{ l.post.author }}</td>
<td>{% if l.file %}
Download
{% else %}
<h6>Not available</h6>
{% endif %}
</td>
<td> <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'lesson_delete' post.id l.id %}">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
This is my class-based view:
class LessonDeleteView(DeleteView):
model = Lesson
success_url = '../'
template_name = 'lesson_confirm_delete.html'
As you are deleting Lesson, you don't need to provide Post ID. You can simply use Lesson ID here. So try like this:
# url
path('post/lesson_uploaded/<int:pk>/', LessonDeleteView.as_view(), name='lesson_delete'), # using pk instead of lession_id, it will resolve the error you are facing
# template
<td> <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'lesson_delete' l.id %}">Delete</a>
</td>
Update
from comment section, you can override the delete method like this:
class LessonDeleteView(DeleteView):
model = Lesson
success_url = '../'
template_name = 'lesson_confirm_delete.html'
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.file.delete() # <-- added file delete code
success_url = self.get_success_url()
self.object.delete()
return HttpResponseRedirect(success_url)
Why are you passing the lesson id.
Since Post gets deleted by default lesson would get deleted as well. Check this video to better understand how to pass the id and details on Delete View.
DeleteView(Class Based Views)