Not able to perform Update Operation on Django - python

I am making todo application and i am having problem doing the update operation
views.py
def update(request, task_id):
task = Task.objects.get(pk=task_id)
if request.method == 'POST':
form = TaskForm(request.POST or None, instance=task)
if form.is_valid():
form.save()
return redirect('/')
return render(request, 'update.html', {'task': task})
forms.py
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = '__all__'
urls.py
path('update/<int:task_id>', views.update, name='update'),
update.html
{% extends 'base.html' %}
{% block content %}
{% if task %}
<form class="form-inline my-2 my-lg-0" method="POST" >
{% csrf_token %}
<input type="search" class="form-control mr-sm-2" name="task" value="{{task.text}}">
<input type="hidden" name="completed" value="{{task.completed}}">
<button type="submit" class="btn btn-outline-secondary my-2 ">Edit Task</button>
</form>
{% endif %}
{% endblock %}
I am able to get the Value of the selected item in textbox but when i edit it and press Edit Task Nothing happens .

# The url name is update, so your action submit should go to 'update'
<form action="{% url 'update' task_id=task.pk %}" method="POST" class="form-inline my-2 my-lg-0">
…
</form>

Related

Displaying "Like" and "Dislike" buttons if user has liked a post with Django

thank you for taking the time to read this.
I'm working on a project for CS50W in which I have to display a series of posts which users can like and then dislike.
I can successfully display the number of likes but I can't get the "Like" Button to change into "Dislike" once this is done.
Here's the relevant code:
views.py
def index(request):
return render(request, "network/index.html", {
"posts": Post.objects.all().order_by('time'),
"form": NewPost(),
"likes": Like.objects.all(),
})
...
def like(request, post_id):
if request.method == "POST":
#make sure user can't like the post more than once.
user = User.objects.get(username=request.user.username)
#find whatever post is associated with like
post = Post.objects.get(id=post_id)
#access liked values:
if Like.objects.filter(user=user, post=post).exists():
Like.alreadyLiked = True
return HttpResponseRedirect(reverse('index'))
else:
newLike = Like(user=user, post=post)
newLike.alreadyLiked = True
post.likes += 1
post.save()
newLike.save()
return HttpResponseRedirect(reverse('index'))
Then models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
import datetime
class User(AbstractUser):
pass
class Post(models.Model):
text = models.CharField(max_length=127)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="author")
time = models.TimeField(auto_now=False, auto_now_add=True)
likes = models.PositiveIntegerField(default=0)
def __str__(self):
if self.likes == 1:
return f"{self.user} ({self.time}): {self.text} - {self.likes} Like"
elif self.likes == 0:
return f"{self.user} ({self.time}): {self.text} - No Likes"
else:
return f"{self.user} ({self.time}): {self.text} - {self.likes} Likes"
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="users")
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="posts")
alreadyLiked = models.BooleanField(default=False)
def __str__(self):
return f"{self.user} liked {self.post}"
Finally, index.html where the button is displayed.
{% extends "network/layout.html" %}
{% block body %}
<form action="/newPost" method="post" name="newPost">
{% csrf_token %}
{{ form.content }}
<input type="submit">
</form>
{% for post in posts %}
<div id="post{{post.id}}">{{ post }}
{% if likes.post == post and likes.user == user.username %}
<form action="{% url 'dislike' post.id %}" method="post" name="dislike" id="dislikeform">
{% csrf_token %}
<button type='submit' name='dislike' value="{{ post.id }}" class="btn btn-primary">Dislike</button>
</form>
{% else %}
<form action="{% url 'like' post.id %}" method="post" name="like" id="likeform">
{% csrf_token %}
<button type='submit' name='like' value="{{ post.id }}" class="btn btn-primary">Like</button>
</form>
{% endif %}
{% if follows.following == True %}
<form action="{% url 'unfollow' post.user %}" method="post" name="follow">
{% csrf_token %}
<button type='submit' name='follow' value="{{ post.user }}" class="btn btn-primary">Follow</button>
</form>
{% else %}
<form action="{% url 'follow' post.user %}" method="post" name="follow">
{% csrf_token %}
<button type='submit' name='follow' value="{{ post.user }}" class="btn btn-primary">Follow</button>
</form>
{% endif %}
</div>
{% endfor %}
{% endblock %}
My idea is that in the part of the form for liking and disliking, django template's should determine whether or not the logged in user has already liked the post, in which case it will display a Dislike button instead of the Like button. Most importantly this segment:
{% if likes.post == post and likes.user == user.username %}
<form action="{% url 'dislike' post.id %}" method="post" name="dislike" id="dislikeform">
{% csrf_token %}
<button type='submit' name='dislike' value="{{ post.id }}" class="btn btn-primary">Dislike</button>
</form>
{% else %}
<form action="{% url 'like' post.id %}" method="post" name="like" id="likeform">
{% csrf_token %}
<button type='submit' name='like' value="{{ post.id }}" class="btn btn-primary">Like</button>
</form>
{% endif %}
I have a similar issue with the Follow and Unfollow buttons but I feel that if I can implement the first problem's solution I can apply it too.
Figured it out after rethinking the model relationships.
I added a new field to my Post model:
class Post(models.Model):
text = models.CharField(max_length=127)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="author")
time = models.TimeField(auto_now=False, auto_now_add=True)
likes = models.PositiveIntegerField(default=0)
user_likes = models.ManyToManyField(User)
User is now related to post as a ManytoManyField, which allows me to create relationships between these models.
then in views.py:
def like(request, post_id):
if request.method == "POST":
#make sure user can't like the post more than once.
user = User.objects.get(username=request.user.username)
#find whatever post is associated with like
post = Post.objects.get(id=post_id)
newLike = Like(user=user, post=post)
newLike.alreadyLiked = True
post.likes += 1
#adds user to Post
post.user_likes.add(user)
post.save()
newLike.save()
return HttpResponseRedirect(reverse('index'))
I did the same thing for dislike and will try the same for follow and unfollow.
Lastly, in index.html:
{% if user in post.user_likes.all %}
<form action="{% url 'dislike' post.id %}" method="post" name="dislike" id="dislikeform">
{% csrf_token %}
<button type='submit' name='dislike' value="{{ post.id }}" class="btn btn-primary">Dislike</button>
</form>
{% else %}
<form action="{% url 'like' post.id %}" method="post" name="like" id="likeform">
{% csrf_token %}
<button type='submit' name='like' value="{{ post.id }}" class="btn btn-primary">Like</button>
</form>
{% endif %}
Now it's working perfectly.

