How to check if the object is assigned to another object | Django - django

I am working on a django case like below:
models.py
class Room(models.Model):
name = models.CharField("Room No.",max_length=200)
class Meta:
verbose_name_plural = "Room"
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField("name",max_length=200)
father_name = models.CharField("father Name",max_length=200)
cell_no = models.CharField("cell No",max_length=200)
address = models.CharField("address",max_length=500)
room = models.ForeignKey(Room, on_delete=models.CASCADE, null=True, blank=True, related_name='all_rooms')
class Meta:
verbose_name_plural = "Student"
def __str__(self):
return self.name
views.py
def room(request):
allrooms= Room.objects.all()
form = RoomForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
messages.success(request, "Room added successfully.")
return redirect('/room')
context = {'allrooms':allrooms, 'form':form}
return render(request, 'room.html', context)
In templates in room.html I want to show the status Vacant/Occupied based on the fact if a room is assigned to some student or not. I have the following code in template but it shows 'Vacant' status for all rooms.
<table id="example1" class="table table-bordered table-striped">
<thead>
<tr>
<th>Room</th>
<th class="text-center">Status</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
{% for room in allrooms %}
<tr>
<td>{{ room.name }}</td>
<td class="text-center">
{% if room.student_set.all %}
<small class="badge badge-danger">Occupied</small>
{% elif not room.student.all %}
<small class="badge badge-success">Vacant</small>
{% endif %}
</td>
<td class="text-center"><i class="fas fa-edit"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
Please help someone to show he status of the room.

to get assigned and unassigned rooms you have to write queries with respect to the related field(in this case the foreign key "all_rooms") as follows:
total_rooms = Room.objects.all().annotate(num_rooms=Count("all_rooms"))
assigned_rooms = total_rooms.filter(num_rooms__gt=0)
unassigned_rooms = total_rooms.exclude(num_rooms__gt=0)
On running, these queries will return the room instances:

Related

How can I capture the name or reg_no of the book in this list?

