access foreign key via a manytomany relationship in django - django

I have a foreign key that is in turn a many to many relation like the following:
Persons<-M2M->Role(ManyToOne)->Name
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',)
class Name(models.Model):
name=models.CharField(max_length=200)
role=models.ForeignKey(Role,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
ordering = ('name',)
class Address(models.Model):
I can acces the manyTomany field from persons and roles but I cannot access names.
the template:
{% extends "artdb/base.html" %}
{% block content1 %}
<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 %}
<ul>
{% for p in ans %}
{% for r in p.role_set.all %}
<h5>{{ r.role }}</h5>
{% endfor %}
{% endfor %}
<hr>
</ul>
{% endblock content2 %}
{% block content3 %}
<ul>
{% for p in ans %}
{% for r in p.role_set.all %}
<h5>{{ r.name }}</h5>
{% endfor %}
{% endfor %}
<hr>
</ul>
{% endblock content3 %
I konow that I have to iterate to get manyTomany, but is it the same with oneTomany?
how do I access Names from Persons via Role?
}

here is the solution for those interested. (thanks daniel roseman). Iterate through every relation. Here the first relation is many to many and the second many to one:
{% block content3 %}
<ul>
{% for p in ans %}
{% for r in p.role_set.all %}
{% for n in r.name_set.all %}
<h5>{{ n }}</h5>
{% endfor %}
{% endfor %}
{% endfor %}
<hr>
</ul>
{% endblock content3 %}

Related

In which variable is the model instance stored in customized view?

How can I actually pick up values from my model in a customised template?
Let's assume for this example, the model for Request has an attribute "title".
Following views.py:
class RequestModelView(ModelView):
datamodel = SQLAInterface(Request)
extra_args = {'my_extra_arg':Request}
show_template = 'show_request.html'
list_columns = ['title','description','request_status']
and here the show_requests.html
{% extends "appbuilder/general/model/show.html" %}
{% block show_form %}
This Text is before the show widget
{{ super() }}
This Text is shown below..
<hr>
{{ (self.title) }}; {{pk}}; {{pk['title']}}
{% endblock %}
In which variable can I find my object?
The only parameter that works is {{pk}} (it shows the ID of the Request).
I was thinking of something like item['title']
Thanks.
A very similar question was asked on their Github. I think you would have to use something along these lines:
views.py
class RequestModelView(ModelView):
datamodel = SQLAInterface(Request)
list_columns = ['title','description','request_status']
add_template = 'show_request.html'
#expose('/show_request', methods=['GET', 'POST'])
#has_access
def show_request(self):
get_filter_args(self._filters)
self.extra_args = {'item': list_columns}
return super(RequestModelView, self).add()
show_requests.html:
{% extends "appbuilder/general/model/show.html" %}
{% block show_form %}
This Text is before the show widget
{{ super() }}
This Text is shown below..
<hr>
{{ item['title'] }}
{% endblock %}
Documentation is certainly not very clear in this aspect, but please check template-extra-arguments
I'm not sure if you would still need extra_args = {'my_extra_arg':Request}.
The following example should make things clear:
from .models import cars
beautiful_names = ["John", "Jane", "Bob"]
flowers = ["Aster", "Buttercup", "Roses"]
class IndexView(View):
template_name = "dashboard/dashboard_index.html"
def get(self, request, *args, **kwargs):
all_car_objects=cars.objects.all()
return render(request,
self.template_name,
context={"my_addresslist": beautiful_names,
"my_rose_list": roses},
"all_cars":all_car_objects)
In your template you can then do something like:
<h1>Beautiful Names</h1>
{% for name in my_addresslist %}
<p>{{ name }}</p>
{% endfor %}
<h1>Roses</>
{% if my_rose_list %}
{% for rose in my_rose_list %}
<p>{{ rose }}</p>
{% endfor %}
{% endif %}
<h1>Cars</>
{% if all_cars %}
{% for car in all_cars %}
<div>
<p>{{ car.name }}</p>
<p>{{ car.make }}</p>
<p>{{ car.model }}</p>
</div
{% endfor %}
{% endif %}
So for your example, it comes down to this:
class MyView(ModelView):
datamodel = SQLAInterface(MyTable)
extra_args = {'my_request_list':Request}
show_template = 'show_request.html'
<h1>Requests</>
{% if my_request_list %}
{% for request in my_request_list %}
<p>{{ request }}</p>
{% endfor %}
{% endif %}

