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.
Related
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})
I have been working on a simple forums application for a few weeks now. The main goal of the project is to have sooner written a post and then for the post to be displayed. The project does not utilize user models. For some reason when the user completes the form for their post their post is not displayed. I was wondering if anyone knew why this is happening or if any of y'all have any tips.
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views import generic
from . import forms
# Create your views here.
class ForumForm(generic.CreateView):
template_name = 'forums_simple/forum.html'
form_class = forms.ForumForm
success_url = '/'
def form_vaild(self, form):
self.object = form.save(commit=False)
self.object.save()
return super().form_vaild(form)
urls.py
from django.contrib import admin
from django.urls import path, include
from . import views
app_name = 'forums'
urlpatterns = [
path('', views.ForumForm.as_view(), name='forum')
]
models.py
from django.db import models
# Create your models here.
class Post(models.Model):
message = models.TextField(blank=True, null=False)
created_at = models.DateTimeField(auto_now=True)
forms.py
from django import forms
from . import models
class ForumForm(forms.ModelForm):
class Meta:
model = models.Post
fields = ('message',)
forum.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
{% for message in object_list %}
{{ post.message }}
{% endfor %}
</div>
<div class="container">
<form class="forum_class" action="index.html" method="post">
{% csrf_token %}
{% crispy form %}
<button type="submit" name="big-button"></button>
</form>
</div>
{% endblock %}
You need to add object_list to your context in the view so:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# don't forget to import Post
context['object_list'] = Post.objects.all()
return context
I'm new in python and django, wanted to add a function to delete an employee, along with urls and html, the delete button came out just fine, but it didn't do anything, is there anything I did wrong, I've been researching but couldn't find the solution, please advice, thank you, here's the code:
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.forms import modelformset_factory
from .models import Employee
from .forms import EmployeeForm
def index(request):
'''The home page for employee_record.'''
return render(request, 'employee_records/base.html')
#login_required
def employees(request):
'''Shows all employees'''
employees = Employee.objects.filter(owner=request.user).order_by('full_name')
context = {'employees': employees}
return render(request, 'employee_records/employees.html', context)
#login_required
def employee(request, employee_id):
'''Show a single employee'''
employee = Employee.objects.get(id=employee_id)
# Make sure the employee belongs to the current user.
if employee.owner != request.user:
raise Http404
EmployeeFormSet = modelformset_factory(Employee, fields=('full_name',
'address', 'city', 'state', 'zip', 'email', 'hire_date'), extra=0)
if request.method == 'POST':
form = EmployeeFormSet(request.POST)
employees = form.save(commit=False)
for employee in employees:
employee.save()
return HttpResponseRedirect(reverse('employee_records:employees'))
form = EmployeeFormSet(queryset=Employee.objects.filter(id=employee_id))
context = {'employee': employee, 'form' : form}
return render(request, 'employee_records/employee.html', context)
#login_required
def delete_employee(request):
employee
employee.delete()
return redirect('employees')
urls.py
'''Defines URL patterns for employee_records.'''
from django.urls import path
from . import views
app_name = 'employee_records'
urlpatterns = [
# Home page
path('', views.employees, name='employees'),
# Detail page for a single employee
path('employees/<int:employee_id>/', views.employee, name='employee'),
# Detail page for delete a single employee
path('employee/', views.delete_employee, name='delete_employee'),
# Page for adding a new employee
path('new_employee/', views.new_employee, name='new_employee'),
]
employee.html
{% extends 'employee_records/employees.html' %}
{% load bootstrap3 %}
{% block content %}
{% if employee %}
<form method='POST'>
{% csrf_token %}
{{ form.as_p}}
{% buttons %}
<button input type='submit' class="btn btn-primary">submit</button>
{% endbuttons %}
</form>
<a href="{% url 'employee_records:delete_employee' %}">
{% buttons %}
<button input type='delete' class="btn btn-danger">delete</button>
{% endbuttons %}
</a>
{% endif %}
{% endblock content %}
I think you are confused about the scope of employee. In your delete view, employee does not reference a queryset, or a model. Instead, it references the employee view, which is a function, hence your error. To fix this you will need to execute the query directly in your delete_employee view, which means you will have to pass an id to your view (like you did in the employee view):
#login_required
def delete_employee(request, employee_id):
employee = Employee.objects.get(id=employee_id)
employee.delete()
return redirect('employees')
Don't forget to change your path for this view so the employee_id gets passed to your view:
path('delete_employee/<int:employee_id>', views.delete_employee, name='delete_employee'),
The concept of scope is very important, so I would recommend doing some research on this topic.
The issue is in your this code block:
#login_required
def delete_employee(request):
employee
employee.delete()
return redirect('employees')
Where employee is not an object.
You first have to get the Object of that specific employee then you will be able to delete.
Like:
employee_id = request.POST.get('employee_id')
# or
employee_id = request.GET.get('employee_id')
# whatever the way of sending employee_id
then:
employee = Employee.objects.get(id=employee_id)
employee.delete()
Then it will work.
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
I have a section of my site where an admin can add a widget. However the delete button to delete any current widgets is not working. I have this code implemented else where on my site and it is working.
I copied the same code from the other section of my site where this is being used. The other section of my site which uses this code is a little different in that a post can only be deleted be the user who created it, and the widgets can be delete by any user with the "access_level" field is equal to "admin". However, I am the only admin so it should still work. The page that the widget stuff is displayed on is only accessible if your "access_level" is equal to admin so I don't need to validate whether or not they have the permission before deleting. Please help.
widget_list.html:
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="content">
<div class="widgets-list">
{% for widget in widget_list %}
<h3>{{ widget.name }}</h3>
<h3>{{ widget.widget_order }}</h3>
<div>
<p>{{ widget.body }}</p>
</div>
{% if user.is_authenticated %}
<a class="auth-user-options" href="{% url 'adminpanel:delete-widget' pk=widget.pk %}">Delete</a>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
Adminpanel app views.py:
from django.shortcuts import render
from adminpanel.forms import WidgetForm
from adminpanel.models import Widget
from django.utils import timezone
from django.contrib.auth import authenticate,login,logout
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse,reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import SelectRelatedMixin
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
# Create your views here.
class CreateWidgetView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'index.html'
form_class = WidgetForm
model = Widget
def form_valid(self,form):
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('adminpanel:widgets')
class SettingsListView(ListView):
model = Widget
ordering = ['widget_order']
class DeleteWidget(LoginRequiredMixin,SelectRelatedMixin,DeleteView):
model = Widget
select_related = ('Widget',)
success_url = reverse_lazy('adminpanel:widget')
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
def delete(self,*args,**kwargs):
return super().delete(*args,**kwargs)
Project url spy:
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from accounts import views
from colorsets import views
from colors import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.home,name='index'),
url(r'^accounts/',include('accounts.urls',namespace='accounts')),
url(r'^colorsets/',include('colorsets.urls',namespace='colorsets')),
url(r'^adminpanel/',include('adminpanel.urls',namespace='adminpanel')),
]
Adminpanel app urls.py:
from django.conf.urls import url
from adminpanel import views
app_name = 'adminpanel'
urlpatterns = [
url(r'^widgets/',views.SettingsListView.as_view(),name='widgets'),
url(r'^new/$',views.CreateWidgetView.as_view(),name='create-widget'),
url(r'^delete/(?P<pk>\d+)/$',views.DeleteWidget.as_view(),name='delete-widget'),
]
EDIT: Here is the error I'm getting I forgot to add it.
FieldError at /adminpanel/delete/10/
Cannot resolve keyword 'user_id' into field. Choices are: body, id, name, widget_order
and the traceback points to this:
/Users/garrettlove/Desktop/colors/adminpanel/views.py in get_queryset
return queryset.filter(user_id=self.request.user.id) ...
▶ Local vars
Adminpanel app models.py (widget model):
from django.db import models
from adminpanel.choices import *
# Create your models here.
class Widget(models.Model):
name = models.CharField(max_length=50)
widget_order = models.IntegerField(blank=False,unique=True)
display_name = models.IntegerField(choices=WIDGET_NAME_CHOICES,default=1)
body = models.TextField(max_length=500)
def __str__(self):
return self.name
As your error is saying:
Cannot resolve keyword 'user_id' into field.
And it points to this line:
return queryset.filter(user_id=self.request.user.id)
It's that your queryset model does not have a user_id field. In your DeleteWidget view you have specified model = Widget
and as you see in your Widget model, you have the following fields: body, id, name, widget_order. There is no user_id field.
You need to change your filtering logic. If you want to have a related User model, you should use ForeignKey relation and then you can filter by the User's id.
In your models.py:
from django.contrib.auth.models import User
class Widget(models.Model):
# ...
user = models.ForeignKey(User, on_delete=models.CASCADE)
And then in your DeleteWidget's get_queryset, you can do the following:
return queryset.filter(user__id=self.request.user.id)
# __________________________^
# Note that there is a double underscore here!
# This is because Django uses double underscore for accessing related models in queries.