I made a comment model for a blog and I wanted to give the user a way to delete the comment so I made a function based view for it but it didn't work so I decided to use a class based view but both of the views give the same error. the only thing that happens is that the url gets a ? after it and the page just refreshes as it is. The function based and class based views are both given below
func based
def comment_delete(request, pk):
comment_to_delete=get_object_or_404(comment,pk=pk)
if request.method=='POST':
post_url=comment_to_delete.content_object.get_absolute_url()
comment_to_delete.delete()
messages.success(request, 'Your comment has been deleted')
return HttpResponseRedirect(post_url)
context={
'comment':comment_to_delete
}
return render(request, 'blog/confirm_delete.html', context)
class based
class DeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = comment
success_url = '/'
def test_func(self):
comment= self.get_object()
if self.request.user == comment.user:
return True
return False
html of confirm page
{% extends 'blog/base.html' %}
{% block content %}
<form>
<p>are you sure you want to delete {{ comment }}</p>
<input type="submit" value="confirm" >
</form>
{% endblock %}
models.py
class comment(models.Model):
post=models.ForeignKey(Blog, on_delete=models.CASCADE)
user=models.ForeignKey(User, on_delete=models.CASCADE)
content=models.TextField(max_length=160)
timestamp=models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{}-{}'.format(self.post.title,str(self.user.username))
def get_absolute_url(self):
return reverse('comment', kwargs={"pk": self.pk})
You need to add a post request to your form. Post requests need tokens to protect from Cross Site Request Forgeries. Normally a token is passed with every post request.
<form method="POST">
{% csrf_token %}
<p>are you sure you want to delete {{ comment }}</p>
<input type="submit" value="confirm" >
</form>
The problem is in your template, not your views. You need to add method="post" to the form to do a POST request, and add {% csrf_token %} to prevent a CSRF error.
<form method="post">
{% csrf_token %}
<p>are you sure you want to delete {{ comment }}</p>
<input type="submit" value="confirm" >
</form>
Related
My success_url for my class based delete view does not work for some reason.
in views.py
# allows a user to delete a project
class DeletePost(DeleteView):
template_name = 'user_posts/post_delete.html'
model = Post
# return to the all posts list
success_url = reverse_lazy('posts_list')
# make sure the user is looking at its own post
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if not obj.user == self.request.user:
raise Http404("You are not allowed to Delete this Post")
return super(DeletePost, self).dispatch(request, *args, **kwargs)
in urls.py:
path('list/', PostsListView.as_view(), name="posts_list"),
path('create-post/', CreatePostView.as_view(), name="post_create"),
path('update-post/<int:pk>', UpdatePost.as_view(), name="post_update" ),
path('delete-post/<int:pk>', DeletePost.as_view(), name="post_delete")
in the HTML file:
{% extends 'base.html' %}
{% block content %}
<form action="." method="POST" style="width:80%;">
{% csrf_token %}
<h3>Do You want to delete this post: "{{ object.title }}"</h3>
<input class="btn btn-primary" type="submit" value="Confirm"/>
Cancel
</form>
{% endblock content %}
whenever I click ok to delete a specific project, it doesn't return to the list of posts for:
image of the error on the webpage
you have not this URL indeed:
forum-posts/delete-post/
actually, you forgot to specify an integer indicating the post_id that must be deleted. for example:
forum-posts/delete-post/1/
I'm making a simple blog app. I have added the ability to "like" a post on your feed. However, the only way I can figure out closing a view is by returning some form of redirect. The problem is, if the post you're "liking" is halfway down the page, I don't want it to reset the zoom to the top of the page again. Is there a way simply to redirect to the same page without affecting zoom?
Here's my post model:
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="author")
likes = models.ManyToManyField(User, related_name="likes", blank=True)
def like(self, post):
self.likes.add(post)
def unlike(self, post):
self.likes.remove(post)
I have the following setup in Views:
#login_required
def like(request, pk):
post = Post.objects.get(id=pk)
Post.like(post, request.user)
return HttpResponseRedirect(reverse('Home'))
#login_required
def unlike(request, pk):
post = Post.objects.get(id=pk)
Post.unlike(post, request.user)
return HttpResponseRedirect(reverse('Home'))
Here's how I'm calling the Views from my URLs:
path('like/<int:pk>', views.like, name='Like'),
path('unlike/<int:pk>', views.unlike, name='Unlike'),
I'm using a form on my template to trigger the URL:
{% if user in post.likes.all %}
<form action="{% url 'Unlike' post.pk %}" method="POST">
{% csrf_token %}
<button type="submit" value="{{ post.id }}" class="unlike">UNLIKE</button>
</form>
{% else %}
<form action="{% url 'Like' post.pk %}" method="POST">
{% csrf_token %}
<button type="submit" value="{{ post.id }}" class="like">LIKE</button>
</form>
{% endif %}
Is there something I can change? I'm assuming there's something I'll need to change or add under "return" in my view functions?
One way to do this would be adding an anchor tag to each like button that uses the post ID, then when redirecting to the post from your view, include #pk at the end of the post URL to direct to that ID anchor down the page.
This is my first time using Django and I am very simply trying to save text to the database. I have created the table inputs in the database.
I am getting the following error;
Error - Page not found (404)
My code is as follows;
Models.py
from django.db import models
class Input(models.Model):
waist = models.IntegerField(default=0)
height = models.IntegerField(default=0)
def __unicode__(self):
return "{0} {1} {2}".format(
self, self.waist, self.height)
forms.py
class InputForm(forms.ModelForm):
class Meta:
model = Input
fields ={
'waist',
'height'
}
views.py
def InputView(request):
if request.POST:
form = InputForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('account/input')
else:
form = InputForm()
args = {'form' : form}
return render(request,'accounts/input.html', args)
urls.py
url(r'^input/$',views.InputView, name='view_input')
input.html
{% extends 'base.html' %}
{% block head %}
<title> Edit Profile </title>
{% endblock %}
{% block body %}
<div class="container">
<h1> Enter Body Details </h1>
<br>
<br>
<form action="account/input" method="post">
{% csrf_token %}
<ul>
{{form.as_ul}}
</ul>
<input type="Submit" name="submit" value="submit"/>
</form>
</div>
{% endblock %}
If any one can help it would be greatly appreciated.
HttpResponseRedirect('account/input')
you need to add one more '/' to the beginning like
HttpResponseRedirect('/account/input')
Another way to do it is to use reverse() so if you change the URL you don't have to change your code and you avoid mistakes entering the URL.
Instead of
HttpResponseRedirect('/account/input')
use
HttpResponseRedirect(reverse('view_input'))
remember to add the import
from django.urls import reverse
Hi Guys
I started coding in Django and i just wanted to make an 9gag-Clone.
I followed some Tutorials and acctualy made a Blog. But when i "upload" Images it allways take the default value.
So here is my Html:
{% extends "posts/post_base.html" %}
{% load bootstrap3 %}
{% block post_content %}
<h3 class="title">Poste Some Memes here</h3>
<form action="{% url 'posts:create' %}" method="POST">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="posten" class="btn btn-primary btn-large">
</form>
{% endblock %}
Here is my Views.py:
class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
fields = ('title','picture','group')
model = models.Post
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
and at least my models.py:
class Post(models.Model):
user = models.ForeignKey(User,related_name='posts')
created_at = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=30,default='Titel')
picture= models.ImageField(upload_to=settings.MEDIA_ROOT, default='/static/img/default.png')
title_html = models.CharField(max_length=30,default='Titel', editable = False)
group = models.ForeignKey(Group,related_name='posts',null=True,blank=True)
def __str__(self):
return self.title
def save(self,*args,**kwargs):
self.title_html =misaka.html(self.title)
super().save(*args,**kwargs)
def get_absolute_url(self):
return reverse('posts:single',kwargs={'username':self.user.username,'pk':self.pk})
class Meta:
ordering = ['-created_at']
#unique_together = ['user','title','bild']
urls.py and other htmlfiles work correctly.
everything was makemigrated and migrated
I just need to know why it dont save the Images, or dont upload it.
Just replace
<form action="{% url 'posts:create' %}" method="POST">
with
<form action="{% url 'posts:create' %}" method="POST" enctype="multipart/form-data>
Uploaded image are at self.request.FILES
self.object.picture = self.request.FILES or self.request.FILES.get('key')
self.object.save()
You can POST data in self.request.POST and file in self.request.FILES
Both answers where right so couldn't pick them bouth.
So here is the solution:
Added
enctype="multipart/form-data"
to my HTML-Form
AND
added
self.bild = self.request.FILES['bild']
to my CreatePost
First of all I'm glad to be here, I read you lately and i found useful answers here.
This is my first post so please be kind with me, I'm a newbie in programming.
So, I'm writing my 1st web application in Django - a todo app and I don't know how to write the function that does this this. I found something in Django docs and in other related discussions but it doesn't work.
Here's my code:
#models.py
class Task(models.Model):
user = models.ForeignKey(User)
task = models.CharField(max_length=200)
initialized_at = models.DateTimeField(auto_now_add=True)
due_date = models.DateField(default=datetime.now)
done = models.BooleanField(default=False)
def __unicode__(self):
return self.task
#views.py
def edit_task(request, id):
if request.method == 'POST':
task_to_edit = Task.objects.get(pk=task_id)
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm()
return render(request, 'todo/edit_task.html', {'form': form})
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
#edit_task.html
{% block content %}
<form action="/edit_task/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
When I submit the updated form I get this error:
Page not found (404)
Request Method: POST
Request URL: hxxp://127.0.0.1:8000/edit_task/
Using the URLconf defined in jbz.urls, Django tried these URL patterns, in this order:
^admin/
^$ [name='index']
^(?P<task_id>\d+)/$
^(?P<task_id>\d+)/$
^add-task/$
^delete-task/(?P<task_id>\w+)/$
^edit_task/(?P<id>\w+)/$
^done/(?P<task_id>\d*)/$
The current URL, edit_task/, didn't match any of these.
and the root urls.py looks like:
url(r'', include('todo.urls'))
#edit_task.html
{% block content %}
<form action="/edit_task/{{task.id}}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
Notice how I added {{task.id}} expression in <form action="/edit_task/{{task.id}}" method="post">
IMPORTANT NOTE: Substitute {{task.id}} to whatever variable accomplishes this in your template.
The reason why you get the error is because edit_task/ is not getting the other part, task_id to match the regular expression:
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
UPDATE: Also your edit_task view has potential errors as well>
def edit_task(request, id):
task_to_edit = Task.objects.get(pk=id)
if request.method == 'POST':
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm(instance=task_to_edit)
# you don't pass any task variable to the view so the form view
# won't know which task to edit, you'll have to handle that
return render(request, 'todo/edit_task.html', {'form': form, 'task':task_to_edit})
Note: I corrected the code in the view a little. Now the task_to_edit is passed also to the Form to fill the fields when the view is requested via GET. Notice that in order to access to this view, the url in the browser should look like this http://www.example.com/edit_task/2
If other wise you try to access http://www.example.com/edit_task without passing the id you'll get Error 404.
Hope this helps!
I think your pattern for edit task expects an id - task name. Try changing your URL pattern:
'^edit_task/(?P<task_id>\w+)/$'
to
'^edit_task/$'
or providing the task id that you want to edit.
Just add name space to your url and according update your template.
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task', name= "edit_task")
#edit_task.html
{% block content %}
<form action="{% url 'edit_task' task_id %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}