How to solve NoReverseMatch? - django-models

Refer here for traceback****django throwing the error like this. Exception Value:Reverse for 'movie_details' with arguments '('',)' not found. 1 pattern(s) tried: ['movie\/(?P[0-9]+)\/$']
{% extends 'base.html' %}
{% block title %}
{{object.first_name}} - {{object.last_name}}
{% endblock %}
{% block main %}
<h1> {{object}} </h1>
<h2>Actor</h2>
<ul>
<p>hello</p>
{% for role in object.role_set.all %}
<li>
{{role.movie}}
</li>
{% endfor %}
</ul>
<h2>Writer</h2>
<ul>
{% for movie in objects.writing_credits.all %}
<li>
{{movie}}
</li>
{% endfor %}
</ul>
<h2>Director</h2>
<ul>
{% for movie in object.directed.all %}
<li>
{{movie}}
</li>
{% endfor %}
</ul>
{% endblock %}
codes in model.py
from django.db import models
class PersonManager(models.Manager):
def all_with_prefetch_movies(self):
qs = self.get_queryset()
return qs.prefetch_related('directed','writing_credits','roll_set__movie')
class Person(models.Model):
first_name = models.CharField(max_length=140)
last_name = models.CharField(max_length=140)
born = models.DateField()
died = models.DateField(null=True,blank=True)
objects = PersonManager()
Codes in views.py
class MovieDetail(DetailView):
model = Movie
queryset = Movie.objects.all_with_prefetch_persons()
class PersonDetail(DetailView):
queryset = Person.objects.all_with_prefetch_movies()
url mapping in urls.py
url pattern mentioned bellow
urlpatterns = [
path('movies/', MovieList.as_view(), name='movie_list'),
path('movie/<int:pk>/', MovieDetail.as_view(), name='movie_details'),
path('person/<int:pk>/', PersonDetail.as_view(), name='person_details'),
]

Related

How can i retrieve context from for loop in views django and send it to template

I need to do one page with topic and all entries about this topic. And for each entries I need all comments shown up below each entry. Comments should be for exact entry. Cant find it solution and decided ask. Thank you.
models.py
--snip--
class Comment(models.Model):
date_added = models.DateTimeField(auto_now_add=True)
text = models.TextField()
owner = models.ForeignKey(User, on_delete=models.CASCADE)
entry = models.ForeignKey(Entry, on_delete=models.CASCADE)
def __str__(self):
return f"{self.text[:50]}..."
views.py
--snip--
def topic(request, topic_id):
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.all()
comments = []
for entry in entries:
c = entry.comment_set.all()
comments.append(c)
context = {'topic': topic, 'entries': entries,
'comments': comments}
return render(request, 'learning_logs/topic.html'
,context)
topic.html
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>{{ topic.title }}</p>
<p>{{ topic.description }}</p><br>
<p>Entries:</p><br>
<ul>
{% for entry in entries %}
<li>{{ entry.text }}</li>
<ul>
<p>Comments:</p>
{% for comment in comments %}
<li>{{ comment.text }}</li>
{% endfor %}<br>
</ul>
{% empty %}
<li>Not entries</li>
{% endfor %}
</ul>
{% endblock content %}
You can do this with just topic. No need to get entries and comments:
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>{{ topic.title }}</p>
<p>{{ topic.description }}</p><br>
<p>Entries:</p><br>
<ul>
{% for entry in topic.entry_set.all %}
<li>{{ entry.text }}</li>
<ul>
<p>Comments:</p>
{% for comment in entry.comment_set.all %}
<li>{{ comment.text }}</li>
{% endfor %}<br>
</ul>
{% empty %}
<li>Not entries</li>
{% endfor %}
</ul>
{% endblock content %}
You will also want to optimise the query using prefetch_related so you don't hit the db per entry per comment:
topic = Topic.objects.prefetch_related('entry_set__comment_set').get(id=topic_id))
context = {'topic': topic}
return render(request, 'learning_logs/topic.html', context)

Wagtail Uploaded Document direct URL