Django ManyToMany relationship details

I want to build a website in which users can send words to each other using Django. When a user deletes a word, that word will be deleted for only that user. I have a working website; the only problem is when a word is deleted, it is deleted for all users. How can I fix this problem, is it a problem which is related to ManyToMany relationships?
Django word model:
from django.db import models
from datetime import datetime
from django.contrib.auth.models import User
class Word(models.Model):
definition = models.CharField(max_length=350)
turkish = models.CharField(max_length=50)
english = models.CharField(max_length=50)
users = models.ManyToManyField(User)
creator = models.CharField(max_length=50)
def __str__(self):
return self.english
def summary(self):
return self.definition[:50] + "..."
The share view function:
#login_required
def send(request):
users_list = User.objects.all().exclude(username=request.user.username)
user = request.user
small = user.username.title()
send_to_str = request.POST['user']
sent_word_str = request.POST['word']
send_to = User.objects.get(username=send_to_str)
sent_word = Word.objects.get(id=sent_word_str)
if not users_list:
sendmessage = 'You have no friends'
else:
sendmessage = ''
sent_word.users.add(send_to)
words = Word.objects.filter(users=user).order_by('-english')
return render(request, 'intro.html', {'sendmessage': sendmessage, 'words': words, 'small' : small})
The delete view function:
#login_required
def delete(request):
if request.method == 'POST':
current_id = request.POST['word_id']
current_word = Word.objects.get(id=current_id)
current_word.delete()
messages.add_message(request, messages.INFO, 'Succesfully deleted.')
return redirect('translater:home')
else:
return render(request, 'intro.html', {'message': 'there is a problem'})
Redirected to this html:
{% if words %}
<h3 style="color:gray;font-weight:bold">My Word List</h3>
<br>
{% endif %}
{% for word in words %}
<h4 style="color:red">{{ word.english }} / {{ word.turkish }} </h4>
<h4 style="color:green">{{ word.summary }} / {{ word.creator }}</h4>
<br>
<button type="button" onClick="document.getElementById('deleterForm').submit()" class="btn btn-warning">Delete!</button>
<button type="button" onClick="document.getElementById('sharerForm').submit()" class="btn btn-primary">Share!!</button>
<form id="deleterForm" action="{% url 'translater:delete' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="word_id" value="{{ word.id }}">
</form>
<br>
<form id="sharerForm" action="{% url 'translater:share' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="word_id" value="{{ word.id }}">
</form>
<form id="senderForm{{ word.id }}" action="{% url 'translater:send' %}" method="POST">
{% csrf_token %}
{% for user in users_list %}
<input type="submit" name="user" value="{{ user }}">
<input type="hidden" name="word" value="{{ word.id }}">
{% endfor %}
{{ sendmessage }}
</form>
<br>
{% endfor %}

