List of child ID in django template - django

Here is my models.py:
#child
class Country(models.Model):
name = models.CharField(max_length=255)
wine_rg = models.ManyToManyField(WineRegion, blank=True)
#parent
class WorldRegion(models.Model):
name = models.CharField(max_length=255)
country = models.ManyToManyField(Country, blank=True)
def __str__(self):
return self.name
views.py:
world_region_filters = WorldRegion.objects.all()
templates/test.html:
{% for world_region in world_region_filters %}
{{ world_region.name }} - {{ return list of country ID }}
{% endfor %}
How to return all country ID (child) on django template? I know I can do this:
{% for country in world_region.country.all %} {{ country.id }} {% endfor %}
But is there any way to make it shorter? I've tried this:
{{ world_region.country.all.id }}
But it doesn't work. Any suggestions?

i dont know why you want a list of ids in html
whatever you've implemented is fine still if you want list of ids maybe you can do like this:
data = WorldRegion.objects.all().values("name", "country_id")
region_names = [ i['name'] for i in data ]
country_ids = [ i['country_id'] for i in data ]
then you can pass it to html as a context

If you are using PostgresSQL, then you can use ArrayAgg like this:
from django.contrib.postgres.aggregates.general import ArrayAgg
from django.db.models import Count
world_region_filters = WorldRegion.objects.all().annotate(
country_list=ArrayAgg('country', distinct=True),
)

Related

How to iterate in subitems of a object in a django template

views.py:
from django.views import generic
from .models import Servico
class ServicoView(generic.DetailView):
model = Servico
context_object_name = 'servico'
template_name = 'servico.html'
models.py:
from djongo import models
class PublicoAlvo(models.Model):
def __str__(self):
return ''
alvo1 = models.CharField(max_length = 126)
alvo2 = models.CharField(max_length = 126, blank = True, default = '')
class Meta:
abstract = True
class Servico(models.Model):
t_id = models.CharField(primary_key = True, unique = True, max_length = 252)
alvos = models.EmbeddedField(
model_container = PublicoAlvo
)
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('servicos/<slug:pk>/', views.ServicoView.as_view(), name = 'servico')
]
I think these are the relevant files in my Django app folder. Back to the question, how can I iterate over the values that are going to be stored in servico.alvos in my template? If I want to show t_id, I just use {{ servico.t_id }} and it works fine. I could write something like:
<HTML1>
{{ servico.alvos.alvo1 }}
<HTML2>
<HTML1>
{{ servico.alvos.alvo2 }}
<HTML2>
And that would show the values that I want, but would make things uglier, since I would have to write a lot of repeated standard HTML (that I indicated as and ) to format each value inside servico.alvos, and more limited (imagine if I decide to change the model and add more 6 values in the PublicoAlvo class). I tried the following:
{% for alvo in servico.alvos.all %}
<HTML1>
{{ alvo }}
<HTML2>
{% endfor %}
and
{% for alvo in servico.alvos.items %}
<HTML1>
{{ alvo }}
<HTML2>
{% endfor %}
But I get nothing printed. When I try:
{% for alvo in servico.alvos %}
<HTML1>
{{ alvo }}
<HTML2>
{% endfor %}
I get 'PublicoAlvo' object is not iterable
Is there a way to get what I want using a loop in my template or changing something in my models.py?
Try
{{ servico.t_id }}
{{ servico.alvos }}
Then in your models.py
class PublicoAlvo(models.Model):
def __str__(self):
# Option 1: List all <alvo> fields
return ", ".join(
[
self.alvo1,
self.alvo2,
]
)
# Option 2: If you don't like manually listing each <alvo> field
# return ", ".join(
# [
# getattr(self, f"alvo{index}") for index in range(1, 3)
# ]
# )
...
This might give something like
The value for alvo1, While for alvo2 is this one
Update
You could also try
{% for key, value in servico.alvos.items %}
{% if key|slice:":4" == "alvo" %}
{{ value }}<br>
{% endif %}
{% endfor %}
This might show something like
The value for alvo1
While for alvo2 is this one
Based on the first answer of Niel Godfrey Ponciano, I was able to solve the problem.
models.py:
from djongo import models
class PublicoAlvo(models.Model):
def __str__(self):
return ''
def list(self):
return [value for key, value in self.__dict__.items() if not key.startswith('_')]
alvo1 = models.CharField(max_length = 126)
alvo2 = models.CharField(max_length = 126, blank = True, default = '')
class Meta:
abstract = True
class Servico(models.Model):
t_id = models.CharField(primary_key = True, unique = True, max_length = 252)
alvos = models.EmbeddedField(
model_container = PublicoAlvo
)
And then I can iterate over servico.alvos.list using a for in the template just by adding the list method that returns the relevant fields (variables) values in my class.