I'm working on a library system. I am unable to get the registration number of a book/books to be returned back to library...
My intention is to click on Return which captures the book name for return processing.. With what I have, when I print(book) it returns None meaning nothing has been taken from the click
My models
class Books(models.Model):
DEPARTMENT = (
('COM', 'Computer'),
('ELX', 'Electronics'),
('CIV', 'Civil'),
('BBS', 'Business'),
('MSC', 'Miscellaneous'),
)
reg_no = models.CharField(max_length=20, blank=True)
book_name = models.CharField(max_length=200)
no_of_books = models.IntegerField()
book_detail = models.TextField(default='text')
department = models.CharField(max_length=3, choices=DEPARTMENT)
def Claimbook(self):
if self.no_of_books>1:
self.no_of_books=self.no_of_books-1
self.save()
else:
print("not enough books to Claim")
def Addbook(self):
self.no_of_books=self.no_of_books+1
self.save()
def __str__(self):
return self.book_name
class Return(models.Model):
return_date = models.DateField(default=datetime.date.today)
borrowed_item = models.ForeignKey(Issue,on_delete=models.CASCADE)
def new_issue(request):
if request.method == 'POST':
i_form = IssueForm(request.POST)
if i_form.is_valid():
name = i_form.cleaned_data['borrower_id']
book = i_form.cleaned_data['book_id']
i_form.save(commit=True)
books = Books.objects.get(book_name=book)#Get a book names as selected in the dropdown
semest = Student.objects.get(name=name).semester#Get a student with a semester as selected in the dropdown
departm = Student.objects.get(name=name).depart
Books.Claimbook(books)
return redirect('new_issue')
else:
i_form = IssueForm()
semest = None
departm = None
sem_book = Semester.objects.filter(sem=semest, depart=departm)
return render(request, 'libman/new_issue.html', {'i_form': i_form, 'sem_book': sem_book})
The return view
def return_book(request):
book = request.GET.get('book_pk')
print(book)
books = Books.objects.get(id=book)
#b_id = r_form.cleaned_data['borrower_id']
Books.Addbook(books)
Issue.objects.filter(borrower_id=1, id=book).delete()
return render(request,'libman/view_issue.html',{'issue':issue})
The template that displays the borrowed books with a link to return beside each book.
{% if issue %}
<table class="layout">
<thead>
<th>Reg No.</th>
<th>Student Name</th>
<th>Book Name</th>
<th>Issue Date</th>
<th>Action</th>
</thead>
{% for borrow in issue %}
<tr>
<td>{{ borrow.borrower_id.student_id }}</td>
<td>{{ borrow.borrower_id }}</td>
<td>{{ borrow.book_id }}</td>
<td>{{ borrow.issue_date }}</td>
<td name='book_pk'>Return </td>
</tr>
{% endfor %}
</table>
{% else %}
<p> There are no books registered. </p>
{% endif %}
Issue model
class Issue(models.Model):
borrower_id = models.ForeignKey(Student,on_delete=models.CASCADE)
book_id = models.ForeignKey(Books,on_delete=models.CASCADE)
issue_date = models.DateField(default=datetime.date.today)
def __str__(self):
return str(self.book_id)
if i understood correctly - I believe you need to pass the borrow.book_id to the return view. so the return view knows which book you want return
in your template add the variable book_pk as follows
<td name='book_pk'>Return </td>
also you need to update your urls.py file to accept the new variable something like this
urlpatterns = [
path('returnbook/<book_pk>/', return_book),
]
but the above will need to also update your view function to handle the new passed argument and fetch the object etc..
def return_book(request,book_pk):
Or
you can add a form with a submit button
<form action="{% url 'return_book' %}">
<label for="book_id">Borrowed Book_id</label>
<input type="text" id="book_id" name="book_pk" value="{{ borrow.book_id }}" disabled><br><br>
<input type="submit" value="Submit">
</form>
it should work with your current code i think

Print a project name in jinja template

I have the following models
AcsObject class
class AcsObjects(models.Model):
object_id = models.IntegerField(primary_key=True)
object_type = models.ForeignKey('AcsObjectTypes', db_column='object_type')
context = models.ForeignKey('self', blank=True, null=True)
security_inherit_p = models.BooleanField()
creation_user = models.IntegerField(blank=True, null=True)
Projects class
class ImProjects(models.Model):
project = models.ForeignKey('AcsObjects',related_name='project', on_delete=False, primary_key=True)
project_name = models.CharField(max_length=1000)
project_nr = models.CharField(max_length=100)
project_path = models.CharField(max_length=100)
TimesheetTasks class
class TimesheetTasks(models.Model):
task = models.ForeignKey('Projects', related_name='t_task', on_delete=False, primary_key=True)
uom = models.ForeignKey('Categories', related_name='u_uom', on_delete=False)
planned_units = models.FloatField(blank=True, null=True)
billable_units = models.FloatField(blank=True, null=True)
I wrote the following code into views.py file.
class TimesheetData(TemplateView):
template_name = 'timesheet.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["da"] = TimesheetTasks.objects.all()
return context
I want to print a project_name but it is giving me a task_id ( task_id and project_id are same) using jinja template.
timesheet.html
<body>
<p> {{da}} </p>
<table class="table table-light">
<thead class="thead-light">
<tr>
<th>Task </th>
</tr>
</thead>
<tbody>
{% for timesheet in da %}
<tr>
<td> {{timesheet.task}} </td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
It is giving me a blank output
Output
That's simply just because you're not access to product_name field yet.
<tbody>
{% for timesheet in da %}
<tr>
<td> {{timesheet.task}} </td>
</tr>
{% endfor %}
</tbody>
With this, Jinja just render the task id (project id), because Jinja think that you're not need any other information but just the foreign key value. So to be able to see the project_name, you should use this instead: timesheet.task.project_name, it does the job.
<tbody>
{% for timesheet in da %}
<tr>
<td> {{timesheet.task.project_name}} </td>
</tr>
{% endfor %}
</tbody>
Just want to mention that this could lead to another issue (performance issue) when Jinja have to query the data when render the template. To get rid of that, consider to use select_related which is an API of Django Queryset, check it out and gain some experiment that API, it really useful when using Django.

