Unable to update CharField - Django - python

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 %}

Related

Django restricting users from updating/deleting other users posts

views.py
#login_required(login_url='/login')
def updatepost(request,pk):
post = Post.objects.get(id=pk)
form = PostForm(instance=post)
if request.method =='POST':
form = PostForm(request.POST, request.FILES, instance=post)
if form.is_valid():
form.save()
return redirect ('mainpage')
context = {'form':form}
return render( request, 'postform.html', context )
postform.html
{% include 'main.html'%}
{% block content %}
{%if user.is_authenticated%}
{% if user.id == post.user.id%}
<div>
<form method="POST" action ="">
{% csrf_token %}
{{form.as_p}}
<input type="Submit" value ="Submit"/>
</form>
</div>
{%endif%}
{%endif%}
{% endblock content %}
I am trying to restrict user who is logged in - from updating , deleting other users posts.
However when I Try to use {% if user.id == post.user.id%} , the page becomes blank even for the user who is editing his own post. The same goes for deleting.
It works on mainpages - where posts are displayed (it hides edit and delete buttons).
What is the reason that the post is not showing inside the template ?
I don't understand that even {{post.user}} in postform.html does not appear , neither on deleteform etc. - why this data of objects of a post is not being sent to postform.html ?
You should change the context to access the post instance from your template.
context = {'form': form, 'post': post}
You can only access the context values from the templates. So pass the ones you want to use while you are returning a response.

Django | Redirect View after "liking" without scrolling

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.

URL Displaying Wrong Form and View in Django

I am attempting to render a form where the only field is a dropdown. I have the form, view, .html, url all set up. But when I access this url, it shows a different form and view and I suppose also a different .html. I am so confused on why this is happening as it had been working fine for quite some time so I obviously changed something.
forms.py
#this is the form for the dropdown
class ManifestDropDown(forms.Form):
References = forms.ModelChoiceField(queryset=Orders.objects.values_list('reference', flat=True).distinct(),
empty_label=None)
manifest_references.html
<!--html for dropdown-->
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST" action="manifest">
{% csrf_token %}
{{ reference_list }}
<button type="submit" class="btn btn-primary" name="button">Submit</button>
</form>
</div>
{% endblock %}
views.py
#view for dropdown
def manifest_references(request):
if request.method == 'POST':
if form.is_valid():
reference_id = form.cleaned_data.get('References')
form.save()
query_results = Orders.objects.all()
reference_list = ManifestDropDown()
context = {
'query_results': query_results,
'reference_list': reference_list,
}
return render(request, 'manifest_references.html', context)
urls.py
url(r'^manifest_references', manifest_references, name='manifest_references'),
base.html
<!--showing the link to this url-->
...
<a class="dropdown-item" href="{% url 'manifest_references' %}">Edit Manifests</a>
When I access the url above - instead of showing the manifest_references view with the dropdown, it immediately jumps to a different view manifest which is referenced as the action in the manifest_references.html. Please someone help me determine why this is happening.

Comment isn't getting deleted

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>

Upload any file in django

I was trying to create a function for upload file in Django. First time I running my code, it's cannot upload a file. So, I was trying to improve my code and what I got its error. I thought the error it's weird because I always used that and I never get an error. I'll show my code.
models.py
class UploadFiles(models.Model):
File = models.ImageField(upload_to = 'Images/', default='Images/')
views.py
def upload_file(request):
if request.method == 'POST':
form = UploadFile(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
form = UploadFile()
return render(request, 'girl/upload.html', {'form': form})
forms.py
class UploadFile(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField
upload.html
{% extends 'girl/base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
<p>Return to home</p>
{% endblock %}
error:
django.urls.exceptions.NoReverseMatch: Reverse for '/' not found. '/' is not a valid view function or pattern name.
urls.py
url(r'^cat/upload/$', views.upload_file, name='uploads')
Any help would be appreciated.
This is the line the error is
<p>Return to home</p>
Change it to
<p>Return to home</p>
And in your forms to
class UploadFile(forms.ModelForm)
class Meta:
model=UploadFiles
fields ='__all__'

Categories

Resources