How to increment counter on button click using Django - python

New to Django, and I'm stuck on a problem. I have several buttons on a page, each is an instance of a simple Color object I created. The object has attributes of 'name'(string),'hex'(string), and 'count'(integer). I want to be able to keep track of how many times each button is pressed; so, for example, if someone presses the button associated with 'Red,' it will Post to the database that the 'count' attribute for Red should increment by 1.
This is basically how the 'vote' function works in the app they show in the Django documentation, but I cannot figure out how to apply it to my program, even though mine is simpler. Any advice is appreciated. Please let me know if I've posted enough code to determine the issue.
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from .models import Color
### function in question ###
def detail(request, colorname):
bodybg = colorname
colorslist = Color.objects.all()
colorcount = 0
for color in colorslist:
if colorname == color.hex:
colorcount = color.count
colorCounterObj = get_object_or_404(Color, pk=colorcount)
selected_color = colorCounterObj.choice_set.get(pk=request.POST['choice'])
selected_color.count += 1
selected_color.save()
context = {
'bodybg' : bodybg,
'colorslist' : colorslist,
'colorcount' : colorcount,
}
template = loader.get_template('colortime/detail.html')
return HttpResponse(template.render(context, request))
<!-- HTML on my index page, where the buttons are. Makes a list of buttons in different colors, that works just fine. Not sure if my 'formaction' is worded properly or really even functional -->
<body>
<center>
{% if colorslist %}
<ul>
{% for color in colorslist %}
<li ><h3 class='button' style='background-color:{{ color.hex }};' formaction="{% url 'colortime:detail' color %}" method="post" name='choice'>{{ color.name }}</h3></li>
{% endfor %}
</ul>
{% else %}"
<p>No colors here.</p>
{% endif %}
</center>
</body>
Right now the error I'm getting is:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/color/0000FF/
Raised by: colortime.views.detail
No Color matches the given query.
The url varies slightly based on which button I press but they all do this.
Edit: Models.py and Urls.py below
from django.urls import path
from . import views
app_name = 'colortime'
urlpatterns = [
path('', views.index, name='index'),
path('<str:colorname>/', views.detail, name='detail'),
]
from django.db import models
from django import forms
# Create your models here.
class Color(models.Model):
hex = models.CharField(max_length=6)
name = models.CharField(max_length=50)
count = models.IntegerField(default=0)
def __str__(self):
return self.name

Related

Class based views does not render HTML in template-Is context missing?

I started to work with class based views, but the codes that I've written initially does not render in the template when I use class based views. The data that is in note.title (see template) simply does not show up when I use class based views.
When I change back to function based views and refresh the page, the HTML code in the template shows up without any problems. Could someone explain what causes this error?
I've read something about context not been found by the template but I don't really understand what it means and how context resolves the issue.
Thanks in advance!
views.py
from multiprocessing import context
from django.shortcuts import render
import notes
from .models import Notes
from django.http import Http404
from django.views.generic import ListView, DetailView, CreateView
# Create your views here.
class NotesCreateView(CreateView):
models = Notes
fields = ["title", "text"]
succes_url = "/smart/notes"
class NotesListView(ListView):
model = Notes
context_objects_name = "note"
template_name = "notes/notes_list.html"
class NotesDetailView(DetailView):
model = Notes
context_object_name = "note"
# def list(request):
# all_notes = Notes.objects.all()
# context = {'notes': all_notes}
# return render(request, 'notes/notes_list.html', context)
# def detail(request, pk):
# try:
# note = Notes.objects.get(pk=pk)
# except Notes.DoesNotExist:
# raise Http404("This note doesn't exist")
# context = {'note': note}
# return render(request, 'notes/notes_detail.html', context)
urls.py
from django.urls import path
from . import views
app_name = "notesApp"
urlpatterns = [
path('notes', views.NotesListView.as_view(), name="notes.list"),
path('notes/<int:pk>', views.NotesDetailView.as_view(), name="notes.deta"),
path("notes/new", views.NotesCreateView.as_view(), name="notes.view"),
# path('notes', views.list, name="notes.list"),
# path('notes/<int:pk>', views.detail, name="notes.deta"),
]
template
{% extends 'base.html' %}
{% block content %}
<h1 class="my-5">This are the notes:</h1>
<div class="row row-cols3 g-2">
{% for note in notes %}
<div class="col">
<div class="p-3 border">
<a href="{% url 'notesApp:notes.deta' pk=note.id %}" class="text-dark text-decoration-non">
<h3>{{notes.title}}</h3>
</a>
{{note.text|truncatechars:10}}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
You have to use precisely what you set in context_objects_name. So if you want to loop through Notes objects in ListView, then you have to set your view to:
class NotesListView(ListView):
model = Notes
context_objects_name = "notes" # PLURAL
Then in template leave everything as is. Well, maybe you want to change {{notes.title}} to {{note.title}}, because it is inside the for loop.

