Pass OneToOne relationships to Django Templates - django

I am trying to setup a OneToOne relationship in Django in order to show data from TableA and TableB for a specific record.
I am having issues figuring out how to display it in my view, examples are out there but some seem a bit outdated or have solutions that I am not familiar with.
I have tried with some different calls in the views file as well as in my templates file without any luck, any input would be highly appreciated!
My models.py
from django.db import models
# Create your models here.
class tableA(models.Model):
created = models.DateTimeField(default=None)
published = models.CharField(max_length=50, default=None)
publisher = models.CharField(max_length=50, default=None)
code = models.CharField(max_length=25, null=True, unique=True)
class Meta:
db_table = 'tableA'
unique_together = (("publisher", "published"),)
def __str__(self):
return self.created
class tableB(models.Model):
tableA = models.OneToOneField(tableA, on_delete=models.CASCADE, primary_key=True, default=None)
code = models.CharField(max_length=50, default=None, null=True)
url = models.CharField(max_length=100, default=None, null=True)
class Meta:
managed = True
def __str__(self):
return self.tableA.code
My views.py
def nani(request):
data = TableA.objects.all()
return render(request, 'site/home.html', {'data':data})
My template
{% for test in data %}
<tr>
<td>{{ test.published }}</td>
<td>{{ test.publisher }}</td>
<td>{{ test.TableB.url }}</td>
</tr>
{% endfor %}

If the uppercase/lowercase letters are like you said, just do this, I just tested it.
views.py
from .models import tableA
def nani(request):
data = tableA.objects.all()
return render(request, 'site/home.html', {'data': data})
in your site/home.html :
{% for test in data %}
{{ test.published }}
{{ test.publisher }}
{{ test.tableb.url }}
{% endfor %}
and also something wrong about your str method. datetime is not a string format. so in your models.py, you have to fix this line like this:
def __str__(self):
return str(self.created)

Related

Display Todo under its category [Django]

I'm not sure how to ask this question but I'll give it a shot.
I am writing a Todo application and want to display each todo under its respective category in the template. For example
Display each category
{% for category in categories %}
<h2>{{ category.name }}</h2>
Now show each todo that falls under the above category
{% for todo in todos %}
<p>{{ todo.description }}</p>
{% endfor %}
{% endfor %}
How do I create a queryset that will give my this type of structure? Or is there are different way to achieve this?
If something is unclear or require more info let me know and I'll add it to the post
Any help is appreciated, thank you.
Models
class Category(models.Model):
name = models.CharField(max_length=20)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Todo(models.Model):
# Priority choices
PRIORITY_CHOICES = (
("bg-danger", "High"),
("bg-info", "Normal"),
("bg-warning", "Low"),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
description = models.CharField(max_length=255)
priority = models.CharField(max_length=200, choices=PRIORITY_CHOICES, null=True)
completed = models.BooleanField(default=False)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
category = models.ManyToManyField(Category)
def __str__(self):
return self.description
View
def todo_listview(request):
template_name = "todos/listview.html"
context = {
"todos": get_users_todos(user=request.user),
"categories": Category.objects.all(),
}
return render(request, template_name, context)
You can prefetch the user's Todos, with:
from django.db.models import Prefetch
def todo_listview(request):
template_name = 'todos/listview.html'
context = {
'categories': Category.objects.prefetch_related(
Prefetch('todo_set', queryset=get_users_todos(user=request.user), to_attr='user_todos')
)
}
return render(request, template_name, context)
and then render this with:
Display each category
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for todo in category.user_todos %}
<p>{{ todo.description }}</p>
{% endfor %}
{% endfor %}
Since there is a many-to-many field between Category and Todo, it is possible that the same Todo will be printed multiple times: once per category.
Note: The documentation advises to
use the AUTH_USER_MODEL setting [Django-doc] over
get_user_model() [Django-doc].
This is safer, since if the authentication app is not yet loaded, the settings
can still specify the name of the model. Therefore it is better to write:
from django.conf import settings
class Todo(models.Model):
# …
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)

How to show name instad of id in django ForeignKey?