is_paginated not working properly for class based views in Django

book_list.html
{% extends "base.html" %}
{% block content %}
<h3> Available books </h3>
{% if book_list %}
<ul>
{% for book in book_list %}
<li> {{book.title }} <small> by {{book.author }}</small></li>
<p>{{ book.summary }}
{% endfor %}
<ul>
{% endif %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% else %}
<h4> pagination not working</h4>
{% endif %}
{% endblock %}
class in views.py :
class BookListView(generic.ListView):
model = Book
paginate_by = 2
queryset =Book.objects.all()
urls.py :
urlpatterns =[
url('^$',views.index, name ='index'), # matching with an empty string
url('^books/$',views.BookListView.as_view(),name ='books'), #the one to which I am adding the paginator
url('^book/(?P<pk>\d+)/$',views.BookDetailView.as_view(),name='book-detail'),
]
Book model :
class Book(models.Model):
title=models.CharField(max_length=100)
author = models.ForeignKey('Author',on_delete=models.SET_NULL,null = True)
summary = models.TextField(max_length=200,help_text="Enter the description")
isbn = models.CharField('ISBN',max_length=13 ,help_text='13 Character ISBN number' )
genre = models.ManyToManyField(Genre,help_text = 'selct a genre for this book')
class Meta:
ordering =["title"]
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book-detail',args=[str(self.id)] )
The book_list gets rendered perfectly, the problem is with the paginator, the is_paginated condition is not working and it executes the else statement, I have been trying for more than 3 hours, but couldn't find a solution, What Am I missing here ?
Django version : 1.11.2
Python : 3.5
Edit :
update 1: The problem was the paginate_by value was two, and the total items to display was also two hence it didn't initiate the is_paginated tag,It worked fine when I added one item more than paginate_by value.
use this, you had some problem with the if condition
{% extends "base.html" %}
{% block content %}
<h3> Available books </h3>
{% if object_list %}
<ul>
{% for book in object_list %}
<li> {{book.title }} <small> by {{book.author }}</small></li>
<p>{{ book.summary }}
{% endfor %}
<ul>
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% else %}
<h4> pagination not working</h4>
{% endif %}
{% else %}
<h4> No book</h4>
{% endif %}
{% endblock %}

Displaying Nested ManyToMany Relation