Queryset only allowing me to SELECT just one tables fields in a join

I have two tables, but am just trying to get just the dNm from T table (while joining), but instead I can only pull fields from TSF.
I have models file:
models.py
class T(models.Model):
emailVerified = models.EmailField(max_length=50)
dNm = models.CharField(max_length=40,unique=True)
FKToUser = models.ForeignKey('auth.user', default=None, on_delete=models.PROTECT)
class TSF(models.Model):
httpResponse = models.IntegerField(validators=[MaxValueValidator(3)])
FKToT = models.ForeignKey('T', on_delete=models.PROTECT)
In regular (pseudo) sql I'm trying to do something like:
SELECT dNm
FROM T, TSF
WHERE T.id=TSF.FKToT
AND T.FKToUser=<<THE CURRENTLY SIGNED IN USER>>
However, its only allowing me to do the following in pseudo sql:
SELECT <any field from TSF>
FROM T, TSF
WHERE T.id=TSF.FKToT
AND T.FKToUser=<<THE CURRENTLY SIGNED IN USER>>
My views.py:
def viewed(request):
AUS = TSF.objects.filter(FKToTld__FKToUser=request.user).values('dNm')
return render(request, 'file.html', {
'ATFS':ATFSs
})
Outputting in template
{{ t.dNm }}
UPDATE This is now not throwing an error on page, but sending a bunch of blanks.
What am I doing wrong here?
values() returns a Queryset of dictionaries. you can check here for more info.
You can do something like this:
views.py
AUS = TSF.objects.filter(FKToTld__FKToUser=request.user).values('FKToTld__dNm').disctinct()
template.html
{% for key, value in ATFS.items %}
{{ key }}: {{ value }}
{% endfor %}

custom url patterns in Django

