Django | Redirect View after "liking" without scrolling - python

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.

Related

Getting id of instance in form and save in it

I am building a Blog App and I am working on a feature in which A user can report comment so I created another model for storing reports so i am saving which comment is reported But I placed report form in detail view so report form will be below the comment in post detail page, In which I am not getting the comment id when reporting.
models.py
class Blog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=1000)
class Comment(models.Model):
commented_by = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.CharField(max_length=1000)
class ReportComment(models.Model):
reported_by = models.ForeignKey(User, on_delete=models.CASCADE)
reported_comment = models.ForeignKey(Comment, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
views.py
def blog_detail_page(request, blog_id):
post = get_object_or_404(Blog, pk=blog_id)
if request.method == 'POST':
reportform = CommentReportForm(data=request.POST)
if FlagCommentForm.is_valid():
form = reportform.save(commit=False)
# Saving in this line
flagForm.reported_comment = reportform.id
form.reported_by = request.user
form.save()
return redirect('home')
else:
reportform = CommentReportForm()
context = {'reportform':reportform, 'post':post}
return render(request, 'blog_detail_page.html', context)
blog_detail_page.html
{{post.title}}
{% for comment in post.comment_set.all %}
{{comment.body}}
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ reportform }}
</table>
<button type="submit">Save</button>
</form>
</div>
{% endfor %}
What have I tried :-
I have also tried by using loop like :-
comments = post.comment_set.all()
for com in comments:
if request.method == 'POST':
......
if reportform.is_valid():
....
......
......
form.reported_by = com
But it always saved the first comment id.
Then I tried by request.POST method, Like :-
comment_ID = request.POST['comment_id']
But is showed MultiValueDictKeyError error.
I have tried many times But the id of comment is not saving with report instance.
You will need to add the primary key of the comment to the form, or to the URL where you submit the form to. For example as a hidden form element:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="comment_id" value="{{ comment.pk }}">
<table>
{{ reportform }}
</table>
<button type="submit">Save</button>
</form>
An alternative is to make a URL where you report a comment to with:
urlpatterns = [
path('comment/<int:comment_id>/report', some_view, name='report-comment')
]
then you can submit the form to that view with:
<form method="post" action="{% url 'report-comment' comment_id=comment.pk %}" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ reportform }}
</table>
<button type="submit">Save</button>
</form>

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>

How to access data of Django ManyToMany Field?

I want to Create a Like Functionality in Home page of my Social media Website. I am using ManyToManyField for Storing Likes on Particular post as shown in models.py. In my home page I have list of Posts and I want to check weather a Posts in already Liked by Current Logged in User or not.
In my views.py I am using
post = Posts.objects.filter('likes')
if post.likes.filter(id=request.user.id).exists():
models.py
class Posts(models.Model):
title = models.CharField(max_length=250, blank=False)
content = models.CharField(max_length=15000,
help_text="Write Your thought here...")
likes = models.ManyToManyField(User, blank=True)
views.py
def home(request):
post = Posts.objects.filter('likes')
print('Thats just Test', post)
if post.likes.filter(id=request.user.id).exists():
print("Already Exixts")
is_liked = False
context = {
'all_posts': all_posts,
'is_liked': is_liked,
}
return HttpResponse(template.render(context, request))
hometemplte.html: (Only Like Button)
<form action="{% url 'like_post' %}" method="POST">
{% csrf_token %}
{% if is_liked %}
<button type="submit" name="like" value="{{ post.id }}" class="btn upvote liked">Liked</button>
{% else %}
<button type="submit" name="like" value="{{ post.id }}" class="btn upvote">Upvote</button>
{% endif %}
</form>
If you want to get data of the ManyToMany field, for backwards mapping you need to use related_name parameter while declaring the model.
So your attribute will be:
likes = models.ManyToManyField(User, blank=True, related_name='likes')
Your query to check if the particular post has been liked by the user or not is:
post.likes.filter(id=request.user.id).exists():
Update
The issue in your case is you are retrieving multiple posts in a single line:
Posts.objects.filter('likes'), which returns a query set.
You need to fetch a particular post and then check if the user likes the post or not.
post = Posts.objects.all()[0] will not throw any error.

Unable to update CharField - Django

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

Categories

Resources