Include Object and Object's Foreign Keys in One Query Django - python

I have the following models:
class Document(models.Model):
name = models.CharField(max_length=30, null=True, blank=True)
reference = models.CharField(max_length=30, null=True, blank=True)
def __str__(self):
return self.Name
class Subdocument(models.Model)
document = models.ForeignKey(Document, null=True, default=None)
pdf = models.FileField(upload_to='media')
Ultimately I want to show both the name from Document and the pdf from Subdocument in the same <li> in my template within a for loop. So it could be something like:
{% for item in something %}
<li class="list-group-item">
{{ item.Name }} {{ item.pdf }}
</li>
{% endfor %}
My issue is because they are in separate models, I'm not sure how to get fields from both. So what query, or queries could I run in my view in order to make this possible? Any other approach is welcome, this is just to illustrate my end goal.
Thank you!
EDIT:
views.py
def doc_view(request):
something = Subdocument.objects.filter(document__isnull=False)
return render(request, 'my_template.html', context={'something': something})

Have you tried something like this,
# views.py
def my_view(request):
docs = Subdocument.objects.filter(document__isnull=False) # filtering out empty documents
return render(request, 'my_template.html', context={'docs': docs})
# my_template.html
{% for doc in docs %}
<li class="list-group-item">
{{ doc.document.name }} {{ doc.pdf.url }}
</li>
{% endfor %}

Try this
models.py
replace
name = models.CharField(max_length=30, null=True, blank=True)
to
name = models.CharField(max_length=30, null=True, blank=False)
template
{% for item in something %}
<li class="list-group-item">
{{ item.document.name }} {{ item.pdf }}
</li>
{% endfor %}

Related

How do I access the data from inside a nested for loop

I want to do something like below in html where multiple "spots" are displayed, and within each spot the "links" associated to each specific spot is displayed.
How would I write the logic to display the specific links for each spot?
html
{% for spot in spots %}
<div>
<h2>{{ spot.title }}</h2>
</div>
{% for link in links %}
<div>
<h3>{{ link.url }}</h3>
</div>
{% endfor %}
{% endfor %}
My models are as below. SpotLinks is the intermediate table for Links and Spots table.
models.py
class Spots(models.Model):
title = models.CharField(max_length=155)
slug = models.SlugField(unique=True, max_length=155)
class Links(models.Model):
title = models.CharField(unique=True, max_length=155, blank=True)
url = models.CharField(max_length=75, blank=True)
class SpotLinks(models.Model):
link = models.ForeignKey('Links', models.DO_NOTHING)
spot = models.ForeignKey('Spots', models.DO_NOTHING)
class Articles(models.Model):
title = models.CharField(max_length=155)
slug = models.SlugField(unique=True, max_length=155)
summary = models.TextField(blank=True, null=True)
class ArticleSpots(models.Model):
article = models.ForeignKey('Articles', models.DO_NOTHING)
spot = models.ForeignKey('Spots', models.DO_NOTHING)
I tried links = Links.objects.filter(spotlinks__spot=spots) in views.py but because spots has multiple spots in it it doesn't get filtered.
Will the logic be written in the views.py or as django templates in the html file?
Im new to web development so any direction would help. Thanks!
views.py
def article(request, slug):
article = get_object_or_404(Articles, slug=slug)
spots = Spots.objects.filter(articlespots__article=article).distinct()
links = Links.objects.filter(spotlinks__spot=spots)
context = {
'spots': spots,
'article': article,
'links': links}
return render(request, 'articletemplate.html', context)
To access the related objects, use the related manager.
In this case, the related manager is spot.spotlinks_set.
{% for spot in spots %}
<div>
<h2>{{ spot.title }}</h2>
</div>
<!-- {% for link in links %} --> <!-- Replace this -->
{% for spotlink in spot.spotlinks_set.all %} <!-- with this -->
<div>
<!-- <h3>{{ link.url }}</h3> --> <!-- Replace this -->
<h3>{{ spotlink.link.url }}</h3> <!-- with this -->
</div>
{% endfor %}
{% endfor %}
Reference: https://docs.djangoproject.com/en/3.2/ref/models/relations/
You need to add one foreign field to Links model to reference spot, so Links model will be:
class Links(models.Model):
title = models.CharField(unique=True, max_length=155, blank=True)
url = models.CharField(max_length=75, blank=True)
spot = models.ForeignKey(Spots, on_delete=models.CASCADE, related_name="links")
thereby, you can get the links for each spots by:
from django.shortcuts import get_object_or_404
spot = get_object_or_404(Spots, title="choose the the title") # you can filter it in your preferred way
links = spot.links.all()
Then, in context; you don't need to send links at all, instead you can iterate in html in this way:
{% for spot in spots %}
<div>
<h2>{{ spot.title }}</h2>
</div>
{% for link in spot.links %}
<div>
<h3>{{ link.url }}</h3>
</div>
{% endfor %}
{% endfor %}