I am trying to generate a url to an uploaded document (PDF, DOC...etc) on my search results page. Search is returning the items but there seems to be no url field. There is a file field which seems to have the file name, but I am unable to get a link back to this file. I am using the stock document model. Is there some sort of special tag that needs to be used like with the images?? At my wits end.
Search view
if search_query:
results = []
page_results = Page.objects.live().search(search_query)
if page_results:
results.append({'page': page_results})
doc_results = Document.objects.all().search(search_query)
if doc_results:
results.append({'docs': doc_results})
img_results = Image.objects.all().search(search_query)
if img_results:
results.append({'image': img_results})
search_results = list(chain(page_results, doc_results, img_results))
query = Query.get(search_query)
# Record hit
query.add_hit()
and the template page.
{% for result in search_results %}
{% for k, v in result.items %}
{% if k == 'page' %}
{% for item in v %}
<p>
<h4>{{ item }}</h4>
Type: Article<br>
Author: {{ item.specific.owner.get_full_name }}<br>
Publish Date: {{ item.specific.last_published_at}}
</p>
{% endfor %}
{% elif k == 'docs' %}
{% for item in v %}
<p>
<h4>{{ item.title }}</h4>
Type: Document<br>
Publish Date: {{ item.created_at }}
</p>
{% endfor %}
{% elif k == 'image' %}
{% for item in v %}
<p>
{% image item original as item_img %}
<h4>{{ item.title }}</h4>
Type: Image<br>
Publish Date: {{ item.created_at }}
</p>
{% endfor %}
{% endif%}
{% endfor %}
{% endfor %}

In Wagtail streamfield template how to check if a field of a structblock inside a structblock is null?

I have a StructBlock like this :
class CardBlock(blocks.StructBlock):
header= blocks.StructBlock([
("text", blocks.CharBlock(required=False, help_text="Header text")),
("classes", blocks.CharBlock(required=False, help_text="Header css classes")),
],
template="streams/card_header_block.html")
image= ImageChooserBlock(required=False)
icon= blocks.CharBlock(required=False, help_text="fontawesome classes for an icon")
title= blocks.StructBlock([
("text", blocks.CharBlock(required=False, help_text="Title text")),
("classes", blocks.CharBlock(required=False, help_text="Title css classes")),
],
template="streams/card_title_block.html")
bodyHTML = blocks.RawHTMLBlock()
footer= blocks.StructBlock([
("text", blocks.CharBlock(required=False, help_text="Footer text")),
("classes", blocks.CharBlock(required=False, help_text="Footer css classes")),
],
template="streams/card_footer_block.html")
class Meta:
template = "streams/card_block.html"
icon = "placeholder"
label = "Card"
And a template like this:
{% load wagtailcore_tags %}
{% load wagtailimages_tags %}
{% image value.image fill-300x150 as img %}
<div class="card {% if value.classes %} {{value.classes}} {% endif %}">
{% if value.header.text is not Null %}
{% include_block value.header %}
{% endif %}
{% if value.image %}
<img src="{{ img.url }}" alt="{{ img.alt}}" class="card-img-top" />
{% endif %}
<div class="card-body">
{% if value.title %}
{% include_block value.title%}
{% endif %}
{% if value.subtitle %}
{% include_block value.subtitle%}
{% endif %}
<div class="card-text">{% include_block value.bodyHTML %}</div>
{% if value.link %}
{% include_block value.link%}
{% endif %}
</div>
{% if value.footer %}
{% include_block value.footer%}
{% endif%}
</div>
I am trying to check is a child block like Header has its value filled by the page editor or not. If not I do not show the HTML. But I am afraid the header div still shows up. Someting is wrong with the way I am putting the condition.
A blank CharBlock is equal to the empty string, which is not the same as null (and in any case, Python's null value is None, not Null). You can test this the same way that you've tested other empty values in your template: {% if value.header.text %}

Wagtail Show latest blog posts on Homepage through a streamfield

I have 3 mains sections in my site, homepage, blog index, and blog specific. I am using the streamfield function in wagtail to order various sections in the homepage. One of those sections is for the latest three blog posts.
I have done this for the blog index page, but can't grab the latest blog posts in the streamfield.
My model looks like this
class CaseStudiesIndex(Page):
def casestudies(pages):
casestudies = CaseStudyPage.objects.all().order_by('-first_published_at')
return casestudies
intro = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel('intro', classname="full")
]
class LatestPosts(blocks.StructBlock):
static = blocks.StaticBlock(admin_text='Latest posts: no configuration needed.',)
def casestudies(pages):
casestudies = CaseStudyPage.objects.all().order_by('-first_published_at')[:3]
return casestudies
class Meta:
icon = 'doc-full'
label = 'Latest Posts'
template = 'blocks/_latestPosts.html'
class HomePage(Page):
blocksbody = StreamField([
('lead_banner', LeadBanner()),
('latest_posts', LatestPosts()),
('team', Team())
],null=True,blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('blocksbody'),
]
In my block folder I am calling the file fine and it renders the wrapper fine but I can't grab any of the data, I have tried a bunch of ways but nothing returns.
{% load wagtailcore_tags wagtailimages_tags %}
{% load static %}
<section>
<div class="wrapper__inner">
<ul>
{% for case in self.casestudies %}
{{case.title}}
{% endfor %}
{% for case in self.case_studies %}
{{case.title}}
{% endfor %}
{% for case in self.latest_posts %}
{{case.title}}
{% endfor %}
{% for case in page.casestudies %}
{{case.title}}
{% endfor %}
{% for case in page.case_studies %}
{{case.title}}
{% endfor %}
{% for case in page.latest_posts %}
{{case.title}}
{% endfor %}
</ul>
</div>
</section>
For the Blog Index page that does work I do the following.
{% extends "inner_base.html" %}
{% load wagtailcore_tags %}
{% block body_class %}template-case-studies{% endblock %}
{% block content %}
<section>
<div class="wrapper__inner">
<h1>{{self.title}}</h1>
<ul>
{% include "blocks/CaseStudiesLatestBlock.html" %}
</ul>
</div>
</section>
{% endblock %}
And the CaseStudiesLatestBlock.html which works fine looks like
{% load wagtailcore_tags wagtailimages_tags %}
{% load static %}
{% for case in self.casestudies %}
<li>
<strong>{{ case.title }}</strong>
</li>
{% endfor %}
Defining your own methods on a StructBlock won't work - the self (or value) variable you receive on the template is just a plain dict, not the StructBlock object itself. (This might seem counter-intuitive, but it's consistent with how blocks work in general: just as a CharBlock gives you a string value to work with and not a CharBlock instance, StructBlock gives you a dict rather than a StructBlock instance.)
Instead, you can define a get_context method (as documented here) to provide additional variables to the template:
class LatestPosts(blocks.StructBlock):
static = blocks.StaticBlock(admin_text='Latest posts: no configuration needed.',)
def get_context(self, value, parent_context=None):
context = super(LatestPosts, self).get_context(value, parent_context=parent_context)
context['casestudies'] = CaseStudyPage.objects.all().order_by('-first_published_at')[:3]
return context
You can then access the casestudies variable in the template, e.g. {% for case in casestudies %}.