I have a website I am trying to build for personal use, and it possesses two id's one for a meeting (where the race is run) and one for the event (the race number). The event id is in the form of "123456_01" and is passed in the model as a primary key for the Event model, as seen below...
class Event(models.Model):
meeting = models.CharField(max_length=500)
meetingID = models.ForeignKey(Meeting, on_delete='CASCADE', related_name='races')
eventID = models.CharField(max_length=300, primary_key=True)
venue = models.CharField(max_length=600, null=True)
race_no = models.CharField(max_length=2)
event_time = models.TimeField()
status = models.CharField(max_length=100)
distance = models.CharField(max_length=600)
I currently have the views file set up as follows:
class EventDetailView(DetailView,LoginRequiredMixin):
context_object_name = 'race_detail'
template_name = 'event.html'
model = models.Event
slug_url_kwarg = 'eventID'
I also have my front end set up so that at present when I click on a certain race, it automatically navigates to the page with the link http://127.0.0.1:8000/app/123456_01/, so that part is working through this config in the HTML:
{% url 'bettingUI:race' eventID=events.eventID %}
the problem I seem to be having is with the configuration of the urls.py file and possibly something I am missing in the views.py file.
my urls.py file is set up as follows :
from django.urls import path, include
from . import views
app_name = 'bettingUI'
urlpatterns = [
path('',views.DashListView.as_view(),name='dashboard'),
path('<eventID>/', views.EventDetailView.as_view(), name='race'),
]
I thought from reading the docs that I need to use a slug because of the '_' character in the ID I am passing in but I am constantly getting an error in the browser stating that it can not resolve keyword 'slug' into the field. Choices are: dro_eventID, dro_meetingID, dro_meetingID_id, event_time, meeting, race_no, runners, status, venue ( **the fields of the model). If I change the urls.py file to the below, I get the same error:
path('<slug:eventID>/', views.EventDetailView.as_view(), name='race'),
I am a bit lost here so would love some guidance.
Thank you.
I worked it out, the answer is to input <slug:pk>
but now I am getting an error at my dashpage (the page i land at to click through to the race page):
NoReverseMatch at /app/
Reverse for 'race' with keyword arguments '{'eventID': '1216859_01'}' not found. 1 pattern(s) tried: ['app/(?P<pk>[-a-zA-Z0-9_]+)/$']
So I give it again now the working version:
First you should add a slug field to your Event Model and this will let you use slug, so your model will look like this:
from django.utils.text import slugify
class Event(models.Model):
meeting = models.CharField(max_length=500)
meetingID = models.ForeignKey(Meeting, on_delete='CASCADE', related_name='races')
eventID = models.CharField(max_length=300, primary_key=True)
venue = models.CharField(max_length=600, null=True)
race_no = models.CharField(max_length=2)
event_time = models.TimeField(null=True)
status = models.CharField(max_length=100, null=True)
distance = models.CharField(max_length=600, null=True)
slug = models.SlugField(max_length=50, null=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.eventID, allow_unicode=True)
return super(Event, self).save(*args, **kwargs)
Notice the save() function and in that we added a slugify() method to slugify the eventID field at event savings.
Then your views should look like these:
from .models import Event, Meeting
class EventList(ListView):
model = Event
template_name = 'event_list.html'
context_object_name = 'race_list'
class EventDetailView(DetailView,LoginRequiredMixin):
context_object_name = 'race_detail'
template_name = 'myusers1/event.html' # this could be only event.html if the template is in yourapp/templates/ folder directly
model = Event
slug_url_kwarg = 'slug'
Notice in the above view that we now use actually the default slug definition.
I put the listview url under races/ sub-url but you can put it anywhere you want. And in your urls.py you can now use the slug values correctly like:
path('races/<slug:slug>/', views.EventDetailView.as_view(), name='race'),
path('races/', views.EventList.as_view(), name='race_list'),
In my trial app the templates look like the followings: listview template:
{% extends 'myusers1/base.html' %}
{% block content %}
<div class"container">
<div class="col col-lg-2">
<h2>Races</h2>
<ul>
{% for race in race_list %}
<div class="col-xs-12 .col-md-8"><li> {{ race.venue }} </li></div>
{% endfor %}
</ul>
</div>
</div>
{% endblock %}
And the detail template looks like this:
{% extends 'myusers1/base.html' %}
{% block content %}
<div class"container">
<div class="col col-lg-2">
<h2>Race Details</h2>
<div class="col-xs-12 .col-md-8"> <h4>Venue name: </h4> {{ race_detail.venue}} </div>
<div class="col-xs-12 .col-md-8"> <h4>Event ID: </h4> {{ race_detail.eventID }} </div>
<div class="col-xs-12 .col-md-8"> <h4>Meeting name: </h4> {{ race_detail.meeting }} </div>
<div class="col-xs-12 .col-md-8"> <h4>Meeting ID: </h4> {{ race_detail.meetingID.id }} </div>
</div>
</div>
{% endblock %}
And the visual result about how dynamic urls work using the above:
I hope that the above will help you to finalize your app list and details view now. Cheers.
I think I found a solution here try this:
url.py:
path('<slug:eventID>/', views.EventDetailView.as_view(), name='race')
Now you can simple get the instance of Event in your EventDetailView generic view by using get_object method like this:
class EventDetailView(DetailView, LoginRequiredMixin):
context_object_name = 'race_detail'
template_name = 'event.html'
model = models.Event
def get_object(self):
e1 = Event.objects.get(eventID=self.kwargs['eventID'])
print (e1.eventID) # or e1.pk gives: 123456_01
return e1
You can also change your eventID from CharField to SlugField. And still have it working.

