(I searched this error on StackOverflow and tried the solution ideas, but hey did not work.)
In my Django Project, I tried to add a like button to my article detail page. If users like the article, they click the like button and return the same article page. I saw this video on Youtube and wrote the same code by changing some values according to my project. But I encountered an error which says Field 'id' expected a number but got ''.
I read some solutions on Stackoverflow and tried to delete migrations files (except init.py), and then I wrote python manage.py makemigrations and then python manage.py migrate. Unfortunately, it did not work. I want to share my code, so maybe you can give me some solution ideas.
model.py
class Article(models.Model):
author = models.ForeignKey("auth.User", on_delete = models.CASCADE, verbose_name="Kullanıcı")
title = models.CharField(max_length = 50, verbose_name="Başlık")
content = RichTextField()
created_date = models.DateTimeField(auto_now_add = True, verbose_name="Oluşturma Tarihi")
likes = models.ManyToManyField(User, related_name='blog_post')
urls.py
urlpatterns = [
path('dashboard/',views.dashboard, name ="dashboard"),
path('addarticle/',views.addarticle, name ="addarticle"),
path('article/<int:id>',views.detail, name ="detail"),
path('update/<int:id>',views.updateArticle, name ="update"),
path('delete/<int:id>',views.deleteArticle, name ="delete"),
path('',views.articles, name ="articles"),
path('comment/<int:id>',views.addComment, name ="comment"),
path('like/<int:id>',views.LikeView, name ="like_post"),
]
views.py
def LikeView(request, id):
post = get_object_or_404(Article, id=request.POST.get("post_id"))
article.likes.add(request.User)
return HttpResponseRedirect(reverse("detail", args=[str(id)]))
detail.html (In this html, I show the content of the article and who published it, comments and likes)
<form action="{% url 'article:like_post' article.id %}" method="POST">
{% csrf_token %}
<button type="submit" name="post_id" value="{{ article_id }}" class="btn btn-primary btn-sm">
<i class="bi bi-hand-thumbs-up"></i> Like
</button>
</form>
You can see likes table in this photo I can like a post in admin page. But obviously thats not appropriate for users.
And thats the error page I encountered.
The value is article.id, not article_id:
<button type="submit" name="post_id" value="{{ article.id }}" class="btn btn-primary btn-sm">
That being said, it does not make much sense to pass it both as URL parameter and as POST parameter. You can simply make a form without the post_id, and use the URL parameter instead:
from django.shortcuts import redirect
from django.views.decorators.http import require_POST
#require_POST
def LikeView(request, id):
post = get_object_or_404(Article, id=id)
post.likes.add(request.user)
return redirect('detail', id)
Then the form simply looks like:
<form action="{% url 'article:like_post' article.id %}" method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-sm">
<i class="bi bi-hand-thumbs-up"></i> Like
</button>
</form>
Note: One can use the #require_POST decorator [Django-doc]
to restrict the view to only be accessible for a POST request.
Related
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.
I am working on a website using Django. I'm having a difficult time playing around codes, how do I get the ID of a user without passing a primary key (id, pk) in the URL. My code below does not give me a solution to getting the ID of a particular user. When I print (user) it prints the current user logged in. Is there a way to get the ID of other users?
def home(request):
p=Profile.object.filter(user=request.user)
u=p.user
send_request=FriendRequest.objects.filter(from_user=p.user)
def send_request(request, id):
user=get_object_or_404(User, id=id)
frequest=FriendRequest.get_or_creat(from_user=request.user, to_user=user).first()
path('home', home_view, name='home')
<a href='{% url 'site:send_request' profile.user.id %}'>Add friend<a>
Use a form with POST method and send the user_id as a parameter but hidden to the user.
<form method="post" action="{% url 'your_url' %}">
{% csrf_token %}
<input type="hidden" name="user_id" value="{{ user_id }}" />
<button type="submit">Add Friend</button>
</form>
You can access the parameter in the view like this
request.POST.get('user_id')
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.
This is becoming very frustrating, like all of my Django form endeavors have been thus far...
I have a search bar form that is supposed to send the user to a url '/project/search/<query>/' and the url works fine if I type in a url but my form is not mapping correctly. I am implementing this first in the search results page, which will still have a search bar, and whenever I type in a value to the search bar I get redirected to '/project/search/'. Where have I gone wrong? I have spent a solid two days on this to no avail.
I am really struggling with this and I have no idea what I am doing wrong. I wish I had at least an error or something to fix but this is just not working.
Here is my form class and view:
from django import forms
class SearchForm(forms.Form):
search_string = forms.CharField(initial='Search Article Text',max_length=100)
def search(request, search_query):
form = SearchForm()
context = RequestContext(request)
search_string = search_query.replace('_',' ')
search_terms = search_query.split('_')
search_results = Article.objects.all()
for term in search_terms:
search_results = search_results.filter(article__icontains=term)
context_dict = {
'search_string':search_string,
'search_results':search_results,
'form':form,
}
if request.method == 'POST':
form = SearchForm(request.POST)
context_dict['form'] = form
if form.is_valid():
search_string = form.cleaned_data['search_string']
search_query = search_string.replace(' ','_')
###return HttpResponseRedirect(reverse('search', args=(search_query,)))
search_url = '/project/search/' + search_query + '/'
return HttpResponseRedirect(search_url)
return render_to_response('search.html', context_dict, context)
The html:
<form action='/beacon/search/' class="navbar-form navbar-right" method='POST'>
<div class="form-group">
{% csrf_token %}
{{ form.search_string }}
</div>
<input type='submit' value='Submit' class='btn btn-default'/>
</form>
I don't really understand your question. You're getting redirected because that's what you've told the view to do: you explicitly return an HttpResponseRedirect. If you don't want to redirect, don't do that.
Ok after troubleshooting for probably 5 or so days I have realized what my issue was (I also had a little help from the Django Users Google group).
I am answering this in case anybody also has my problem in the future btw. I'm obviously not an expert on the forms part of Django.
This all had to do with the actual HTML writeup I had. In my form tag the action was to '/project/search/' which just redirected me to that URL because django thought /project/search/ was different than project/search/query . Therefore all I needed to do for this part was change the action to refer to any URL that would validate my search view- so I picked /project/search/search_query/ but anything after /project/search/ would have worked.
My second issue was with my input. I needed to include a name in my input -'search_string'- so my search view would understand what values the form itself was carrying.
Therefore my html in the end looks like:
<form action='/beacon/search/search_query/' class="navbar-form navbar-right" method='POST'>
<div class="form-group">
{% csrf_token %}
<input type="text" name='search_string' class="form-control" placeholder="Search Article Text"/>
</div>
<!--<button type="submit" class="btn btn-default" value='Submit'>Submit</button>-->
<input type='submit' value='Submit' class='btn btn-default'/>
</form>
Credit to Branko Majic to helping my on Dj Users Group as well. Seriously.
I followed this guide to extend registration in Django and it all seemed working until I clicked register and nothing happens. I checked in the command line with sql and table exists as per specification, however when I try to view items with UserProfile.objects.all() it returns empty list. Seems like nothing is getting sent anywhere upon form submission.
I get no errors, so bit confused on what is the issue.
models.py
def user_registered_callback(sender, user, request, **kwargs):
profile = UserProfile(user = user)
profile.first_name = str(request.POST["first_name"])
profile.last_name = str(request.POST["last_name"])
profile.city = str(request.POST["city"])
profile.country = str(request.POST["country"])
profile.save()
user_registered.connect(user_registered_callback)
forms.py
from registration.forms import RegistrationForm
class CustomRegistrationForms(RegistrationForm):
first_name = forms.CharField(label ="First Name")
last_name = forms.CharField(label ="Last Name")
city = forms.CharField(label ="City")
country = forms.CharField(label ="Country")
urls.py
url(r'^accounts/register/$', RegistrationView.as_view(form_class = CustomRegistrationForms),
name = 'registration_register', kwargs=dict(extra_context={'next_page': '/services/'})),
url(r'^accounts/', include('registration.backends.simple.urls'))
) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
registration_form.html
<form method="post" action="" class="wide">
{% csrf_token %}
..sample form
<label for="id_username">Username:</label>
{% if form.username.errors %}
<p class="errors">{{ form.username.errors.as_text }}</p>
{% endif %}
{{ form.username }}
<input type="submit" class="btn btn-default btn-sm" value="Register"></input>
</form>
Remove action from form tag completely. This will result in sending the form request as HTTP-POST to itself, in this case "/accounts/register". But this is not your main problem.
According to the documentation (https://django-registration.readthedocs.org/en/latest/forms.html) after reading I'm pretty sure you are missing the fields required by registration.forms.RegistrationForm which you are subclassing. The backend will take care of these and reject the given values. Because you are only showing username and its errors in your template the other validation errors will never show up.
Add the required fields to your form and try again. You may want to simply render it through
{{ form.as_p }}