Query returning every cover in db for each entry?

My query seems to be returning 1 entry for each cover. That is, if I have 3 covers in the database, then the query will return entry #1 three times with each of the different covers. Since I have 7 entries, I'm getting 21 results. How do I structure my query to return the cover associated with the entry?
Here's what I have:
#app.route('/list', methods=['GET', 'POST'])
def list():
entries = Book.query.order_by(Book.id.desc()).all()
cvr_entries = Cover.query.filter(Cover.book).all()
### Other queries I've tried ###
# cvr_entries = Cover.query.join(Cover.book).all()
# cvr_entries = Cover.query.filter(Cover.book.any())
# cvr_entries = Cover.query.filter(Cover.book.any()).all()
return render_template(
'list.html',
entries=entries,
cvr_entries=cvr_entries)
Here's the /list output page:
{% for entry in entries %}
{% for cvr in cvr_entries %}
<article class="entry">
<img src="/static/data/covers/{{ cvr.name }}" alt="Cover for {{ entry.title }}" />
<ul class="entry-info">
<li class=""><h2>{{ entry.title }}</h2></li>
<li class="">Summary: {{ entry.summary|truncate( 30, true ) }}</li>
</ul>
</article>
{% endfor %}
{% endfor %}
Switching the order of the entries and cvr_entries for loops changes nothing. I've also tried adding first() instead of all(), but that leads to an error where it says
TypeError: 'Cover' object is not iterable
so that was a bust. I don't understand how to build the query.
Here is my model, as requested by #jonafato:
book_to_cover = db.Table('book_to_cover',
db.Column('cover_id', db.Integer, db.ForeignKey('cover.id')),
db.Column('book_id', db.Integer, db.ForeignKey('book.id'))
)
class Book(db.Model):
__tablename__ = 'book'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String())
summary = db.Column(db.Text)
book_to_cover = db.relationship('Cover', secondary=book_to_cover,
backref=db.backref('book', lazy='dynamic'))
def __repr__(self):
return "<Book (title='%s')>" % (self.title)
class Cover(db.Model):
__tablename__ = 'cover'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
def __repr__(self):
return "<Cover (name='%s')>" % self.name
Generally, you iterate over the model-- your relationships should allow you to do:
books = Book.query.all()
return render_template('list.html', books=books)
Then in your Jinja2 list.html template:
{% for book in books %}
<h3>{{ book }}</h3>
<ul>
{% for cover in book.book_to_cover %}
<li>{{ cover }}</li>
{% endfor %}
</ul>
{% endfor %}
It'd be more natural to rename the book_to_cover to covers to make it more like natural language when you access the model.

Resources