Django View Problem. Filtered Tickets Are Not Appearing

I'm currently working on a project in Django that is a "bug tracker" or "ticket tracker" as some might call it. The goal here is to create a post or "ticket" that details a bug in the website or software for a development team.
Each "ticket" has general information like name, summary, etc. but also has a "category" for the software languages or bug type(Think like categories for a blog). Every ticket also has a "priority", that is developed in a similar way as to the categories, based on the severity of the bug that a reporter encounters.
I have already developed a way to click on a category name and view a list of tickets within the same category. This is successful and it works great! Naturally, my next step in the process is to use that same method of implementing ticket priorities. My goal is to be able to click on a priority and see a filtered view of all "severe" tickets with that priority, just like how my categories are set up.
Here is my problem:
When I click on a priority (low, medium, high, & severe), it will take me to my ticket_priority.html template for that particular priority, but does not filter or show any ticket of that priority when there is in fact ticket with that priority. All I'm trying to do is to take that same methodology of building out "categories" but implementing them as "priorities" for the team to filter out based on the severity of the bug.
I think there is something wrong with my ticket_priority view, but I just don't know what the deal is and need extra eyes.
First here is my models:
from django.db import models
from django.utils.timezone import timezone
from datetime import datetime
# Create your models here.
#Priority
class Priority(models.Model):
name = models.CharField(max_length=20,null=True)
def __str__(self):
return self.name
#Category
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
#TICKET
class Ticket(models.Model):
#BugID
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100, blank=True, null=True)
reporter = models.CharField(max_length=100, blank=True, null=True)
created_on = models.DateTimeField(auto_now_add=True, blank=True, null=True)
last_modified = models.DateTimeField(auto_now=True)
#BugOverview
summary = models.TextField(blank=True, null=True)
url = models.URLField(blank=True, null=True)
image = models.ImageField(upload_to='media/images/', blank=True, null=True)
#BugEnvironment
platform = models.CharField(max_length=20, blank=True, null=True)
operating_system = models.CharField(max_length=20, blank=True, null=True)
browser = models.CharField(max_length=20, blank=True, null=True)
categories = models.ManyToManyField('Category', related_name='posts')
#BugDetails
steps_to_reproduce = models.TextField(blank=True, null=True)
expected_result = models.CharField(max_length=100, blank=True, null=True)
actual_result = models.CharField(max_length=100, blank=True, null=True)
#BugTracking
priorities = models.ManyToManyField('Priority', related_name='posts')
assigned_to = models.CharField(max_length=100, blank=True, null=True)
completed = models.BooleanField(db_column='Completed', default=False)
datecompletion = models.DateTimeField(db_column='DateCompletion', blank=True, null=True)
def set_completion(self):
self.completed = True
self.datecompletion = datetime.now()
self.save()
def __str__(self):
return self.title
Next up is my views.py for ticket_category & ticket_priority:
# TICKET CATEGORY INDEX
#login_required(login_url='/accounts/login/')
def ticket_category(request, category):
tickets = Ticket.objects.filter(
categories__name__contains = category
)
context = {
"category": category,
"tickets": tickets
}
return render(request, 'ticket_category.html', context)
#################################################################3
# TICKET PRIORITY INDEX
#login_required(login_url='/accounts/login/')
def ticket_priority(request, priority):
tickets = Ticket.objects.filter(
priorities__name__contains = priority
)
context = {
"priority": priority,
"tickets": tickets
}
return render(request, 'ticket_priority.html', context)
And here is my ticket_category.html template:
{% extends "base.html" %}
{% load static %}
{% block page_content %}
<div class = "container">
<div class = "row">
<!-- Post Content Column -->
<div class="col-lg-8">
<h1> {{ category | title }} </h1>
{% for ticket in tickets %}
<div class="card">
{% for priority in ticket.priorities.all %}
<div class="card-header">
Ticket #{{ ticket.id}} |
<a href="{% url 'ticket_priority' priority.name %}">
{{ priority.name }}
</a>
</div>
{% endfor %}
<div class="card-body">
<h5 class="card-title">{{ ticket.title }}</h5>
<p class="card-text">{{ ticket.summary|truncatewords:20 }}</p>
<p class="card-text"> Categories:
{% for category in ticket.categories.all %}
<a href="{% url 'ticket_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</p>
View Ticket
Edit Ticket
Ticket Completed
Delete Ticket
</div>
</div>
<br>
{% endfor %}
</div><!-- Column -->
{% include "sidebar.html" %}
</div> <!-- Row -->
</div><!-- Container-->
{% endblock %}
And here is my ticket_priority.html template:
{% extends "base.html" %}
{% load static %}
{% block page_content %}
<div class = "container">
<div class = "row">
<!-- Post Content Column -->
<div class="col-lg-8">
<h1> {{ priority | title }} </h1>
{% for ticket in tickets %}
<div class="card">
{% for priority in ticket.priorities.all %}
<div class="card-header">
Ticket #{{ ticket.id}} |
<a href="{% url 'ticket_priority' priority.name %}">
{{ priority.name }}
</a>
</div>
{% endfor %}
<div class="card-body">
<h5 class="card-title">{{ ticket.title }}</h5>
<p class="card-text">{{ ticket.summary|truncatewords:20 }}</p>
<p class="card-text"> Categories:
{% for category in ticket.categories.all %}
<a href="{% url 'ticket_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</p>
View Ticket
Edit Ticket
Ticket Completed
Delete Ticket
</div>
</div>
<br>
{% endfor %}
</div><!-- Column -->
{% include "sidebar.html" %}
</div> <!-- Row -->
</div><!-- Container-->
{% endblock %}
When the ticket_priority.html template renders, everything appears (base.html, sidebar, priority title, etc) - but no tickets appear - the makes me think that its a problem with my view.
Been stuck on this for over a day. No errors are thrown, just no tickets appear for any priority. They DO appear for each category though. Any help or a point in the right direction would be great. Thank you!
I actually ended up figuring it out on my own and the answer was, naturally, pretty simple.
There wasn't a problem with my model or views, it was my urls. The order of your URL paths DOES matter - though I'm not sure how that works.
Before the fix, my "priority" was routing to my "category" and rendering that view instead.
path("<category>/", views.ticket_category, name="ticket_category"),
path("<priority>/", views.ticket_priority, name="ticket_priority"),
Basically my urls were out of order. I simply moved the priority url above category like so.
path("<priority>/", views.ticket_priority, name="ticket_priority"),
path("<category>/", views.ticket_category, name="ticket_category"),
Now when I click on a link that leads to the priority it displays everything in the particular priority group.
Still not sure what caused it to fix, but its works.