Django form not rendering? (No Model)

So my Django form is not rendering in the html.
all I'm able to see is the Get Rank text.
I'm not sure if it's because I don't have a model or maybe it's something wrong with my html?
If you need to see anything else let me know not sure what's wrong, I also tried just doing it all inside of the home function but then it doesn't render the html at all.
Side question - Also I only plan on grabbing the users name, and the tag outside their name ("JohnDoeNA#1") so I probably use a get method correct?
EDIT: Fixed the button not working now only thing not rendering is the form. (Mis-spelling)
Updated Code to be correct.
views.py:
from urllib import response
from django.shortcuts import render
from django.http import HttpResponse
import requests
from .forms import SearchUser
import json
# Create your views here.
def index(response):
return render(response, "main/base.html")
def home(response):
form = SearchUser()
data = requests.get(
'https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/ReallyBlue/NA1?api_key=RGAPI-ee8fcdce-05c5-4ad4-b909-8efa722b1134')
userid = data.json()['puuid']
return render(response, "main/home.html", {
'form': form,
'userid': userid,
# 'mmr': apidata['rank']
})
forms.py:
from django import forms
class SearchUser(forms.Form):
name = forms.CharField(label="Name", max_length=200)
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("home/", views.home, name="home")
]
home.html:
{% extends 'main/base.html'%}
{% block content %}
<h2>Valorant Ranked Checker</h2>
<form method="post" action="/home/">
{{form}}
<button type="submit", name="search">
Get rank
</button>
</form>
<p><strong>{{userid}} - {{mmr}}</strong></p>
{% endblock %}
base.html:
<!DOCTYPE html>
<head>
<title>Blue's Valorant Ranked Checker</title>
</head>
<body>
<div id="content", name="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
You have two main issues here:
You were rendering your base template as your root directory (base.html) and therefore Django's template inheritance wasn't working correctly. You'll want to render the child template (the one that includes extends) if you want template inheritance to work properly.
You need to pass your Django form (SearchUser) to the render function of the view
I recommend making these changes:
====================
Remove reference to the index view in your urls.py as we don't need it. Instead, use your home child template as your root view:
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.home, name="home")
]
====================
Remove the no longer needed index function from views.py. You'll also want to pass reference to your form (SearchForm) inside of Django's render shortcut function.
views.py:
from urllib import response
from django.shortcuts import render
from django.http import HttpResponse
import requests
from .forms import SearchUser
import json
# Create your views here.
def home(response):
data = requests.get(
'https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/ReallyBlue/NA1?api_key=RGAPI-APIKEY')
userid = data.json()['puuid']
return render(response, "main/home.html", {
'form': SearchUser(), # include reference to your form
'userid': userid,
# 'mmr': apidata['rank']
})
def search(response):
form = SearchUser()
return render(response, "main/home.html", {"form": form})
Your view function that renders the form and the form template must match. form also must be in your context.
Put the form in the home.html and change the home view like so:
def home(response):
form = SearchUser()
return render(response, "main/home.html", {'form': form})

How does one pass arguments from the URL to a view before rendering a new page?