Django : get data and edit in the same form, edit in one place

I've been working to make an edit form where shows data saved in db and user can edit it like jsp model and view. When user click button it shows add form but all the relevant information in db is already filled up in the form, so user can modifying old data and once they click submit button it redirect to main.
I succeeded to display a form when user click edit button but failed to get data.
this is views.py
#login_required
def update_article(request, article_no):
article = get_object_or_404(Article, no=article_no)
if request.method == "POST":
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('blog.views.detail', no=article.no)
else:
form = ArticleForm(instance=article)
return render(request, 'blog/update_article.html', {'form': form})
urls.py
url(r'^update_article/(?P<article_no>[0-9]+)/$', views.update_article, name='update_article'),
update_article.html
{% extends 'blog/base.html' %}
{% block body %}
<form class="form-horizontal" role="form" action="create_article.html" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'blog/form_template.html' %}
<button type="submit" class="button-primary">submit</button>
</form>
list
{% endblock %}
detail.html
This is part of the page send users to update_article.html
<form action="{% url 'blog:update_article' item.no %}" method="post" style="display: inline;">
{% csrf_token %}
<input type="hidden" name="no" value="{{ item.no }}" />
<button type="submit" class="button-primary">edit</button>
</form>
form_template.html
{% for field in form %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<span class="text-danger small">{{ field.errors }}</span>
</div>
<label class="control-label col-sm-2" for="title">{{ field.label_tag }</label>
<div class="col-sm-10">{{ field }}</div>
</div>
{% endfor %}
In update_article views
pass article object with form
return render(request, 'blog/update_article.html', {'form': form, 'article': article})
and then form in html page
<form class="form-horizontal" role="form" action="create_article.html" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'blog/form_template.html' %}
<input class="u-full-width" type="text" name="title" value="{{article.title}}"/>
<textarea class="u-full-width" name="content" value="{{article.content}}"></textarea>
<button type="submit" class="button-primary">등록</button>
</form>
I think this would help your problem
also I guess your action link is not valid

Django - Render view based on search query from search view

I have what is probably a very basic question. I have read through Django forms docs but am still missing something here. I want to have a search bar in one template (search.html) and return the search query in another template (results.html). I have the following so far, using this SO answer as a guide, which returns the following error. Thanks for any help.
Exception Value:
results() missing 1 required positional argument: 'search_id'
urls.py
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^landing/', views.search, name='search'),
url(r'^results/', views.results, name='results'),
]
forms.py
from .models import Apartment
class Apt(forms.ModelForm):
class Meta:
model = Apartment
fields = ('name')
views.py
def search(request):
if request.method == 'POST': #the form has been submitted
form = Apt(request.POST) #bound form
if form.is_valid(): #validations have passed
name = form.cleaned_data['name']
u = Apt.objects.create(name=name)
#REST query will go here.
#commit to database
u.save()
return redirect('results', search_id=u.name)
else: #create an unbound instance of the form
form = Apt(initial={'name':'name'})
#render the form according to the template, context = form
return render(request, 'search/landing.html', {'form':form})
def results(request, search_id):
search_id = request.POST.get('name')
query = get_object_or_404(Apt, pk=search_id)
return render(request, 'search/results.html', {'query':query} )
landing.html
{% extends "base_simple.html" %}
{% block title %}Look up your name{% endblock %}
{% block main_content %}
<!-- Intro Header -->
<header class="intro">
<div class="intro-body">
<div class="container">
<div class="inner cover">
<h1 class="cover-heading">find your name</h1>
<form id="searchform" method="POST" action="" accept-charset="utf-8">
{% csrf_token %}
<input id="apt" type="text" class="form-control" placeholder="Apartment Name" value="{{ Apt.name }}">
<input type="submit" value="Search" class="btn btn-lg btn-default">
</form>
</div>
</div>
</div>
</header>
{% endblock %}
results.html
{% extends "base_simple.html" %}
{% block title %}search results{% endblock %}
{% block main_content %}
<div class='col-sm-6 col-sm-offset-3'>
<div class="row">
<div class="col-sm-12">
{% for q in query %}
<div class="jumbotron">
<h3>{{ q.name }}</h3>
</div>
{% endfor %}
</div>
</div>
<hr/>
</div>
{% endblock %}
in urls you need to change result to
url(r'^results/(?P<search_id>.+)/', views.results, name='results'),
Named groups in the regex are passed as arguments to the view
You should also remove the line search_id = request.POST.get('name') from your results view as the redirect will not contain any POST data