if statement in Django template not working

I can't find out why this is not working.
It always goes to {% else %} block.
The text in machine_model is something like "Lidl - Food Market" or "Kaufland - Buy Here" or something other without those two words.
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django import forms
from django.urls import reverse
class MyName(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class MyModel(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class MySide(models.Model):
name = models.CharField(max_length=50, unique=True)
class MyMachine(models.Model):
date_delivery = models.DateTimeField(null=True)
machine_name = models.ForeignKey(MyName, on_delete=models.PROTECT)
machine_model = models.ForeignKey(MyModel, on_delete=models.PROTECT)
machine_serial = models.CharField(max_length=15, default='0')
use_side = models.ForeignKey(MySide, on_delete=models.PROTECT)
views.py
from django.views.generic import ListView
from .models import MyMachine
class MyMachineListView(ListView):
model = MyMachine
template_name = 'site/home.html'
context_object_name = 'machines'
ordering = ['date_delivery']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
site_title = 'Home'
context["site_title"] = site_title
return context
home.html
{% extends "site/base.html" %}
{% load static %}
{% block content %}
{% for machine in machines %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<small class="text-muted">{{ machine.date_delivery|date:"d.F Y" }}
</small>
</div>
<h2><a class="article-title" href="">{{ machine.machine_name }} - {{ machine.machine_serial }}</a></h2>
{% if 'Lidl' in machines.machine_model %}
<p class="article-content">{{ machine.use_side }} - Lidl</p>
{% elif 'Kaufland' in machines.machine_model %}
<p class="article-content">{{ machine.use_side }} - Kaufland</p>
{% else %}
<p class="article-content">{{ machine.use_side }} - {{ machine.machine_model}}</p>
{% endif %}
</div>
</article>
{% endfor %}
{% endblock content %}
everything else is working fine. Thank You in advance!
I see two problems here.
One, you're referencing machines.machine_model, but machines is a queryset. I'm somewhat surprised referencing machine_model on it doesn't just fail with a rendering error. It should be machine.machine_model, since that's your loop variable.
That leads us to the second problem. machine.machine_model is a foreign key reference to another model, not a string. There's no string that's in a model instance (barring defining the membership function yourself). I haven't personally tested but I don't think Django stringifies on the fly (as it will when you reference {{ machine.machine_model }}). Try it with if ... in machine.machine_model.name.

List of model fields with missing values nicely formatted in Django template

I'm trying to make a view in Django to list each entry in a model and any of the fields that are missing values. The template is a table: one column is a specific field and the other column is a list of the fields with missing values. I have a working version, but the missing fields are just strung together, and I'd like to have them nicely formatted with commas in between.
#models.py
class exif(models.Model):
image = models.ForeignKey('image', on_delete=models.CASCADE, blank=False, null=False)
filename = models.CharField(max_length=100, blank=True, null=True)
artist = models.CharField(max_length=100, blank=True, null=True)
copyright = models.CharField(max_length=100, blank=True, null=True)
keywords = models.CharField(max_length=100, blank=True, null=True)
caption = models.CharField(max_length=100, blank=True, null=True)
comment = models.CharField(max_length=100, blank=True, null=True)
...
#views.py
def exif_export(request):
exif_records = serializers.serialize("python", exif.objects.all())
return render(request, 'exif_export.html', {'exif_records': exif_records})
#exif_export.html
<table>
<tr>
<th>File</th>
<th>Missing Exif Fields</th>
</tr>
{% for record in exif_records %}
<tr>
<td>
{% for field, value in record.fields.items %}
{% if field == 'filename' %}
{{ value }}
{% endif %}
{% endfor %}
</td>
<td>
{% for field, value in record.fields.items %}
{% if not value %}
{{ field }}, <!-- This comma makes a trailing comma at the end of the list -->
{% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
Is there a good way to format those fields into a nice list? Right now it'll look like:
artist, comment,
Whereas it'd be nice if it looked like:
artist, comment
Or even better:
Artist, Comment
Do I have to make a dictionary or something in the view and pass that to the template? Or is there a way to make a list of fields missing values in Django and/or Python in general? It'd be nice if the template could just handle it, I just can't think of any other way.
You can do {{ field|capfirst }} for capitalizing the first letter, to remove the trailing comma you could do something like
{% for field, value in record.fields.items %}
{% if not value and field != last_field %}
{{ field|capfirst }},
{% endif %}
{% endfor %}
{{ last_feild|capfirst }}
and pass last_field in somewhere (probably in the model).
Alternatly, you could write a templatetag to do this for you.

django regroup templatetag does not group properly

I have following template
{% regroup product.hotel.facilities.all by facilitytype as facilities %}
{% for facility in facilities %}
<h5>{{ facility.grouper }}</h5>
<p class="tab-content-title bld">
{% for i in facility.list %}
<li>{{ i }}</li>
{% endfor %}
{% endfor %}
And following model structure:
class Hotel(TranslatableModel):
code = models.CharField(max_length=255)
facilities = models.ManyToManyField('hotels.Facility',null=True)
class Facility(TranslatableModel):
code = models.CharField(max_length=255, unique=True)
facilitytype = models.ForeignKey(FacilityType, null=True, blank=True)
translations = TranslatedFields(
name=models.CharField(max_length=255, blank=True),
)
But when I run the page i see below. Instead I want to see the list grouped and distinct by facility_types:
Any ideas?
You have to sort your data by the grouper field first.

Categories

Resources