I have a model with a ForeignKey to itself.
models.py
class Person(models.Model):
name = models.CharField(max_length=20)
important_name = models.ForeignKey('Person', on_delete=models.SET_NULL, blank=True, null=True, related_name='first', verbose_name='Very Important Name')
def __str__(self):
return self.name
def get_fields(self):
return [(field.verbose_name, field.value_from_object(self)) for field in self.__class__._meta.fields]
And when i want to show my data with DetailView CBV in view it show id instead of name.
views.py
class DetailPerson(DetailView):
model = Person
template_name = 'panel/detail_person.html'
detail_person.html
<table class="table">
{% for label, value in object.get_fields %}
<tr>
<td>{{ label }}</td>
<td>{{ value }}</td>
</tr>
{% endfor %}
</table>
How can i show name instead of id?
Here we can use getattr instead of value_from_object, which will return us the related instance of Person instead of an ID.
def get_fields(self):
return [(field.verbose_name, getattr(self, field.name)) for field in self.__class__._meta.fields]
example:
from base.models import Person
a = Person.objects.first()
a.get_fields()
Returns
[('ID', 1), ('name', 'Joe'), ('Very Important Name', <Person: Bob>)]
Now, we may access all of Bob's attributes in the template as well, if the need arose.

how to get data from another table which have foreign key relation with user table django?

I have three tables user, Profile and booking. Profile and booking table have foreign key with user table. Profile and Booking table are not directly linked. In BookingList view i want to access the profile data is it possible if yes how i can i do this.
models.py
class Profile(models.Model):
uid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4)
name = models.CharField(max_length=100, unique=True)
contact_person = models.CharField(max_length=100)
mobile = models.CharField(max_length=15)
email = models.CharField(max_length=40)
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
profile_status = models.BooleanField(default=False)
def __str__(self):
return self.name
class Booking(models.Model):
port_of_loading = models.ForeignKey(LoadPort, on_delete=models.PROTECT)
port_of_discharge = models.ForeignKey(DestinationPort, on_delete=models.PROTECT)
equipment_type = models.CharField(max_length=10, choices=CONT_TYP)
quantity = models.IntegerField()
pick_up_date = models.DateField(null=True, blank=True)
hand_over_date = models.DateField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
def __str__(self):
return self.port_of_loading
views.py
class BookingList(LoginRequiredMixin, ListView):
model = Booking
template_name = 'documentation/details_booking.html'
context_object_name = 'all_bk'
def get_queryset(self):
queryset = super(BookingList, self).get_queryset().order_by('-pk')
return queryset
In template i want to access the profile.name
{% for item in all_bk %}
<tr>
<td>{{ item.created_by.profile.name }}</td>
</tr>
{% endfor %}
There can be multiple profiles created by a user so you will have to loop over them
{% for item in all_bk %}
{% for profile in item.created_by.profile_set.all %}
{{ profile.name }}
{% endfor %}
{% endfor %}

Create a string that contains values from related objects to display in view