Filter a Django form select element based on a previously selected element

Let's consider the following models
models.py
Class Brand(models.Model):
company_name = models.CharField(max_length=100)
class CarModel(models.Model):
brand = models.ForeignKey(Brand)
name = models.CharField(max_length=100)
Class FleetCars(models.Model):
model_car = models.Foreignkey(CarModel)
What is the best way to solve this problem in django?
Suppose a form (for insertions in FleetCars) consists of two select elements, like this:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<br />Brand:
<select>
<option value="Brand1">Brand1</option>
<option value="Brand2">Brand2</option>
</select>
<br />
<br />Model:
<select>
<option value="Model1_B1">Model1_B1</option>
<option value="Model1_B2">Model1_B2</option>
</select>
</body>
</html>
In this case, I want the options in the second select to depend on the value selected in the first. For example, if the user chose Brand1 for a Brand in the first select, the second select would be filtered with only cars whose Brand was Brand1, that is, only "Model1_B1".
Obs.
I saw many solutions with forms.ModelChoiceField, but only works with edit and since the user do not change the brand.
After hours and hours of research, without success, I decided to try to solve on my own. The solution that I found maybe don't be the best or the more elegant, but is working. (For download full Django project, click on this repo => https://github.com/Sidon/djfkf/.)
models.py
from django.db import models
class Brand(models.Model):
company_name = models.CharField(max_length=100)
def __str__(self):
return self.company_name
class Car(models.Model):
brand = models.ForeignKey(Brand)
name = models.CharField(max_length=100)
def brand_name(self):
return self.brand.company_name
def __str__(self):
return self.name
class Fleet(models.Model):
car = models.ForeignKey(Car)
description = models.CharField(max_length=100)
def car_name(self):
return self.car.name
def brand(self):
return self.car.brand.company_name
def __str__(self):
return self.description
The goal is to register cars on the fleet. The only fields that are will be recorded: Car (foreign key) and description. On the form, there will be one select element for brands that will work just only as a helper for to filter the car's combo box.
forms.py
import json
from django import forms
from .models import *
class RegCarForm(forms.ModelForm):
dcars = {}
list_cars = []
for car in Car.objects.all():
if car.brand.company_name in dcars:
dcars[car.brand.company_name].append(car.name)
else:
dcars[car.brand.company_name] = [car.name]
list_cars.append((car.name,car.name))
brands = [str(brand) for brand in Brand.objects.all()]
brand_select = forms.ChoiceField(choices=([(brand, brand) for brand in brands]))
car_select = forms.ChoiceField(choices=(list_cars))
brands = json.dumps(brands)
cars = json.dumps(dcars)
class Meta:
model = Fleet
fields = ('brand_select', 'car_select', 'description',)
RegCarForm is a form for register cars, there are three fields: brand_select, car_select, and description. In addition, I defined two JSON attributes: 1) a dictionary whose keys are brands (strings) and values are lists of respective's cars and 2) A list of strings that represent the brands. Those two attributes will work as helpers for JS functions.
views.py
from django.shortcuts import render
from .forms import RegCarForm
from .models import *
def regcar(request):
if request.method == 'POST':
car_form = RegCarForm(data=request.POST)
if car_form.is_valid():
cdata = car_form.cleaned_data.get
car_selected = Car.objects.filter(name=cdata('car_select'))
reg1 = Fleet(car_id=car_selected[0].id, description=cdata('description'))
reg1.save()
else:
print ('Invalid')
else:
car_form = RegCarForm()
return render(request, 'core/regcar.html', {'car_form': car_form})
The view is practically auto-explanatory. Assigns the Form to the car_form variable, render the template core/regcar.html and, after Post, make the validation of the form and save the data.
regcar.html (template django)
{% extends "base.html" %}
{% block head %}
{% endblock %}
{% block content %}
<h1>Registering cars on the fleet. <br />(Populate one drop down based on selection in another)</h1>
<p>Change the contents of drop down Car based on the selection in dropdown Brand, using Django-forms + Javascritp</p>
<div class="select-style">
<form action="." method="post">
{% csrf_token %}
{{ car_form.as_p }}
<p><input type="submit" value="Register a car"></p>
</form>
</div>
{% endblock %}
{% block js %}
{% include "js1.html" %}
{% endblock %}
The template only just renders the form and load the script JS. Nothing else.
Finally, the js script, that makes the hard work.
{% block js %}
<script language="javascript">
$('#id_brand_select').change(function() {populateCar(this)});
$('#id_description').addClass('descriptions');
cars = {{ car_form.cars | safe }}
brands = {{ car_form.brands | safe}};
populateBrand();
$("#id_car_select").empty();
$("#id_car_select").append('<option value="" disabled selected>First select a brand</option>');
function populateBrand() {
$('#id_brand_select').empty();
$("#id_brand_select").append('<option value="" disabled selected>Select your option</option>');
$.each(brands, function(v) {
$('#id_brand_select')
.append($("<option></option>")
.attr("value", brands[v])
.text(brands[v]));
});
}
function populateCar(event) {
brand = $("#id_brand_select option:selected").text();
$("#id_car_select").empty();
$("#id_car_select").append('<option value="" disabled selected>Select your option</option>');
for (let [b, bcars] of Object.entries(cars)) {
if (b == brand) {
//alert(b);
for (car in bcars) {
$('#id_car_select')
.append($("<option></option>")
.attr("value", bcars[car])
.text(bcars[car]));
}
}
}
}
</script>
{% endblock %}
When the document is loaded, this script assigns the change event of brand_select (combo for selection of brand) to the function poplulateCar, assign the form's JASON attributes (cars and brands) to a JS variables and call the populateBrand function.
Links:
Full project in Django:
https://github.com/Sidon/djfkf/
class Country(models.Model):
country_name=models.CharField(max_length=10, blank=True, null=True)
class State(models.Model):
state_name=models.CharField(max_length=10, blank=True, null=True)
class MyCustomModal(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, blank=True)
state = models.ForeignKey(State, on_delete=models.CASCADE, null=True, blank=True)
Here is my Form
class MyCustomForm(forms.ModelForm):
class Meta:
model = MyCustomModal
fields = [
'country',
'state',
]
def __init__(self, *args, **kwargs):
super(MyCustomForm, self).__init__(*args, **kwargs)
self.fields['country'] = forms.ChoiceField(choices=[('1','india'),('2','US')])
self.fields['state'].queryset = State.objects.filter(pk=2)

django templatetags not return correct data

I've built a small templatetag that looks towards my DB and makes a calculation based on the most popular trophies logged.
templatetag looks as follows:
#register.inclusion_tag('trophies/trophies.html')
def trophies():
return { 'trophies': Trophies.objects.values("specie").annotate(Count("id")).order_by()}
trophies/trophies.html
{% for obj in trophies %}
<li>{{ obj.specie }}</li>
{% endfor %}
trophy model
class Trophies(models.Model):
user = models.ForeignKey(User)
specie = models.ForeignKey(Specie)
Specie model
class Specie(ImageModel):
species = models.CharField(max_length=50, unique=True, verbose_name='Common Name')
running {{ obj.specie }} returns the id, and running {{ obj.specie.species }} returns nothing.
Why does this happen?
Try this:
#register.inclusion_tag('trophies/trophies.html')
def trophies():
return { 'trophies': Trophies.objects.values("specie", "specie__species").annotate(Count("id")).order_by()}
And in template:
{{ obj.specie__species }}
See related question: Display Django values() on Foreign Key in template as object instead of its id