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.
Related
Currently working through the Python Crash Course Django section I've got everything but the edit posts page working. I added the edit post link under each post but this error now displays when you try to view the homepage:
Reverse for 'edit_post' with no arguments not found. 1 pattern(s) tried: ['edit_post/(?P<post_id>[0-9]+)/$']
Here is the code I've been using.
from django.db import models
# Create your models here.
class BlogPost(models.Model):
"""A topic the user is learning about"""
title = models.CharField(max_length=200)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""A place for the user to create a blog post"""
return self.title
Views
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogForm
# Create your views here.
def index(request):
"""The home page for Blog"""
return render(request, 'blogs/index.html')
def blogposts(request):
"""Show all blogposts"""
blogposts = BlogPost.objects.order_by('date_added')
context = {'blogposts': blogposts}
return render(request, 'blogs/blogposts.html', context)
def new_post(request):
"""Add a new post"""
if request.method != 'POST':
# No data submitted, create a blank form
form = BlogForm()
else:
# POST data submitted; process data
form = BlogForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:blogposts')
# Display a blank or invalid form
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
current_entry = BlogPost.objects.get(id=post_id)
if request.method != 'POST':
# Initial request; pre-fill form with current entry
form = BlogForm(instance=current_entry)
else:
form = BlogForm(instance=current_entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:index')
context = {'post':post, 'form':form}
return render(request, 'blogs/edit_post.html', context)
URLs
"""Defines URL patterns for blogs"""
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# Page that shows all topics
path('blogposts/', views.blogposts, name='blogposts'),
# Page that displays a single post
path('new_post/', views.new_post, name='new_post'),
# Page for editing a post
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
blogposts.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Blog Posts</p>
<ul>
{% for blogpost in blogposts %}
<h1>{{ blogpost }}</h1>
<p>{{ blogpost.body }}</p>
Edit post
{% empty %}
<li>No blogs have been posted yet</li>
{% endfor %}
</ul>
Create a new post
{% endblock content %}
edit_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Edit post:</p>
<form action="{% url 'blogs:edit_post' post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save Changes</button>
</form>
{$ endblock content %}
You need to pass the id of the blog post you want to edit.
So in your blogposts.html try:
"{% url 'blogs:edit_post' blogpost.pk %}"
I started to learn Django today, but I am stuck at using forms. I have created two forms: /contact and /blog-new. The form at the Contact page is working fine, but the one at /blog-new is redirecting me to the home page after the submission button is pressed and no information is printed in the terminal nor saved in the database.
Code on Github
I appreciate if someone can explain to me what I did wrong as I cannot figure it out. Thank you!
mysite/blog/forms.py
from django import forms
from .models import BlogPost
class BlogPostModelForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['title', 'slug', 'content']
mysite/blog/views.py
from .forms import BlogPostModelForm
def blog_post_create_view(request):
# create objects
# ? use a form
# request.user -> return something
form = BlogPostModelForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = BlogPostModelForm()
template_name = 'form.html'
context = {'form': form}
return render(request, template_name, context)
mysite/blog/models.py
from django.db import models
# Create your models here.
class BlogPost(models.Model):
title = models.TextField()
slug = models.SlugField(unique=True)
content = models.TextField(null=True, blank=True)
mysite/mysite/urls.py
from blog.views import (
blog_post_create_view,
)
urlpatterns = [
..
path('blog-new', blog_post_create_view),
..
]
mysite/templates/form.html
{% extends "base.html" %}
{% block content %}
{% if title %}
<h1>{{ title }}</h1>
{% endif %}
<form method='POST' action='.'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Send</button>
</form>
{% endblock %}
You need to point to right url in action attribute of form.
<form action="/blog-new/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
I think it's not necessary in your case but you could also refactor your view to match the docs.
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import SomeForm
def some_view(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = SomeForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = SomeForm()
return render(request, 'template_name.html', {'form': form})
You need to point to right url in action attribute of form.
That was not actually the solution but something that helped me to figure out what was wrong.
It is not necessary to point to /blog-new/ as . for action will point to the same page, but I have tried with /blog-new/ as action URL and I was surprised to see that /blog-new/ page doesn't exist.
The bug was in mysite/mysite/urls.py for missing a /:
path('blog-new', blog_post_create_view),
It is funny (and annoying) how a symbol like / missing from your code will mess up everything and make you spend hours trying to find a solution as simple as that.
Thank you for your time spend to have a look over my code and try to help me!
I am trying to display a simple form (3 fields) on a webpage using Django but no fields are displaying - see code below.
I've gone through the Django doc, MDN doc, most of the StackOverflow posts here, but it's still not working.
I was able to see, using {% debug %}, that there is no object EmailInput on the page.
At this point, I am not sure what is causing this issue. Any help would be very much appreciated.
Thanks
forms.py
from django import forms
class EmailInput(forms.Form):
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
views.py
from django.shortcuts import render
from .models import journalEntry
from django.http import HttpResponseRedirect
from django.urls import reverse
from journal.forms import EmailInput
def index(request):
post = journalEntry.objects.filter(status__exact='f')
latest_post = journalEntry.objects.filter(status__exact='f').order_by('-created')[:5]
return render(request, 'journal_index.html', context = {'post':post,'latest_post':latest_post})
def email_input(request):
if request.method == 'POST':
form = EmailInput(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('journal-index'))
else:
form = EmailInput()
return render(request, 'journal_index.html',{'form':form})
journal_index.html
{% extends "base_generic.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit"/>
</form>
{% endblock content %}
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='journal-index'),
]
If you want to display it in the index page then you have to send it as a context variable in your index function. And now it will be available in your journal_index.html template file.
def index(request):
post = journalEntry.objects.filter(status__exact='f')
latest_post = journalEntry.objects.filter(status__exact='f').order_by('-created')[:5]
form = EmailInput()
context = {
'post': post,
'latest_post': latest_post,
'form': form
}
return render(request, 'journal_index.html', context = context)
The code from your email_input function is not called anywhere so there is no way this form could be displayed. Also you have to figure out where do you want to display this form. If you don't want to display it together with the stuff from your index page then you would have to create a new template file, add the form there and add a new url path to display that page.
It is because you are not even calling email_input.
you need to bind it to a url like this
urlpatterns = [
url(r'^$', views.email_input),
]
only my Submit button is popping up when i am trying to pass a form.
I even tried just copying the code from the Django website... Still does not work for me.
This is my forms.py
from django import forms
class contactForm(forms.Form):
name = forms.CharField(required=False, max_length=100, help_text='100 max.')
email = forms.EmailField(required=True)
comment = forms.CharField(required=True, widget=forms.Textarea)
This is my views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from .forms import contactForm
def contact(request):
form = contactForm(request.POST or None)
if form.is_valid():
print(request.POST)
context = locals()
return render(request, 'contact/contact.html', context)
def index(request):
return render(request, 'contact/contact.html')
This is my contact.html
{% extends "contact/base.html" %}
{% block content %}
<h1>Contact</h1>
<form method='POST' acion=''> {% csrf_token %}
{{ form.as_p }}
<input type='submit' value='submit form'/>
</form>
{% endblock %}
I really do not know what is wrong with this code...please help! Thanks
ps: I am new to python, maybe i need another version?
You have two views rendering the same template. One of them, contact, passes the form to the template. The other, index, does not, so there is nothing called form in the context and the result will be blank.
I created a panel in open stack. What I want to do is produce a simple page that when loaded it makes a call to get a status and then puts that status (good, bad, warning) in a page with a combo box and have a submit button that when hit gets back to my python code so I can do what I want based on that status.
They way I did it was a form with a ChoiceField. I have a class IndexView (views.APIViews) from open stack I believe. It has a get_data method called where I can go get the data and return a context. I haven't found an example where you set the something in the context passing the status to a form somehow. Like context['status'] = "Good"..
What I get is when the page is loaded get_data is called and I do nothing. The submit button is there but no "Status: (combo box)" I hit Submit and status is called with a POST. form.is_valid() is false and it returns a render with a form created passing in request.POST. This gets a form to appears and I can hit Submit and I get a call to status with a .POST and is_valid is true and it redirects to thanks like I want. It's just that I can't get data into the form in get_data.
Here is my code:
Views.py
from horizon import views
from django import forms
from django.shortcuts import render
from django.http import HttpResponseRedirect
STATUS_CHOICES = (
("GOOD", "Good"),
("BAD", "Bad"),
("COMPROMISED", "Compromised")
)
def thanks(request):
return render(request, 'pinehurst_dashboard/ssa_panel/sent.html')
class SsaForm(forms.Form):
status = forms.ChoiceField(choices = STATUS_CHOICES, label="Status:")
def status(request):
print("STATUS CALLED method=",request.method)
if request.method == 'POST': # If the form has been submitted...
form = SsaForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
print("redirect to THANKS!")
return HttpResponseRedirect('thanks/') # Redirect after POST
else:
print("form.is_valid = false")
else:
print("Requesting form\n")
form = SsaForm(initial = {"status", "BAD"}) # An unbound form
return render(request, 'pinehurst_dashboard/ssa_panel/index.html', {
'form': form,
})
class IndexView(views.APIView):
# A very simple class-based view...
template_name = 'my_dashboard/ssa_panel/index.html'
def get_data(self, request, context, *args, **kwargs):
print("GET_DATA Called", context)
# Add data to the context here...
return context
Urls.py
from django.conf.urls import patterns
from django.conf.urls import url
from openstack_dashboard.dashboards.my_dashboard.ssa_panel import views
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'status/$', views.status),
url(r'thanks/$', views.thanks),
)
nothing in models.py
my_dashboard/ssa_panel/index.html
{% extends 'pinehurst_dashboard/base.html' %}
{% load i18n %}
{% block title %}{% trans "Pinehurst" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("SSA Panel") %}
{% endblock page_header %}
{% block pinehurst_dashboard_main %}
<form action="status/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}