I have the following template:
{% extends "artdb/base.html" %}
{% block content1 %}
<h4>Persons:</h4>
<ul>
{% for p in ans %}
<h5>First name: {{p.firstName}}</h5>
<h5>Last name: {{p.lastName}}</h5>
<h5>Phone: {{p.phoneNumber}}</h5>
<h5>Adress: {{p.streetAdress}}</h5>
<h5>Zip Code: {{p.zipcode}}</h5>
<h5>City: {{p.city}}</h5>
<hr>
{% endfor %}
</ul>
{% endblock content1 %}
{% block content2 %}
<h4>Roles:</h4>
<ul>
{% for p in ans %}
<h5>Role:{{p.persons.role}}</h5>
<hr>
{% endfor %}
</ul>
{% endblock content2 %}
and the model:
class Person(models.Model):
mail=models.EmailField()
firstName=models.CharField(max_length=200)
lastName=models.CharField(max_length=200)
phoneNumber=PhoneNumberField()
streetAdress=models.CharField(max_length=200)
zipcode=models.CharField(max_length=200)
city=models.CharField(max_length=200,default="Göteborg")
country=models.CharField(max_length=200,default="Sweden")
def __str__(self):
return "%s %s" % (self.firstName,self.lastName)
class Meta:
ordering = ('firstName','lastName')
class Role(models.Model):
role=models.CharField(max_length=200)
person=models.ManyToManyField(Person)
def __str__(self):
return self.role
class Meta:
ordering = ('role',)
But when I run the above code the only output that I get is from the block content1, i.e I cannot access the role content. I thought that role.persons.role would do it but apperantley not. There is a many-to-many relationship between perssons and roles.
Any ideas?
This should work
{% block content2 %}
<h4>Roles:</h4>
<ul>
{% for p in ans %}
{% for role in p.role_set.all %}
<h5>Role:{{ role }}</h5>
<hr>
{% endfor %}
{% endfor %}
</ul>
{% endblock content2 %}
We have to create a second for loop, since a many to many relationship will always return a list. Not a single instance. So essentially it's just like accessing a 2d array.
In Django you only have to define a n:n relationship on one end. Django will then automatically add it to the other model as well. It does this by taking the related model name and suffixing _set. So if we want to reference all of the roles attached to a person, it would be person.role_set. The other way around it would be role.person like you defined in the model.
Related
How can I access fields other than the grouper in a Django group_by function?
class dateEvent(models.Model):
event = models.ForeignKey('Event', on_delete=models.CASCADE)
start_date_time = models.DateTimeField(auto_now=False, auto_now_add=False)
def __str__(self):
return "%s" % (self.event.title)
def description(self):
return "%s" % (self.event.description)
class Event(models.Model):
description = RichTextUploadingField(max_length=200)
view:
def my_view(request):
events = dateEvent.objects.all()
context = {
'events': events,
}
return render(request, 'view.html', context)
template:
<ul>
{% for event in dateEvents_list %}
<li><h5>Event: {{ event.grouper }}</h5>
<h6>Description: {{ event.description }}</h6> #How can access the description of the main event?
<ul>
{% for dateEvent in event.list %}
<li>date: {{ dateEvent.start_date_time }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
I'd like to have the title, which is the grouper so it's fine, but also the description.
You can also access your grouper's list objects to get details about the "first record" in your group. So using:
event.grouper.list.0.<any_model_field_you_want>
Will work just fine. I have this in production and it solved my needs immediatly. I found this in a rejected feature request for Django here: https://code.djangoproject.com/ticket/13452
If you need to traverse your model's relationship tree you can do the following.
event.grouper.list.0.<related_model_name>.<any_model_field_you_want>
You can access model attributes from the grouper directly using event.grouper.<any-model-attribute>.
In your example here is how it would look:
<ul>
{% for event in dateEvents_list %}
<li><h5>Event: {{ event.grouper }}</h5>
<h6>Description: {{ event.grouper.description }}</h6>
<ul>
{% for dateEvent in event.list %}
<li>date: {{ dateEvent.start_date_time }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
I can't find any documentation around this usage.
I'm working on a Django web app and have the following query:
I have a model called 'AppQoSList' which lists the applications available to all users.
I have then another model called 'BasicAppSDWANProfiles' which has a ManyToMany relationship with 'AppQoSList' .
In short, it means a user can have multiple 'BasicAppSDWANProfiles' associated to his account and multiple AppQoS can be within a particular BasicAppSDWANProfiles:
class AppQoSList(models.Model):
app_qos_name = models.CharField(max_length=50, blank=None, null=True)
app_qos_description = models.CharField(max_length=500)
def __str__(self):
return u'%s' % self.app_qos_name
class BasicAppSDWANProfiles(models.Model):
profile_name = models.CharField(max_length=30)
profile_basic_app_qos = models.ManyToManyField(AppQoSList)
tenant_id = models.ForeignKey(Tenant, default=3)
I'm facing issue in my template when I try to display the list of apps available and the associated BasicAppSDWANProfile:
{% for app in apps %}
{% for profile_app in sdwan_prof %}
{% for specific_app in profile_app.profile_basic_app_qos.all %}
{% ifchanged specific_app.pk %}
{% if app.pk == specific_app.pk %}
<td><h4><span class="label label-primary">{{ profile_app.profile_name }}</span></h4></td>
{% else %}
<td><h4><span class="label label-warning">Not Assigned</span></h4></td>
{% endif %}
{% endifchanged %}
{% endfor %}
{% endfor %}
{% endfor %}
Issue with this code is that 'Not Assigned' is displayed 6 times on each row (which corresponds to the number of Apps found in BasicAppSDWANProfiles associated with this user) whereas I would like to display it only once:
Would you have any solution for this ?
Thanks in advance.
I was able to address this issue.
First I did clean up my view code to remove duplicate 'Not Assigned' values.
I pass to my template context a dictionary with only apps that have a profile assigned such as below:
{'citrix-static': 'DPS-BLACKLIST',
'exchange': 'DPS-BLACKLIST',
'ms-lync-audio': 'DPS-WHITELIST',
'ms-update': 'DPS-GREYLIST',
'rtp': 'DPS-WHITELIST',
'share-point': 'DPS-WHITELIST'}
In my template, I only loop through this dictionary:
{% for k,v in app_prof_assign.items %}
{% if app.app_qos_name == k %}
<td><h4><span class="label label-primary">{{ v }}</span></h4></td>
{% endif %}
{% endfor %}
I then simply check if the app is not in the profile dictionary, outside the loop:
{% if app.app_qos_name not in app_prof_assign %}
<td><h4><span class="label label-warning">Not Assigned</span></h4></td>
{% endif %}
Finally, I can get the table populated as expected:
I am using Django 1.8 with Postgres 9.2 on a Windows 8 machine.
I have two pieces of nearly identical code from two of my projects. One works and the other doesn't.
Here's the code that works:
# views.py
from django.shortcuts import render
from models import Artist, Track
def music(request):
artists = Artist.objects.all().order_by('orderName')
artistTrackCollections = []
for artist in artists:
artist.tracks = Track.objects.filter(artist=artist).order_by('order')
artistTrackCollections.append(artist)
return render(request, 'music.html', {'artistTrackCollections': artistTrackCollections,})
And the relevant template code:
{% for artist in artistTrackCollections %}
<dl>
<dt>
{% if artist.website %}
<h2>{{ artist.name }}</h2>
{% else %}
<h2>{{ artist.name }}</h2>
{% endif %}
</dt>
<dd>
<ul>
{% for track in artist.tracks %}
<li>“{{ track.title }}”
<i>({{ track.album.title }})</i>
{% endfor %}
</ul>
</dd>
</dl>
{% endfor %}
Now here's pretty much the exact same code from a different project of mine that doesn't work anymore:
def index(request):
productList = PartModel.objects.filter(isBuild=True, isActive=True).order_by('name')
productCollection = []
for product in productList:
product.part_list = product.buildpart.all().order_by('family__type')[:5]
productCollection.append(product)
return render(request, 'index.html', { 'productCollection': productCollection, })
and its corresponding template:
{% for product in productCollection %}
<p>{{ product.name }}
<p>${{ product.price }}
<ul>
{% for part in product.part_list %}
<li>{{ part.family.type.name }} | {{ part.name }}
{% endfor %}
</ul>
{% endfor %}
This code used to work but now it doesn't. In the code that works I succeed in going through each artist and attaching that artist's tracks. In the code that fails I try to go through each PartModel instance that is a build and get that PartModel instance's corresponding parts. They are identical as far as I can tell. productCollection gets populated but the part_list data for some reason is blank. This leads me to believe the problem is with this line:
product.part_list = product.buildpart.all().order_by('family__type')[:5]
But I cannot discern the difference from this line:
artist.tracks = Track.objects.filter(artist=artist).order_by('order')
Thanks in advance for any help!
Model:
class Exercise (models.Model):
name_e = models.CharField(max_length=50)
class Subject (models.Model):
name_s = models.CharField(max_length=50)
exercise = models.ForeignKey(Exercise)
View:
exercise_all = Exercise.objects.all()
subject_all = Subject.objects.all()
My SQL table contain subjects and exercises connected via ForeignKey
I pass view variables as a context to the template:
{% for e_field in exercise_all %}
<table>
<tr><th>Header</th></tr>
{% for s_field in subject_all %}
<tr><td>{{ e_field.name_e }}</td></tr>
{% endfor %}
</table>
{% endfor %}
If I have, let's say, 3 types of Exercises and 10 Subjects connected with Exercises (subject1->exercise1, subject2->exercise1, subject3->exercise1, subject4->exercise2 etc.)
I want to display 3 tables in a template and each table will display only tr/subjects corresponding to table/exercise. I tried with {% if ... in ... %} but maybe i should do some function in view.
In this case you should be able to say:
{% for e_field in exercise_all %}
<table>
<tr><th>Header</th></tr>
{% for s_field in e_field.subject_set.all %}
<tr><td>{{ e_field.name_e }}</td></tr>
{% endfor %}
</table>
{% endfor %}
how do i implement the tree structure in django templates with out using django-mptt.
i have model.
class Person(TimeStampedModel):
name = models.CharField(max_length=32)
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
now i want ..
Parent
Child 1
subchild 1.1
subchild 1.2
nextsubchild 1.2.1
Child 2
Child 3
there names should be click able to show their profile.
I just finished implementing this. I wanted a tree structure for a sub-navigation, but I did not want to do anything strange with recursive templates.
The solution I implemented is very simple: I simply recurse in the view (in my case a generic helper function) and flatten out the hierarchical structure into a simple list. Then, in my template I just use a for loop to iterate over the list.
Each element in the list can be one of three things: "in", the object, or "out". In my case, I'm constructing a series of ul li elements in the view, so when I encounter "in" I create a new ul, when I encounter "out" I close the ul. Otherwise, I render the item.
My template code looks like this:
<ul>
{% for item in sub_nav %}
{% if item == "in" %}
<ul>
{% else %}
{% if item == "out" %}
</ul>
</li>
{% else %}
<li>
<a href='{{item.full_url}}'>{{item.name}}</a>
{% if item.leaf %}
</li>
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
</ul>
The code in the helper function looks like this:
def get_category_nav(request,categories=None):
"""Recursively build a list of product categories. The resulting list is meant to be iterated over in a view"""
if categories is None:
#get the root categories
categories = ProductCategory.objects.filter(parent=None)
categories[0].active=True
else:
yield 'in'
for category in categories:
yield category
subcats = ProductCategory.objects.select_related().filter(parent=category)
if len(subcats):
category.leaf=False
for x in get_category_nav(request,subcats):
yield x
else:
category.leaf=True
yield 'out'
Using those snippets, you should be able to build any sort of hierarchical tree you'd like without doing any recursion in the template, and keeping all the logic in the view.
I know there was already an accepted answer for this, but I thought I'd post the technique in case it helps anyone else.
from Django while loop question and
http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags
# view.py
#register.inclusion_tag('children.html')
def children_tag(person):
children = person.children.all()
return {'children': children}
# children.html
<ul>
{% for child in children %}
<li> {{ child }}</li>
{% if child.children.count > 0 %}
{% children_tag child %}
{% endif %}
{% endfor %}
</ul>
# your template
{% children_tag parent %}
These are great answers but I consolidated a bit and put it on the actual model.
class RecursiveThing(models.Model):
name = models.CharField(max_length=32)
parent = models.ForeignKey('self', related_name='children', blank=True, null=True)
def as_tree(self):
children = list(self.children.all())
branch = bool(children)
yield branch, self
for child in children:
for next in child.as_tree():
yield next
yield branch, None
And then in your template:
<ul>
{% for thing in things %}
{% for branch, obj in thing.as_tree %}
{% if obj %}
<li>{{ obj.name }}
{% if branch %}
<ul>
{% else %}
</li>
{% endif %}
{% else %}
{% if branch %}
</ul>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
</ul>
It's very simple
All you have to do in your view is get all objects:
people = Person.objects.all()
Then in your template :
{% for person in people %}
<li>- {{person.name}} </li>
{% for child in person.children.all %}
<ul>* {{child.nom}} </ul>
{% endfor %}
</li>
{% endfor %}