Class generic DeleteView not working for model related to model

I have a page containing assignment questions.
Questions related to assignment is displayed on asisgnment details page with EDIT and DELETE anchor tags.
But after pressing delete I get an error : Reverse for 'CreateQuestion' with arguments '('',)' not found. 1 pattern(s) tried: ['assignment/(?P[0-9]+)/createQuestion/$']
views.py
class AssignmentDelete(DeleteView):
model = Assignment
template_name = "dashboard/assignment_list.html"
success_url = reverse_lazy('ViewAssignment')
def get(self, request, *args, **kwargs):
return self.delete(request, *args, **kwargs)
class AssignmentDetailView(generic.DetailView):
model = Assignment
template_name = "dashboard/assignment_detail.html"
class QuestionDeleteView(DeleteView):
model = Question
template_name = 'dashboard/assignment_detail.html'
def get_success_url(self):
return reverse_lazy('assignment_detail', kwargs={'pk': self.object.assignment_id})
urls.py
path('<int:assignment_pk>/DeleteQuestion/<int:pk>/delete', views.QuestionDeleteView.as_view(), name='DeleteQuestion'),
path('<int:pk>/createQuestion/', views.QuestionCreate, name='CreateQuestion'),
path('assignment/<int:pk>', views.AssignmentDetailView.as_view(), name='assignment_detail'),
assignment_detail.html
{% extends "./base.html" %}
{% block content %}
<h1>Course:{{assignment.course }}</h1>
<p><strong>Assignment:</strong> {{ assignment.number }}</p>
<p><strong>publish_date:</strong> {{ assignment.publish_date }}</p>
<p><strong>deadline:</strong> {{assignment.deadline_date}}</p>
<div style="margin-left:20px;margin-top:20px">
<h4>Questions</h4>
<table class="table">
<thead class="thead-light">
<tr>
<th scope="col">Question Title</th>
<th scope="col">Question Marks</th>
<th scope="col">Edit Question</th>
<th scope="col">Delete Question</th>
</tr>
</thead>
<tbody>
{% for question in assignment.question_set.all %}
<tr>
<td>{{ question.title }}</td>
<td>{{ question.marks }}</td>
<td> Edit </td>
<td> <a onclick="return confirm('Are you sure?');" href="{% url 'DeleteQuestion' assignment_pk=assignment.id pk=question.id %}">Delete</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<a class=" btn btn-primary" href="{% url 'CreateQuestion' assignment.id %}">Add Question</a>
</div>
{% endblock %}
{% block script %}
{% endblock %}
Models.py
class Assignment(models.Model):
number = models.IntegerField()
course = models.ForeignKey(Course,on_delete = models.SET_NULL,blank=True,null=True)
publish_date = models.DateField(auto_now_add = True)
deadline_date = models.DateField()
faculty = models.ForeignKey(Faculty,on_delete = models.SET_NULL,blank=True,null=True)
def __str__(self):
return f'Assignment {self.number}-{self.course}'
def get_absolute_url(self):
"""Returns the url to access a detail record for this Assignment."""
return reverse('assignment-detail', args=[str(self.id)])
class Question(models.Model):
assignment = models.ForeignKey(Assignment, on_delete=models.SET_NULL,blank=True,null=True)
username = models.ForeignKey(User,on_delete=models.SET_NULL,blank=True,null=True)
title = models.CharField(max_length = 200)
description = models.TextField(blank=True , null = True)
marks = models.IntegerField(null=True)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
def get_absolute_url(self):
"""Returns the url to access a detail record for this book."""
return reverse('question-detail', args=[str(self.id)])
The Assignment detail page with questions associated with it
I did some changes to my code and added a get method and now its working as I wanted it to.
It would be great if someone point out any risk related it.Thank you all for your time in helping in my problem
here is the UPDATED code :
class QuestionDeleteView(DeleteView):
model = Question
template_name = "dashboard/assignment_detail.html"
self.object.assignment_id})
def get(self, request, *args, **kwargs):
return self.delete(request, *args, **kwargs)
def get_success_url(self):
return reverse_lazy('assignment_detail', kwargs={'pk': self.object.assignment_id})