django-why this form is always invalid

i have created a form with minimal fields(for testing) , but it never enters form.is_valid()
Here is the minimal code
in the models.py
from django.db import models
class sample(models.Model):
field1=models.CharField(max_length=100)
field2=models.CharField(max_length=100)
in the forms.py
from django.forms import ModelForm
from app.models import sample
class someform(ModelForm):
class Meta:
model=sample
in the views.py
some imports
def index(request):
return render(request, 'app/index.html')
def contact(request):
if request.method=='POST':
form=someform(request.POST)
if form.is_valid():
field1=form.cleaned_data['field1']
field2=form.cleaned_data['field2']
return HttpResponse("valid")
else:
return HttpResponse("invalid")
else:
form=someform()
return HttpResponse("error")
The problem is , it never enters (if form.is_valid()) . Am i missing something ? please help
in the index.html
<html>
<body bgcolor="#2E9AFE">
<form action="contact" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" id="field1" name="field1">
<input type="text" id="field2" name="field2">
<input type="submit" id="submit" name="submit">
</form></body></html>
First pass your form to index.html, when the request is not POST in views.py:
else:
form=someform()
return render(request, 'index.html', locals())
In template you should make it like this:
<form action="contact" method="POST" xmlns="http://www.w3.org/1999/html">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn">Submit</button>
</form>
When receiving the POST query, Django is looking for the 2 fields of IDs id_field1 and id_field2, litteraly, thus your HTML is to be the following:
<html>
<body bgcolor="#2E9AFE">
<form action="contact" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" id="id_field1" name="field1">
<input type="text" id="id_field2" name="field2">
<input type="submit" id="submit" name="submit">
</form>
</body>
</html>
Another solution is to use the {{ form.as_p }} or {{ form.as_table }} to render the inputs inside or tags automatically.
You could also add {{ form.non_field_errors }}, {{ form.field1.errors }}, and {{ form.field2.errors }} in your current HTML to display the form errors when validation fails.

Categories

Resources