Unexpected Keyword when I Pass Url Parameter - python

I have a view called 'Teams' that loops through different NBA teams in a dictionary and shows their name and logo. When the user clicks on one of these logos, I want them to be taken to the 'TeamDetailView'. This should carry over the chosen team's city/name/logo, and I can see this information being passed in the URL. When I attempt to load the team's individual page, though, it gives me a type error and says that
TeamDetailView() got an unexpected keyword argument 'city'
In the local vars section, it shows my key/value pairs being passed correctly. How can I access these parameters on the team page and correct this error?
callback_kwargs {'city': 'Atlanta', 'logo': 'atlanta-logo.png', 'name': 'Hawks'}
Here is my view:
def TeamDetailView(request):
return render(request, 'bandwagon/team.html/')
Here is my URL:
path('team/<str:city>/<str:name>/<str:logo>/', views.TeamDetailView, name='bandwagon-team'),
Here is my Template for the Teams List:
{% for key, value in teams.items %}
<a class="stream-list" href="{% url 'bandwagon-team' value.city value.name value.logo %}">
<img class="stream-img" alt="The Logo for the {{ value.city }} {{ value.name }}" src="../../../media/logos/{{ value.logo }}">
<p class="name">{{value.city }} {{value.name}}</p>
</a>
{% endfor %}
Here is my Template for the Individual Team Page, which is quite basic for now until I get these parameters passed correctly:
{% extends 'bandwagon/base.html' %}
{% block content %}
<h1 class="article-title">Team</h1>
{% endblock content %}

Have you tried updating your TeamDetailView function to accept the url parameters? Something like -
def TeamDetailView(request, city, name, logo):
return render(request, 'bandwagon/team.html/')

As they've tell you before you're not extracting the data from the path, you're just rendering the HTML without any context:
To solve this I would get the Team filtered by the data you're getting of the path, for example:
def TeamDetailView(request, city, name, logo):
Result = Your_Model.objects.all().filter(Q(City=city, Name=name, Logo=logo))
return render(request, 'bandwagon/team.html', {'Teams': Result})
And then in your template you could do something like:
{% for Team in Teams %}
# What you want to achieve
{% endfor %}

Related

Passing variable to href django template

I have some problem and maybe I can give an example of two views below what I want to achieve.
class SomeViewOne(TemplateView):
model = None
template_name = 'app/template1.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# The downloads view contains a list of countries eg France, Poland, Germany
# This returns to context and lists these countries in template1
class ItemDetail(TemplateView):
model = None
template_name = 'app/template2.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
countries_name = kwargs.get('str')
The view should get the passed "x" with the name of the country where I described it
below.
Then on the page I have a list of these countries.
After clicking on the selected country, a new tab should open and show a list of cities in the selected country.
So I am using in loop template1.html as below
{% for x in list_countries %}
<li>
{{ x }}<br>
</li>
{% endfor %}
I can't pass "x" this way. Why?
The url for the next view looks like this
path('some/countries/<str:x>/',views.ItemDetail.as_view(), name='some-name-url'),
And I can't get that 'x' given in the template in the href
There are several mistakes such as:
It should be only x in url tag neither {{x}} nor '{{x}}'
you have passed the value as x in url params (some/countries/<str:x>/) and accessing it using kwargs.get('str') which is not correct it should be kwargs.get('x').
Also you are not including variable countries_name in context and not even returning context.
Note: Assuming that you are already getting some companies in template1.html template that's why you are running loop.
Try below code:
views.py
class ItemDetail(TemplateView):
template_name = 'template2.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['countries_name'] = self.kwargs.get('x')
return context
Template1.html file
{% for x in list_countries %}
<li>
<a onclick="window.open('{% url 'some-name-url' x %}', '_blank')" style='cursor:pointer;'>{{ x }}</a><br>
</li>
{% endfor %}
Then you can this countries_name value passed from template1.html in template2.html.
template2.html
<p>The clicked country is {{countries_name}}</p>
If Manoj's solution doesn't work, try removing the single quotes AND {{ }}. In my program, my integer doesnt need to be wrapped with {{ }}, so maybe neither does your string.
I have this in my code:
{% for item in items %}
<div class="item-title">
{{ item }}<br>
</div>
Edit {{ item }}
{% endfor %}
It works just fine. Try:
{{ x }}
You don't need pass that variable with single quotes.
<a href="{% url 'some-name-url' {{ x }} %}" #Just removed single quotes from variable x.
And see if it shows on template

