I think I am following the doc correctly but still le* weird problem occurs : MPTT template tag displays the tree nicely, indented and all, but not node.name tag (empty)
My Model
class Forme(MPTTModel):
name = models.CharField(max_length=50, unique=True)
source_id = models.IntegerField(max_length=50, unique=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
def __unicode__(self):
return unicode(self.name)
class MPTTMeta:
order_insertion_by = ['name']
My View
def listnode(request):
nodes = Node.objects.using('hmdjango').all()
selectforme = Forme.tree.all()
allnodes = []
for n in Node.objects.using('hmdjango').all() :
try:
intervention = FieldDataFieldItemIntervention.objects.using('hmdjango').get(entity_id__exact=n.id)
except FieldDataFieldItemIntervention.DoesNotExist:
intervention.field_item_intervention_value = 'BOOM'
try:
forme = FieldDataFieldItemForme.objects.using('hmdjango').get(entity_id__exact=n.id)
except FieldDataFieldItemForme.DoesNotExist:
forme.field_item_forme_tid = 'BOOM'
allnodes.append({'id':n.id, 'title':n.title,\
'intervention':intervention.field_item_intervention_value, \
'forme':forme.field_item_forme_tid})
return render_to_response('node_list.html', {'nodes':allnodes, 'formes':selectforme}, context_instance=RequestContext(request))
My template (I did load mptt_tags)
<ul class="root">
{% recursetree formes %}
<li>
{{ forme.name }}
{% if not forme.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
EDIT
A classic loop through "formes" variables shows that I can access name attribute. Thus my guess is recursivetree template tag, provided by django-mptt, is my main suspect here
{% for forme in formes %}
<li>{{ forme.name }}
{% endfor %}
Found the issue.
In the doc we have the example
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
node is an instance of our MPTT Model. But it has to be call "nodes". AND no variable "nodes" should be in your template.
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 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.
I am trying to iterate over my FKs in my model such that I show all the connections through various tables. My template renders but does not show any values. Any ideas?
models.py
class State(models.Model):
state = models.CharField(max_length=255)
relevantdisease = models.ForeignKey(Disease)
relevantoption = models.ManyToManyField(Option, through='StateOption')
class StateOption(models.Model):
partstate = models.ForeignKey(State)
partoption = models.ForeignKey(Option)
relevantoutcome = models.ManyToManyField(Outcome, through='StateOptionOutcome')
class StateOptionOutcome(models.Model):
stateoption = models.ForeignKey(StateOption)
relevantoutcome = models.ForeignKey(Outcome)
outcomevalue = models.CharField(max_length=20)
views.py
def stateall(request, disease_id):
disease = get_object_or_404(Disease, pk=disease_id)
states = State.objects.select_related().filter(relevantdisease=disease_id)
context = {'disease':disease,'states': states}
return render(request, "stateall.html", context)
template.html
{% for state in states %}
<li>{% for i in state.stateoption_set.all %}</li>
<li>{% for j in i.stateoptionoutcome_set.all %}</li>
{% endfor %}
{% endfor %}
{% endfor %}
I would like the template to show up as:
State1<state>
<li>partoption</li>
<li>relevantoutcome: outcomevalue</li>
State2<state>
<li>partoption</li>
<li>relevantoutcome: outcomevalue</li>
...
Your template never outputs anything.
You're probably misunderstanding the use of the {% for %} template tag.
This:
<li>{% for j in i.stateoptionoutcome_set.all %}</li>
{% endfor %}
Outputs <li> a few times.
But this:
{% for j in i.stateoptionoutcome_set.all %}
<li>{{ j.relevantoutcome }}: {{ j.outcomevalue }}</li>
{% endfor %}
Will output a line per StateOptionOutcome found in i.stateoptionoutcome_set.all.
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 %}
I'm having some trouble using get_absolute_url in a template. It seems to work fine if I just pass in one of my store objects and say {{ store.get_absolute_url }}, but if I have to iterate through a dictionary of stores and then use the get_absolute_url function, it returns nothing. Exactly what I'm doing is below:
class Store(EthicalObject):
type = "Store"
name = models.CharField(max_length=50)
company = models.ForeignKey(Company, verbose_name="Company", null=True, blank=True)
location = models.OneToOneField(Location, verbose_name="Location", null=True, blank=True)
products = models.ManyToManyField('Product', related_name="%(class)s_related", db_table=u'ethicsdb_products_to_stores', blank=True)
companies = models.ManyToManyField('Company', related_name="%(class)s_related", db_table=u'ethicsdb_companies_to_stores', blank=True)
def get_absolute_url(self):
return ('store_details', [str(self.id)])
get_absolute_url = models.permalink(get_absolute_url)
This works:
views.py:
def fetch_sidebar_data(shop_object):
sidebar_modules = {}
if shop_object.content_type.name == 'company':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'store':
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'product':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['tags'] = shop_object.tags
return sidebar_modules['related_stores'][1]
def company_details(request, company_id):
company = get_object_or_404(Company, id=company_id)
sidebar_modules = fetch_sidebar_data(company)
return render_to_response('company/details.html', {'company': company, 'sidebar_modules': sidebar_modules}, context_instance=RequestContext(request))
template:
{% extends "base-onecol.html" %}
{% block page_div_extra_attr %}class="twocol"{% endblock %}
{% block sidebar_content %}
<div id="sidebar-right">
<h1>{{ sidebar_modules.name }}{{sidebar_modules.get_absolute_url }}</h1>
</div>
{% endblock %}
This doesn't work:
views.py:
def fetch_sidebar_data(shop_object):
sidebar_modules = {}
if shop_object.content_type.name == 'company':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'store':
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'product':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['tags'] = shop_object.tags
return sidebar_modules
template:
{% extends "base-onecol.html" %}
{% block page_div_extra_attr %}class="twocol"{% endblock %}
{% block sidebar_content %}
<div id="sidebar-right">
{% for module_name,module in sidebar_modules.items %}
{% ifequal module_name "related_stores" %}
<h3>Sold Here</h3>
{% for related_store in module.values %}
{{ related_store.name }}<br/>
{% endfor %}
{% endifequal %}
{% ifequal module_name "related_products" %}
<h3>Buy Local</h3>
{{ module }}<br/>
{% endifequal %}
{% ifequal module_name "related_companies" %}
<h3>
{{ module }}<br/>
{% endifequal %}
{% ifequal module_name "tags" %}
{{ module }}<br/>
{% endifequal %}
{% endfor %}
</div>
{% endblock %}
In the second one, I just get no return from get_absolute_url. I know it's working in other places when I print it out. Is this a Django bug, the inability to use get_absolute_url in a dictionary of dictionaries?
Wow, that was a rather convoluted question.
Your problem is here: {% for related_store in module.values %}
module is a QuerySet. .values is calling the QuerySet method which returns a dictionary containing the field values for each row. A dictionary has no get_absolute_url attribute, and get_absolute_url isn't a field in the model.
Just use {% for related_store in module %} and you'll be dealing with actual model instances rather than dictionaries, which means {{ related_store.get_absolute_url }} will work fine.