Error during template rendering Reverse for 'group-edit' not found. 'group-edit' is not a valid view function or pattern name

I ve an error when loading 'group_list.html' :
Reverse for 'group-edit' not found. 'group-edit' is not a valid view function or pattern name.
If I supress this href reference, it works but I need this to be able to edit a group instance
this is my views.py for group_edit:
def group_edit(request, group_id):
group_form = GroupFormEdit(instance=Group.objects.get(id=group_id))
if request.method == "POST":
group_form = GroupForm(request.POST, instance=Group.objects.get(id=group_id))
if group_form.is_valid():
group_form.save()
messages.success(request, 'Group saved') # message for inform user of success - See messages in html file
return redirect('home')
else:
group_form = GroupForm()
return render(request, 'imports/group_edit.html', {
"group_form": group_form,
})
my group_list.html:
{% block page %}
<div class="panel-body">
<table class="table table-bordered table-hover table-striped col-md-3">
<thead class="thead-dark">
<tr class="text-center">
<th>Group Name</th>
<th>Parent Name</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<td scope="row" class="col-md-3">{{ group.group_name }}</td>
<td class="col-md-3">{{ group.groupParent_id }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
my urls.py:
urlpatterns = [
path('', views.imports_last, name='home'),
path('company_create/', views.company_create, name='company_creation'),
path('group_create/', views.group_create, name='group_creation'),
path('group_edit/', views.group_edit, name='group_edit'),
path('group_list/', views.group_list, name='group_list'),
]
and models.py:
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
groupParent_id = models.ForeignKey('self', blank=True, null=True, related_name='Parent', on_delete=models.CASCADE)
group_name = models.CharField(max_length=100, null=False, blank=False, unique=True)
def __str__(self):
return '{}'.format(self.group_name)
I find my pain point;
it is in the url
I should mention that I want to add a variable :
path('group_edit/<int:group_id>/', views.group_edit, name='group-edit'),

Using radio button control to select foreign key pointing to an item in nested inline formset

I have the following classes defined that essentially define a Node class. Each Node can have multiple NodeIntf's assigned to it. Each NodeIntf can have multiple NodeIntfIpaddr's assigned to it. One of those NodeIntfIpaddr's maybe assigned as the mgmt_ipaddr attribute on the Node object. And one of them maybe assigned to the mgmt_ipaddr_v6 attribute. Now in my template, I have essentially a nested table for the interfaces and I want to use a radio button selector to choose which of the ipaddrs is selected for the mgmt_ipaddr(_v6) attributes on the Node object, but I'm not quite sure how to do it. I think that, as I iterate over the ipaddr_formset, I have to check to see if that ipaddr represents the selected mgmt_ipaddr, but I'm not sure how to do that. Any help would be appreciated.
class Node(models.Model):
name = models.CharField(max_length=64, primary_key=True)
mgmt_ipaddr = models.ForeignKey('NodeIntfIpaddr', null=True, on_delete=models.SET_NULL)
mgmt_ipaddr_v6 = models.ForeignKey('NodeIntfIpaddr', null=True, on_delete=models.SET_NULL)
class NodeIntf(models.Model):
intf = models.CharField(max_length=32)
node = models.ForeignKey('Node', on_delete=models.CASCADE)
class Meta:
unique_together = ('node', 'intf')
class NodeIntfIpaddr(models.Model):
node_intf = models.ForeignKey('NodeIntf', on_delete=models.CASCADE)
ipaddr = InetAddressField()
class Meta:
unique_together = ('node_intf', 'ipaddr')
class NodeForm(ModelForm):
class Meta:
model = Node
class NodeIntfForm(ModelForm):
class Meta:
model = NodeIntf
class NodeIntfIpAddrForm(ModelForm):
class Meta:
model = NodeIntfIpaddr
NodeIntfIpaddrFormSet = modelformset_factory(NodeIntfIpaddr,
form=NodeIntfIpAddrForm, extra=0)
class BaseNodeIntfFormSet(BaseInlineFormSet):
def add_fields(self, form, index):
super(BaseNodeIntfFormSet, self).add_fields(form, index)
instance = self.get_queryset()[index]
pk_value = instance.pk
form.ipaddr_formset = NodeIntfIpaddrFormSet(
queryset=NodeIntfIpaddr.objects.filter(node_intf=pk_value),
prefix='INTF_%s' % pk_value)
NodeIntfFormSet = inlineformset_factory(Node, NodeIntf,
form=NodeIntfForm, formset=BaseNodeIntfFormSet, extra=0)
class NodeUpdateView(UpdateView):
form_class = NodeForm
model = Node
def get_context_data(self, **kwargs):
c = super(NodeUpdateView, self).get_context_data(**kwargs)
node = self.get_object()
c['action'] = reverse('node-update', kwargs={'pk': node.name})
if self.request.POST:
node_intfs = NodeIntfFormSet(self.request.POST, instance=node)
if node_intfs.is_valid():
addrs = node_intfs.save_all()
else:
node_intfs = NodeIntfFormSet(instance=node)
c['node_intfs_formset'] = node_intfs
return c
Template snippet:
<table class='node_intfs'>
<thead>
<tr class='node_intf'>
<th colspan='2'></th>
<th>Name</th>
<th></th>
</tr>
<tr class='node_intf_ipaddr'>
<th>IPv4 Mgmt<br><label><input type='radio' name='mgmt_ipaddr' value=''{{ node.mgmt_ipaddr|yesno:', checked' }}>None</label></th>
<th>IPv6 Mgmt<br><label><input type='radio' name='mgmt_ipaddr_v6' value=''{{ node.mgmt_ipaddr_v6|yesno:', checked' }}>None</label></th>
<th colspan='2'></th>
</tr>
</thead>
<tbody>
{% for node_intf_form in node_intfs_formset %}
<tr class='node_intf'>
<td colspan='2'></td>
<td>{{ node_intf_form.intf }}</td>
<td></td>
</tr>
{% if node_intf_form.ipaddr_formset %}
{% for ipaddr_form in node_intf_form.ipaddr_formset %}
<tr class='node_intf_ipaddr'>
<td>TODO</td> <---- These are what I can't figure out
<td>TODO</td> <---- These are what I can't figure out
<td></td>
<td>{{ ipaddr_form.ipaddr }}</td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>
I was able to do what I needed by using the following in my template:
<td class='center'><input type='radio' name='mgmt_ipaddr' value='{{ ipaddr_form.instance.id }}'{% if node.mgmt_ipaddr_id == ipaddr_form.instance.id %} checked='checked'{% endif %}</td>
<td class='center'><input type='radio' name='mgmt_ipaddr_v6' value='{{ ipaddr_form.instance.id }}'{% if node.mgmt_ipaddr_v6_id == ipaddr_form.instance.id %} checked='checked'{% endif %}</td>
This compares the mgmt_ipaddr(_v6)_id from the Node object with the id of the instance tied to the individual ipaddr forms, accessible as ipaddr_form.instance.id.
Just for completeness, I was also previously missing the management_form for each of the node_intf_forms and ipaddr_forms.