Getting error 'context must be a dict rather than set.' when trying to retrieve single object where id=id in django Model

I can't make work my detail function to simply retrieve all fields of only one Model element.
my code is :
views.py
def band_detail(request, id):
band = Band.objects.get(id=id)
return render(request,
'bands/band_detail.html',
{'band', band })
in urls.py I wrote:
path('bands/<int:id>/', views.band_detail)
So, when I am going to /bands/{id} it should show me my band_details.html page :
{% extends 'listings/base.html' %}
{% block content %}
<h1> {{ band.name }} </h1>
{% if band.active %}
<h2> Active : <i class="fa-solid fa-check"></i> </h2>
{% else %}
<h2> Active : <i class="fa-solid fa-xmark"></i> </h2>
{% endif %}
{% endblock %}
but instead I get a typeError telling me : 'context must be a dict rather than set.'
error page
I guess this is due to the way I retrieve my Band object from id. But I can't wrap my mind around. That is why I am coming for a lil help.
Thanks in advance
You have a context error! because the context must be a dictionary.
def band_detail(request, id):
band = Band.objects.get(id=id)
return render(request,
'bands/band_detail.html',
context={'band': band })

How to access variables within html template url_for

I'm building a Netflix like website for my Devops course. I made a Python list of dictionaries (Mockfilms) to define my films, and want to populate a database (Ratings) with reviews in preparation for sending data in the format :filmid: :userid: :rating: to a recommendation engine.
My index page is a list of film images with a link to a review form under each one. I want each review form to appear on a different url (/review/ID where ID is saved in mockfilms as oid). In order to do this I want to access mockfilms.oid, then pass it to the view function to make the url for the form. Once the form is complete I then want to add this ID to the Ratings database. Here is what I have so far:
Index:
{% extends "base.html" %}
{% block content %}
<h1>Hello, {{ current_user.username }}! Welcome to our extensive video library:</h1>
{% for film in mockfilms %}
{% set ID = film.oid %}
<div>
<a href = {{ film.video }}>
<img src = {{ film.image }} alt = "doh" style = "width:200px;height:200px;border:0;">
</a>
</div>
<div>
">Leave a review here!
{% endfor %}
{% endblock %}
Route:
#app.route('/review/<ID>', methods = ['GET', 'POST'])
#login_required
def review(ID):
form = ReviewForm()
if form.validate_on_submit():
review = Ratings(User_id = current_user.id, Score_given = form.score.data, Film_id = ID)
db.session.add(review)
db.session.commit()
flash('Thanks for your review')
return redirect(url_for('index'))
return render_template('review.html', title='Review Page', form=form)
The following error is what I get when I run it:
File "/home/jc/Desktop/Lokal/DevopsAssig/microblog/Kilfinnan/lib/python3.5/site-packages/werkzeug/routing.py", line 1768, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'review'. Did you forget to specify values ['ID']?
From this I assume that the issue is with the ID variable within this template. My searchings and learnings led me to believe that {% set %} in the index template would let me declare the ID variable and then use it in the dynamic.
Try this:
{% block content %}
<h1>
Hello, {{ current_user.username }}!
Welcome to our extensive video library:
</h1>
{% for film in mockfilms %}
<div>
<a href="{{ film.video }}">
<img src="{{ film.image }}" alt="doh" style="width:200px;height:200px;border:0;" />
</a>
</div>
<div>
<a href="{{ url_for('review', ID=film.oid) }}">
Leave a review here!
</a>
</div>
{% endfor %}
{% endblock %}
Ultimately your solution was quite close, but it is not necessary to use the Jinja set command when you need to pass the variable into url_for() function using the keyword for the parameter. You could still do it using {% set ID = film.oid %} but it would be a bit superfluous.
Try to provide key=value arguments into your url_for function.
Something like this
">Leave a review here!
Also Flask have a great documentation, Flask docs