I'm having nested many to many relation in my models.py and I've got the display partially working. I have 2 questions:
Is there a way to simplify the presentation, e.g. by inlineformset?
How to I access nested context variables in the template form (see line {% for objective in selected_objectives %} )?
Please let me know if there is a way to make my question more clear
models.py
class Process(models.Model):
title = models.CharField(max_length=200)
desc = models.TextField('process description', blank=True)
def __str__(self):
return self.title
class Objective(models.Model):
process = models.ManyToManyField(Process, verbose_name="related processes", blank=False)
title = models.CharField(max_length=200)
desc = models.TextField('objective description', blank=True)
def __str__(self):
return self.title
class Risk(models.Model):
objective = models.ManyToManyField(Objective, verbose_name="related objectives", blank=False)
title = models.CharField(max_length=200)
desc = models.TextField('risk description', blank=True)
def __str__(self):
return self.title
views.py
#login_required
def detailed_list(request):
#context = RequestContext(request)
obj = []
ri = []
all_processes = Process.objects.order_by('id') #[:1]
for p_index,p in enumerate(all_processes):
obj.append(p.objective_set.all()) #appending objectives for each process
for o_index,o in enumerate(obj[p_index]):
ri.append(o.risk_set.all().values()) #appending risks for each objective
context = {'all_processes': all_processes,
'selected_objectives': obj,
'selected_risks': ri
}
return render(request, 'repository/detailed.html', context)
template detailed.html
<p>Create new Process
</p>
{% if all_processes %}
No: {{ all_processes|length }}
<ul>
{% for process in all_processes %}
<li>{{ process.title }} {{ forloop.counter0 }}</li>
<ul>
{% if selected_objectives %}
{% for objective in selected_objectives %}
<!-- see here --> <li>{{ objective.title }} {{ forloop.counter0 }} - {{ objective.desc }}</li>
{% endfor %}
{% else %}
<p>No objectives are available.</p>
{% endif %}
</ul>
{% endfor %}
</ul>
{% else %}
<p>No processes are available.</p>
{% endif %}
all you have to do is just pass the Process object as the context to your template
context = {'all_processes': all_processes}
and in you template :
<p>Create new Process
</p>
{% if all_processes %}
No: {{ all_processes|length }}
<ul>
{% for process in all_processes %}
<li>{{ process.title }} {{ forloop.counter0 }}</li>
<ul>
{% if all_processes.objective_set.all %}
{% for objective in all_processes.objective_set.all %}
<li>{{ objective.title }} {{ forloop.counter0 }} - {{ objective.desc }}
</li>
{% endfor %}
{% else %}
<p>No objectives are available.</p>
{% endif %}
</ul>
{% endfor %}
</ul>
{% else %}
<p>No processes are available.</p>
{% endif %}
<!-- this is if you want to show risks -->
{% for process in all_processes %}
{% for objective in all_processes.objective_set.all %}
{% for risk in objective.risk_set.all %}
{{ risk.desc }}
{% endfor %}
{% endfor %}
{% endfor %}
I hope this is what you were expecting !

Using MPTT do get_children in templates (at runtime)

my template receives a variable called categories, and I want to list the categories that are "sons" of its father categories
this is my code in template
{% for category,structure in categories|tree_info %}
{% if structure.new_level %}
<li>{{ category.name }} </li>
{% endif %}
{% for level in structure.closed_levels %}
<li>{{level.name}}
{% endfor %}
<ul class="noJS">
{% for cat in category.get_children|tree_info %}
<li>{{ cat.name }}aa </li>
{% endfor %}
</ul>
{% endfor %}
this is the model
class Category(MPTTModel):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(blank=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
class MPTTMeta:
order_insertion_by = ['name']
def __unicode__(self):
return self.name
any idea?
This worked
{% for category in categories %}
<li>
{{ category.name }}
<ul class="noJS">
{% for cat in category.get_children %}
<li>{{ cat.name }} </li>
{% endfor %}
</ul>
</li>
{% endfor %}

Django Reverse Query in Template

I have models like this
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __unicode__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
I want to list all blogs in a page. I have written a view such that
def listAllBlogs(request):
blogs= Blog.objects.all()
return object_list(
request,
blogs,
template_object_name = "blog",
allow_empty = True,
)
And I can display tagline of blog such that in view
{% extends "base.html" %}
{% block title %}{% endblock %}
{% block extrahead %}
{% endblock %}
{% block content %}
{% for blog in blog_list %}
{{ blog.tagline }}
{% endfor %}
{% endblock %}
But I would like to show, such thing blog__entry__name but I don't know how can I achive this in template.
Also, there may be no entry in a blog. How can I detect in template ?
Thanks
To access blog entries (Related Manager): blog.entry_set.all
To do other actions if blog have no entries, you have the {% empty %} tag that is executed when the set is empty.
{% block content %}
{% for blog in blog_list %}
{{ blog.tagline }}
{% for entry in blog.entry_set.all %}
{{entry.name}}
{% empty %}
<!-- no entries -->
{% endfor %}
{% endfor %}
{% endblock %}
based on your code you could do the following.
{% block content %}
{% for blog in blog_list %}
{{ blog.tagline }}
{% for entry in blog.entry_set.all %}
{{entry.name}}
{% endfor %}
{% endfor %}
{% endblock %}