I am creating a stock portfolio app. The user has a list of stocks each of which has a link which looks something like 'http://127.0.0.1:8000/search/symbol=TSLA'. What I want to do is pass the stock symbol 'TSLA' to one of my views and simply print that string on the next page (for now).
What I have done so far (did not include it in the code below) is to simply have some method in my SearchPageView called get_symbol and I tried to get the url from there and in my search.html template, I tried accessing that via {{ view.get_symbol }}. But this displays nothing.
My set-up:
views.py:
class SearchPageView(TemplateView):
template_name = 'search.html'
urls.py:
from django.urls import path, re_path
from .views import SearchPageView
urlpatterns = [
path('search/<string>', SearchPageView.as_view(), name='search_stock'),
]
search.html:
{% extends 'base.html' %}
{% block content %}
{% endblock content %}
I know there's nothing above, all i'm asking for is how to pass the string 'TSLA' to my view then to 'search.html' then I can do what I need to do with it. I appreciate any help.
Change your urls.py by this
path('search/<symbol>', SearchPageView.as_view(), name='search_stock'),
In views.py
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
class SearchPageView(ListView):
template_name = 'your_template.html'
def get_queryset(self):
self.publisher = get_object_or_404(YOUR_MODEL_NAME, name=self.kwargs['symbol'])
return YOUR_MODEL_NAME.objects.filter(symbol=self.symbol)
I consider your model field name is symbol.
You can try like this:
from django.shortcuts import render
def page_view(request):
# recheck how to get data you want pass in html from this view
return render(request, 'search.html', {
'symbol': request.DATA.get('symbol'),
})
and in url change to this:
urlpatterns = [
path('search/<string>', page_view, name='search_stock'),
]
and in search.html you will have {{ symbol }} variable from def page_view

Django: Auto suggest in text field

I'm trying to work out how to have suggestions in a text field using Django (1.11). I've been going through the documentation of autocomplete-light but so far I've not been able to figure out my use case. The documentation on that package is not easy to understand for a total noob :)
I want a text field that gives suggestions as you type, were the suggestions come from the database.
E.g. if it's a list of food items the user types in 'C' and it suggest Chicken and Crisps as they have been entered by someone earlier. I also want the user to be able to enter Cheese even though it hasn't been entered before.
The suggestion "algorithm" just has to check if what has been entered matches the first characters of already existing items.
Here is a boiled down version of the django project:
urls.py
from django.conf.urls import url
from django.contrib import admin
from testapp.views import TestView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'$',TestView.as_view())
]
models.py
from django.db import models
class TestModel(models.Model):
name = models.CharField(max_length=120)
def __str__(self):
return self.name
forms.py
from django import forms
from .models import TestModel
class TestFormClass(forms.ModelForm):
class Meta:
model = TestModel
fields = ('__all__')
views.py
from django.shortcuts import render
from django.views.generic import CreateView
from .forms import TestFormClass
class TestView(CreateView):
form_class = TestFormClass
template_name = 'template.html'
success_url = "/"
template.html
<html>
<header><title>This is title</title></header>
<body>
Enter something <br>
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
</body>
</html>
I'm hoping someone has a relatively simple solution to add the this code, at the moment I'm not worried about authentication or anything, just looking for a basic solution.
You can make use of django-autocomplete-light

Django: Images/Absolute URLS from not displaying in html

I have a block of code on my template which does not show up on my html nor does it give any error on Chromes console. I am trying to display a list of images which when clicked takes you to the detail of that image.
Here is the key part of my HTML(base.html):
<div class="container-fluid">
<h2>Popular</h2> #only this shows up
{% for obj in object_list %}
<img src = "{{ obj.mpost.url}}" width="300"><br>
<a href='/m/{{ obj.id }}/'> {{obj.username}} </a><br/>
{% endfor %}
</div>
views.py:
from django.shortcuts import render,get_object_or_404
from .models import m
# Create your views here.
def home(request):
return render(request,"base.html",{})
def m_detail(request,id=None):
instance = get_object_or_404(m,id=id)
context = {
"mpost": instance.mpost,
"instance": instance
}
return render(request,"m_detail.html",context)
def meme_list(request): #list items not showing
queryset = m.objects.all()
context = {
"object_list": queryset,
}
return render(request, "base.html", context)
urls.py:
urlpatterns = [
url(r'^$', home, name='home'),
url(r'^m/(?P<id>\d+)/$', m_detail, name='detail'),#issue or not?
]
models.py:
class m(models.Model):
username = "anonymous"
mpost = models.ImageField(upload_to='anon_m')
creation_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return m.username
Thank you so much for your time. :)
I assume the problem is the fact that you don't have a url at all for the meme list, so either you're showing the home view and need to move the code from the meme_list view into your home view, or you need to make a url for the meme_list (and navigate to that new url instead)

Categories

Resources