populate bootstrap dropdown on the base.html using django

Im using django 1.9 and python 3.5 which i'm both really new too, and i'm having trouble populating a bootstrap dropdown which is located in the base.html.
So far i have this:
base.html:
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Events
<b class="caret"></b></a>
<ul class="dropdown-menu">
{% if categories %}
{% for cat in category %}
<li><a href="{% url 'categories' pk=cat.pk %}">
{{ cat.name }}</a></li>
{% endfor %}
{% else %}
There are no categories present.
{% endif %}
</ul>
</li>
views.py:
def categories(request, pk):
category = Category.objects.get(pk=pk)
return render(request, 'categories.html', {'category': category})
urls.py:
url(r'^categories/(?P<pk>\d+)/$', views.categories, name='categories'),
So i want the drop down to display the available categories from the database and then when i click on one it will obviously load up the categories.html displaying the relevant category.
any help would be much appreciated.
Edit: sorry i forgot to say the problem i am having.
Im not getting the drop down populated, and is only giving me the "there is no categories present"
There are a couple of issues here:
Firstly, you don't have any context in your view called categories, yet you're checking for them in your template. Your view function is called 'categories', which might be creating some confusion for you. However, this is not context that is accessible to your view. It's just a function.
Secondly, you're not getting a list of categories (which you could iterate as you are in your template) in your view, you're getting a single category with:
category = Category.objects.get(pk=pk)
# using the get() method means you're requesting a single object
So you need to do something more like:
categories = Category.objects.all()
# here, we're getting a QuerySet (list of objects), rather a single object
Then add the categories to your context. So your view would end up looking like this:
def categories(request, pk):
categories = Category.objects.all()
return render(request, 'categories.html', {'categories': categories})
Also, you'll need to change your iterator to iterate over categories, not category:
{% for cat in categories %}
<li><a href="{% url 'categories' pk=cat.pk %}">
{{ cat.name }}</a></li>
{% endfor %}
So, "categories" variable will never give you "true", while you do not define it, and add it to template context.
Do this in your python code
def categories(request, pk):
categories = Category.objects.all()
return render(request, 'categories.html', {'categories': categories})

Updating single Django model field