I'm new to Django so please bear with me. I'm trying to create a view which lists JournalEntries which have type=BP. The list needs to include selected values from the LineItems that are related to each JournalEntry. Each JournalEntry with type=BP only ever has two related LineItems.
models.py
class JournalEntry(models.Model):
date = models.DateField(null=True, blank=False)
TYPE = (
('BP', 'Bank Payment'),
('YE', 'Year End'),
)
type = models.CharField(
max_length=2,
choices=TYPE,
blank=True,
default='0'
)
class LineItem(models.Model):
journal_entry = models.ForeignKey(JournalEntry, on_delete=models.PROTECT)
ledger = models.ForeignKey(Ledger, on_delete=models.PROTECT)
description = models.CharField(max_length=255, null=True, blank=True)
cr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
dr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
class Ledger(models.Model):
name = models.CharField(max_length=255)
views.py
def journalentries_show_all(request):
journal_entries = JournalEntry.objects.filter(type="BP")
context = {
'journal_entries': journal_entries,
}
return render(request, 'journal/journalentries_show_all.html', context)
My template journalentries_show_all.html
<ul>
{% for journal_entry in journal_entries %}
<li>{{ journal_entry.date }}</li>
<li>{{ ledger name from first line item in this journal_entry }}</li>
<li>{{ ledger name from second line item in this journal_entry }}</li>
<li>{{ description from first line item in this journal_entry }}</li>
<li>{{ description from second line item in this journal_entry }}</li>
{% endfor %}
</ul>
In this particular view I'm only interested in displaying JournalEntries which has type=BP, all of which only ever have two line items. Other types of JournalEntries have more LineItems, but those are dealt with in another view.
Basic Python iteration is enough for what your need
results = []
for entry in journal_entries:
results.append(entry.lineitem_set.all()[2]
Just that results list should do it in the context. .all()[2] will send a query with a limit for the first 2 items. You will get the whole items. Select what you need to display in the template, not the views.
To make your life easier, you can also define a related_name attribute on foreign keys and use the name you want there instead of the generated *_set
Why do you want to pass the information as a string? It's an extra step that doesn't add anything. You can pass in entire dictionaries as the context variable so that's what I'd recommend you do. In your view, it is possible to request rows based off of a filter as seen in the docs here. Then you can pass the data from the query into the template as a dictionary.
Also why does your JournalEntry model only have one field? Can we just combine the JournalEntry and LineItem into something like this:
class LineItem(models.Model):
date = models.DateField(null=True, blank=False)
# journal_entry = models.ForeignKey(JournalEntry, on_delete=models.PROTECT)
# this journal_entry fk wouldn't work so you'd have to replace it with something else
ledger = models.ForeignKey(Ledger, on_delete=models.PROTECT)
description = models.CharField(max_length=255, null=True, blank=True)
cr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
dr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
Then for the view I would write something like this:
views.py
from .models import LineItem
def journalentries_show_all(request):
context = LineItem.objects.filter(arbitrary_criteria = True) # choose your own criteria here
return render(request, 'journal/journalentries_show_all.html', context)
The important part would be choosing the filter. If you want to do the first two by date you can follow the example here.
Maybe I understood you wrong but why don't you just send your JournalEntry querset to your template?
def journalentries_show_all(request):
context['journal_entries'] = JournalEntry.objects.all()
....
Then you can display what you want in your template
{% for entry in journal_entries %}
{{ entry.id }} {{ entry.date }}
{% for item in entry.lineitem_set.all|slice:"2" %}
{{ item.ledger.name }}
{% endfor %}
{% endfor %}
After some digging I found that I can access related variables direct in the template as follows:
<td>{{ journal_entry.date }}</td>
<td>{{ journal_entry.lineitem_set.all.1.ledger }}</td>
<td>{{ journal_entry.lineitem_set.all.0.ledger }}</td>
<td>{{ journal_entry.lineitem_set.all.1.description|truncatechars:15 }}</td>
<td>{{ journal_entry.lineitem_set.all.0.description|truncatechars:15 }}</td>

foriegn key object not iterable in template

I have basic models for a section, subsection and clause. 1 section can hold multiple subsections. Each subsection can hold multiple clauses. The models look like:
**models.py**
class Clause(models.Model):
number = models.CharField(max_length=8, unique=True)
requirements = models.TextField(max_length=2000, unique=False, blank=True, null=True)
documentation = models.TextField(max_length=2000, unique=False, blank=True, null=True)
class Subsection(models.Model):
number = models.CharField(max_length=5, unique=True)
name = models.CharField(max_length=150, unique=False)
descriptor = models.TextField(max_length=2000, unique=False, blank=True, null=True)
clause = models.ForeignKey(Clause, on_delete=models.DO_NOTHING, related_name="clause")
class Section(models.Model):
number = models.CharField(max_length=2, unique=True)
name = models.CharField(max_length=150, unique=False)
descriptor = models.TextField(max_length=2000, unique=False, blank=True, null=True)
subsection = models.ForeignKey(Subsection, on_delete=models.DO_NOTHING, related_name="subsection")
basic view function to call the desired section:
**views.py**
def main(request):
form = MainSearchForm()
user = request.user
sections = []
show_results = True
if 'query' in request.GET:
show_results = True
query = request.GET['query'].strip()
if len(query) <= 2:
sections = Section.objects.filter(number__iexact=query)
if sections:
records = sections
tpl = "display_console.html"
context = {'user': user, 'records': records, 'form': form}
return render(request, tpl, context)
else:
tpl = "main.html"
context = {'user': user, 'form': form}
return render(request, tpl, context)
unfortunately, I can't get my template to return my subsection data. The following returns a 'Subsection' object is not iterable error:
**template**
<table class="section_tb">
{% if records %}
{% for record in records %}
<tr>
<td>{{ record.number }}</td><td>{{ record.name }}</td>
</tr>
{% for item in record.subsection %}
<tr>
<td>{{ item.number }}</td><td>{{ item.name }}</td>
</tr>
<tr>
<td colspan=2>{{ item.descriptor }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
{% else %}
{% endif %}
substituting:
{% for item in record.subsection.all %}
for:
{% for item in record.subsection %}
removes the error message, but doesn't return any data. Is there something obvious I'm doing wrong?
This is because Section can have only one Subsection.
So you can access the subsection with just {{record.subsection}} so no forloop needed here.
As a tip remember when you usea one to many, the one is where the foreign key is defined.
The model that store the foreign key will always store only one foreign key.
If you want to access the many foreign keys from the other side use the model_name_in_lowercase_set or define a related name in models.ForeignKey(..., related_name="something") then you can call something_set