Django ManyToMany relationship details - python

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

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.

Not able to perform Update Operation on Django

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>

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

Passing data view-template-view in django

I'm handling input file in my project and passing processed text to another html for user approvement
def vm_to_csv_upload(request):
if request.method == "POST":
some code here
br_work_string = re.sub('\\n', '<br>', work_string)
page_text = 'Here\'s what gonna be uploaded to crowdin:<br><br><br>' + br_work_string + '<br><br><br>Is that okay?'
return render(request, 'upload_crowdin_check.html', {'page_text': page_text, 'csv_text': work_string})
On this page i show passed data:
<body>
<div id="text_check">
{% autoescape off %}
{{ page_text }}
{% endautoescape %}
</div>
<form action="/crowdin_approve/" method="POST" value={{ csv_text }} id="csv">
{% csrf_token %}
<input type="submit" class="btn btn-xs btn-danger" value="Okay">
</form>
</body>
And trying to pass it to another view to process it again.
def crowdin_approve(request):
if request.method == "POST":
return HttpResponse(request.POST)
else:
return HttpResponse('nope')
But only thing i get is csrfmiddlewaretoken. What am i doing wrong? How should i pass {{ csv_text }} value to view? Thx.
You can pass the content of csv_text using an hidden input field:
<form action="/crowdin_approve/" method="POST" id="csv">
{% csrf_token %}
<input type="hidden" name="csv_text" value="{{ csv_text }}">
<input type="submit" class="btn btn-xs btn-danger" value="Okay">
</form>
Then you can access it in the view this way:
def crowdin_approve(request):
if request.method == "POST":
csv_text = request.POST.get('csv_text', None)

Displaying view variables in template with Django?

I'm fairly new to Django, and am working on a project where I use forms to get a user to enter a stock symbol and then using urllib I pull the data from Yahoo and return it. However, I'm not sure how to do this.
Here is my forms.py:
class Search(forms.Form):
search = forms.CharField()
Here is my views.py:
def search(request):
context = RequestContext(request)
if request.method == 'POST':
search = Search(data=request.POST)
if search.is_valid():
success = True
subject = search.cleaned_data['search']
sourceCode = urllib2.urlopen("http://finance.yahoo.com/q/ks?s="+subject).read()
pbr = sourceCode.split('Price/Book (mrq):</td><td class="yfnc_tabledata1">')[1].split('</td>')[0]
else:
print search.errors
else:
search = Search()
return render_to_response('ui/search.html', {"search":search}, context)
This is the form I use to get users input (it has some bootstrap styling):
<form class="navbar-form navbar-right" role="search" action="/search/" method="POST">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="Enter stock symbol" name="search">
</div>
<button type="submit" value="Save" class="btn btn-primary">Submit</button>
</form>
And finally here is my search.html file where I'd like to display the data:
{% extends 'ui/base.html' %}
{% block title %} {{ search.search.value|upper }} {% endblock %}
{% block body_block %}
<div class="container">
<h2>{{ search.search.value|upper }}</h2>
<h2>{{ I'd like to display 'pbr' (as definied in my views.py) here }}</h2>
{% endif %}
</div>
{% endblock %}
What I's like to do is take the pbr from my views.py and display it in my templates. Anyone know if I can do this? Thanks.
Build a result dictionary in your view as:
result = {}
if search.is_valid():
success = True
subject = search.cleaned_data['search']
sourceCode = urllib2.urlopen("http://finance.yahoo.com/q/ks?s="+subject).read()
pbr = sourceCode.split('Price/Book (mrq):</td><td class="yfnc_tabledata1">')[1].split('</td>')[0]
result['pbr'] = pbr
result['search'] = search
and return this result as:
return render_to_response('ui/search.html', {"result":result}, context)
In your template now you can access the pbr as:
<h2>{{ result.search.value|upper }}</h2>
<h2>{{ result.pbr }}</h2>

Categories

Resources