I have 3 database model - Semester, Section and Notecard
The Notecard model has a "Known" field that I use to classify the Notecard objects into "piles" as Known (1) or Unknown (0):
class Notecard(models.Model):
notecard_name = models.CharField(max_length=50)
notecard_body = models.TextField()
section = models.ForeignKey(Section)
known = models.BooleanField()
I have two views - known_list and unkown_list that displays the corresponding piles (known_list below for reference):
def known_list(request, section_name):
try:
section = Section.objects.get(section_name__iexact = section_name)
except Section.DoesNotExist:
raise Http404
known_list = Notecard.objects.filter(known=1, section=section)
paginator = Paginator(known_list, 1)
if known_list:
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
known = paginator.page(page)
except (EmptyPage, InvalidPage):
known = paginator.page(paginator.num_pages)
context = RequestContext(request)
return render_to_response('notecards/known.html', {"known": known}, context_instance=context)
else:
url = reverse('notecard_list', kwargs={'section_name': section_name})
return HttpResponseRedirect(url)
This view brings in the section_name from the previous view to display all the Notecard objects that are in the section that was clicked on, and in the known pile.
In the template below, you can see that I paginate the notecards to one a page:
{% extends "base.html" %}
{% block content %}
<h1 class='title'>NoteCards!</h1>
{% for notecard in known.object_list %}
<h1 class='notecard'>{{ notecard.notecard_name }}</h1>
<h3 class='notecard'>{{ notecard.notecard_body }}</h3>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if known.has_previous %}
<a class="navlink" href="?page={{ known.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ known.number }} of {{ known.paginator.num_pages }}
</span>
{% if known.has_next %}
<a class="navlink" href="?page={{ known.next_page_number }}">next</a>
{% endif %}
</span>
</div>
{% endblock %}
urls.py
urlpatterns += patterns('',
url(r'^(?P<section_name>[\w|\W]+)/unknown/$', unknown_list, name="unknown_list"),
url(r'^(?P<section_name>[\w|\W]+)/known/', known_list, name="known_list"),
url(r'^semester/(?P<semester_name>[\w|\W]+)/', section_list, name="section_list"),
url(r'^section/(?P<section_name>[\w|\W]+)/', notecard_list, name="notecard_list"),
url(r'^notecard/(?P<notecard_name>[\w|\W]+)/', notecard_detail, name="notecard_detail"),
url(r'^$', semester_list, name="semester_list"),
)
That said, I would like to add a "Send to Unknown" button that will allow users to send the notecard whose page they are currently on to the unknown pile (Simply changing the known field to = 0, removing the notecard from the pagination list, and moving to the next page in the pagination).
I have tried replicating my new_notecard view which contains a full form of the model, but I was unable to figure out how to update a single field.
I have also tried using queryset.update() but was unable to figure out how to capture the pk from the specific notecard.
I've been trying to figure this out on my own for over a month, but I've been unsuccessful. Thank you in advance.
EDIT:
It seems like my hang up is pulling the pk of the notecard on each page of the pagination. For example, if I am on page 3 of the pagination - when the "Send to Unknown" button is pushed, how do I identify that notecard in my view and update it from known (1) to unknown (0)
you must create a specific view with a specific url to handle this, for example:
# urls.py
url(r'^movetounknown/(?P<notecard_id>[\w|\W]+)/', notecard_move_to_unknown)
# views.py
#require_POST
def notecard_move_to_unknown(request, notecard_id):
notecard = Notecard.objects.get(pk=notecard_id)
notecard.known = False
notecard.save()
return HttpResponseRedirect(request.POST['next'])
# template
{% for notecard in known.object_list %}
<h1 class='notecard'>{{ notecard.notecard_name }}</h1>
<h3 class='notecard'>{{ notecard.notecard_body }}</h3>
<form action="{% url views.move_to_unknown notecard.pk %}" method="post">
<input type="hidden" name="next" value="{% url known_list known.section.section_name %}?page={{known.paginator.number}}"/>
<input type="submit" value="Move to unknown list"/>
</form>
{% endfor %}
You also can pass the notecard id as a post parameter.
The next parameter tells where to go after the change, here I choose the same page of the known list because once the current card is removed the next one is at this index
Capturing the pk of a specific notecard object can be done by defining a specific url for that notecard. For example:-
# urls.py
url(r'^notecard/(?P<notecard_id>\d+)/$',
'notecard',
name='notecard'),
# corresponding views.py
def notecard(request, note_card_id):
notecard = get_object_or_404(Notecard, pk=note_card_id)
template = 'notecard/notecard.html'
template_vars = {'notecard': notecard}
render(request, template, template_vars)
# notecard/notecard.html
<h2>{{ notecard.notecard_name }}</h2>
<p>{{ notecard.notecard_body }}</p>
You can also define a form with the notecard id/pk being a hidden field for submission and updating into your database (and of course, you will need to update your view function correspondingly).
In essence, to update a specific notecard object, you will simply do in your view function (with form submission or, if you prefer, a pure ajax implementation in your listing page) like this
notecard.known = False
notecard.save()

Categories

Resources