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')
Related
Ive created a Django application where you add jobs and Im fully able to add new jobs but I can update them for some reason? The update feature isn't working and I don't know why??
<form action='/update_job/{{job.id}}' method="POST">
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
{% csrf_token %}
Title: <input type='text' value="{{job.job}}" name='job'>
Description: <input type='text' value="{{job.description}}" name='description'>
Location: <input type='text' value="{{job.location}}" name='location'>
<input type='submit'>
</form>
def update_job(request, job_id):
errors = Job.objects.job_validator(request.POST, job_id)
if job.creator.id != request.session['user_id']:
messages.error(request, "This isn't yours to edit!")
if len(errors):
for key, value in errors.items():
messages.error(request, value)
return redirect(f'/edit_job/{job_id}')
job = Job.objects.get(id=job_id)
job.job = request.POST['job']
job.description = request.POST['description']
job.location = request.POST['location']
job.save()
return redirect('/main')
Page not found (404)
Request Method: POST
Request URL: http://localhost:8000/update_job/2
Using the URLconf defined in Python_Exam.urls, Django tried these URL patterns, in this order:
register
login
logout
main
job_link
job/create
jobs/<int:job_id>/view
jobs/<int:job_id>/delete
jobs/<int:job_id>/edit
jobs/<int:job_id>/update_job
The current path, update_job/2, didn't match any of these.
You swapped the primary key and the update_job, it is:
<form action="/jobs/{{ job.id }}/update_job" method="POST">
…
</form>
You however might want to use the {% url … %} template tag [Django-doc] to determine the URL.
(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.
I found several similar answers, but I could not solve the problem (maybe I searched wrong) anyway.
I'm trying to do the following:
Filter a result by getting the value of "q" where is the input containing the value to search
Add the "q" value in the url, like "/search?q=test"
Copy the url above and from there get the filtered result
My problem so far is:
The value of "q" is only added in the url after another search, ie the url contains "q" with the previous search value, which is bad
I can not access the url and have the results filtered, since when I enter this url, a new request object with no value for "q" is created, so I get a ValueError
So far what I've done is:
template
<form method="POST" action="{% url 'blog:post_search' %}?q={{ query }}" class="form-inline">
<div class="md-form my-0">
<input name="q" class="form-control form-control-sm mr-3 w-75" type="text" placeholder="Pesquisar" aria-label="Search">
</div>
<button class="btn btn-outline-white btn-sm my-0" type="submit">GO</button>
{% csrf_token %}
</form>
urls.py
urlpatterns = [
# ....
path('search', views.post_search, name='post_search'),
]
views.py
def post_search(request):
template = "blog/post_search.html"
query = request.POST.get('q')
if query:
posts = Post.objects.filter(title__icontains=query)
else:
posts = Post.objects.all()
context = {'posts': posts, 'query': query}
return render(request, template, context)
You are confusing POST and GET methods here. Query parameters in the url are typically only used with get requests.
So in your form, you can change this:
<form method="POST" action="{% url 'blog:post_search' %}?q={{ query }}" class="form-inline">
to
<form action="{% url 'blog:post_search' %}" class="form-inline">
The default method for a html form is GET, and named inputs will automatically be included in the action url by the browser when you submit the form. So you should not have a querystring in the from action attribute action='/search' is enough.
In the view you access url parameters from request.GET instead of request.POST.
def search(request):
query = request.GET.get('q')
I am very new in Python and Django. A am trying to make app but I have an issue.
Can anyone help me, please xD
I can't get id of authenticated user...
I tried it in this way, and many other ways...
views.py
class CreateProfile(CreateView):
template_name = 'layout/add_photo.html'
model = Profile
fields = ['image', 'user']
html
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username"> #Here has to be field filled in with logged in user
<input type="file" name="image">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Save Changes</button>
</div>
</div>
</form>
And when I'm starting app, and want to change/add picture, I can do it for anyone from my database, not only for logged in user.
enter image description here
Thanks for patience and help!
In the Django ClassBasedViews you can get your user's id as self.request.user.id and in your template as {{ user.id }}
To check if someone is authenticated you can use self.request.user.is_authenticated() and in your template {% if user.is_authenticated %} .. {% endif %}
class CreateProfile(CreateView):
template_name = 'layout/add_photo.html'
model = Profile
fields = ['image', 'user']
# For example, if you want to return to a certain user
# profile (which requires url adjustments to take a Primary Key)
def get_success_url(self):
user_id = self.request.user.id # Get user_id from request
return reverse_lazy('git_project:user_profile', kwargs={'id': user_id})
I added django.contrib.auth.views.login everywhere in my webpage, for that I had to load a templatetag (that returns the AuthenticationForm) in my base.html. This templatetags includes the registration/login.html template.
The login is working ok but I want it to redirect the users to the same page they are before login. Now, it redirects me to /wherever_i_am/login wich shows registration/login.html with the 'login ok' or 'login fails' messages but without the rest of base.html.
I have followed django documentation and a few SO questions like this but I cannot redirect correctly. I have modified the next variable but it doesn't seem to work (next={{ request.get_full_path }} redirects me to /wherever_i_am/login ...again)
Have you tried something similar? any ideas?
UPDATE1
Now, the question could be something like: Do I have to declare my own login view if I want to include the login form everywhere in my web page?
Thank you.
Found answer:
Change settings.LOGIN_REDIRECT_URL in your settings.py,
below code is copy from django:
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = settings.LOGIN_REDIRECT_URL
...
The below allows redirects the user to the page they were attempting to access after they log in, but without having to write a custom view. It contains all the code you need to add to make it work. (As an aside, not all the TEMPLATE_CONTEXT_PROCESSORS are needed, but if you set a value to it explicitly you overwrite the defaults so need to re-add them.)
settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
"django.core.context_processors.static",
)
urls.py
from django.contrib.auth.views import login, logout
...the other imports for your app ...
urlpatterns = patterns('',
(r'^login/$', login, {'template_name':'login.html'} ),
(r'^logout/$', logout,{'template_name':'logout.html'}),
...the other urls for your app...
)
login.html
<html>
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
{{form}}<br/>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</html>
logout.html
<html>
<p>You are logged out. To log in again, click here.</p>
</html>
views.py
#login_required(login_url="/login/")
def view1(request):
....this is a view you want to protect with security...
#login_required(login_url="/login/")
def view1(request):
....this is a view you want to protect with security...
I used something like this with default login view:
{% if form.errors %}
<p class="error">Sorry, that's not a valid username or password</p>
{% endif %}
<form action="{% url login %}" method="post">
{% csrf_token%}
<label for="username">User name:</label>
<input type="text" name="username" value="" id="username">
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
</form>
# or if it's not declareв шт urls:
<form action="{% url django.contrib.auth.views.login %}?next={{ request.get_full_path }}" method="post">
everything worked fine.
PS: are you absolutely sure that "context_processors.request" is included in settings? Forgetting to include it is a common problem.
UPD: As far as I know, there are no way to make default login view to redirect on failed login (It just doesn't work that way).
Still i may be wrong
Finally I created a login view that calls django.contrib.auth.views.login internally.
I'd suggest to pass a previous url as a parameter within the url:
/accounts/login/?next=my_previous_url
and then use this value in a view
request.next
{{request.get_full_path}} gives you the current path, so is normal that the redirect points to the same place, change it for {{next}} in your registration/login.html template
Adding up to #Sean's anwer. Code for iterating over each form field in order to write field error above the miss-typed field.
So, in Sean's login.html is the existing code:
login.html
<html>
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
{{form}}<br/> <!-- I can change! -->
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</html>
Now what you should do is replace the "I can change!" line (4th line in the above code snippet) with following code:
{% 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">{{ field.label_tag }}</label>
<div class="col-sm-10"> {{ field }}</div>
</div>
{% endfor %}
You can use this snippet for other forms too (for example registration). :)
I stumble upon this question in my process of implementing Facebook Account Linking. The problem is the same: how do I correctly redirect django after successful login?
Remember this: your settings.py contain LOGIN_REDIRECT_URL right? So, that's the only place where you should do the logic of redirecting. To do that, first connect this signal (put this in your views.py):
def after_success_login(sender, user, request, **kwargs):
alt = request.GET.get('account_linking_token')
if alt is not None:
uri = request.GET.get('redirect_uri')
request.session['fb_redirect_uri'] = uri
user_logged_in.connect(after_success_login)
The logic above may not reflect your case, but the idea is setting up a session variable to be read in the route defined as LOGIN_REDIRECT_URL.
So, in my case:
def index(request):
if not request.user.is_authenticated():
form = SignUpForm()
return render(request, 'index.html', {'form': form})
else:
# FB ACCOUNT LINKING!
if 'fb_redirect_uri' in request.session:
redirect_uri = request.session['fb_redirect_uri']
del request.session['fb_redirect_uri']
to = '{}&authorization_code={}'.format(redirect_uri, request.user.username)
print('to', to)
return redirect(to)
That's it!
Add a decorator before the view function should be OK.
#login_required
see here for details