I have an error stating Method not Allowed (POST). But I have a Post method in my view. That's the only method that I have on my view.
class AddOrRemoveFollower(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
#import ipdb; ipdb.set_trace()
other_user = get_object_or_404(User, pk=kwargs['pk'] )
current_user = request.user
if current_user is other_user:
messages.success(request, 'You cannot follow yourself')
return redirect(reverse('myfriendship:friends'))
if current_user not in Follow.objects.followers(other_user):
Follow.objects.add_follower(request.user, other_user)
messages.success(request, 'You are now following a user')
return redirect(reverse('myfriendship:friends'))
else:
Follow.objects.remove_follower(request.user, other_user)
messages.success(request, 'You decided to unfollow this user')
return redirect(reverse('myfriendship:friends'))
urls.py
url(r'^AddOrRemoveFollower/(?P<pk>\d+)/$',
views.AddOrRemoveFollower.as_view(),
name='AddOrRemoveFollower'),
shell
WARNING:django.request:Method Not Allowed (POST): /myfriendship/AddOrRemoveFollower/1/
WARNING:django.server:"POST /myfriendship/AddOrRemoveFollower/1/ HTTP/1.1" 405 0
html
<form class="right" method="POST" action="{% url 'myfriendship:AddOrRemoveFollower' user.id %}">
{% csrf_token %}
<input type="hidden" name="course_id" value="{{user.id}}">
<input class="btn btn-primary btn-sm red darken-2" type="submit" value="{% can_follow user request.user %}">
</form>
You try to post to the detail, POST method in class base view allowed only without pk. Try PUT or PATCH.
Related
I am trying to allow users to deactivate their accounts on my django website. Here is what I have tried:
views.py
from django.contrib.auth.models import User
#login_required
def deactivate_user(request, username):
context = {}
try:
user = User.objects.get(username=username)
user.is_active = False
user.save()
context['msg'] = 'Profile successfully disabled.'
except User.DoesNotExist:
context['msg'] = 'User does not exist.'
except Exception as e:
context['msg'] = e.message
return render(request, 'index.html', context=context)
urls.py
path('deactivate-user/<slug:username>', deactivate_user, name='deactivate_user'),
base.html
<form action="{% url 'users:deactivate_user' slug=username.slug %}" method="post">
{% csrf_token %}
<button type="submit" class="active">Yes, Deactivate</button>
<button type="button" data-dismiss="modal">Cancel</button>
</form>
I am getting a NoReverseMatch error Reverse for 'deactivate_user' with keyword arguments '{'slug': ''}' not found. 1 pattern(s) tried: ['users/deactivate\\-user/(?P<username>[-a-zA-Z0-9_]+)$'] Have tried a few different parameters in the template but can't get anything to work.
You are saying
<form action="{% url 'users:deactivate_user' slug=username.slug %}" method="post">
slug isn't a keyword in your pattern, its a type, similar to <int:pk>, it should be username=username.slug
The form is always sending a Get request instead of a Post which has been explicitly added using method = "POST". So, not able to persist the data to db. I have just started with Django so, any help will be appreciated.
Below are the code snippets:
create_order.html
<form method="POST" action="{% url 'home' %}">
{% csrf_token %}
{{form}}
<input class="btn btn-primary btn-sm" type="submit" name="Submit">
</form>
urls.py
urlpatterns = [
path('', views.dashboard, name='home'),
path('products/', views.product, name='products'),
path('customer/<str:cust_id>/', views.customer, name='customer'),
path('create_order/', views.create_order, name='create_order'),
]
views.py
def create_order(request):
form = OrderForm()
if request.method == 'POST':
print("In Post", request.method)
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
print("In else", request.method)
print(form.is_valid())
if form.is_valid():
form.save()
return redirect('/')
context = {'form' : form}
return render(request, 'accounts/create_order.html', context)
terminal output
In else GET False
You are making a POST request to the wrong view. It should be the create_order view, so:
<form method="POST" action="{% url 'create_order' %}">
{% csrf_token %}
{{ form }}
<input class="btn btn-primary btn-sm" type="submit" name="Submit">
</form>
Note that you should not validate the form in case of a GET request, since then you only render the form. So the view logic should be:
def create_order(request):
if request.method == 'POST':
print("In Post", request.method)
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = OrderForm()
context = {'form' : form}
return render(request, 'accounts/create_order.html', context)
Try to add form action method in your HTML file
<form action="" method="post">{% csrf_token %}
{{ form}}
<input type="submit" value="Submit Feedback" />
</form>
</div>
I have problem similar to this one: Django form data lost on making login required on post
I want answer to be added if user is logged in otherwise redirect user to login page, let him login and then add his answer. My problem is that I lose content of the form when redirecting to login page.
These are my views:
def question(request, question_id):
question = get_object_or_404(Question, pk=question_id)
form = AnswerForm()
return render(request, 'questions/question.html', {'question': question, 'form' : form},)
#login_required
def answer(request, question_id):
question = get_object_or_404(Question, pk=question_id)
form = AnswerForm(request.POST) if request.method == 'POST' else AnswerForm()
if form.is_valid():
answer = form.save(commit=False)
answer.author = request.user
answer.question = question
answer.save()
return HttpResponseRedirect(reverse('question', args=(question.id,)))
Form:
<form method="POST" action="{% url 'answer' question.id %}">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Odpowiedz">
</form>
Form in login template:
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="next" value="{{request.GET.next}}" />
<input type="submit" value="login" />
</form>
I don't know if something more than url can be passed by using next.
#login_required decorator automatically adds a next GET parameter to the LOGIN_URL, so that user is redirected back to the same page the login was triggered from. Right now, you're triggering it from the answer view, so user will come back directly to answer view. POST Data is lost whenever a redirect occurs, so there's no way you can get the data except for temporarily saving it in cookies or redirecting the user to question page after login.
Implementation 1
POST Data is not saved but the user gets redirected to QuestionView
from django.shortcuts import redirect, reverse
...
...
def answer(request, question_id):
if not request.user.is_authenticated:
return redirect("%s?next=%s" % (settings.LOGIN_URL, reverse('question-view-name'))
...
...
Implementation 2
POST Data is saved to the session and then retrieved after login. I haven't tried it and it required you to serialize POST data to string. Also, requires django.contrib.sessions in INSTALLED_APPS and django.contrib.sessions.middleware.SessionMiddleware in your MIDDLEWARE. Checkout https://data-flair.training/blogs/django-sessions/ for how to set, create and delete session variables.
from django.shortcuts import redirect, reverse
...
...
def answer(request, question_id):
if not request.user.is_authenticated:
request.session['form_data'] = YourSerializerFunctionToSerializeFormData(request.POST)
# must retuern a string, use json.dumps() to convert a dictionary to string
return redirect("%s?next=%s" % (settings.LOGIN_URL, reverse('answer-view-name', args=[question_id]))
data = None
if request.method == 'GET':
if 'form_data' in request.session:
data = request.session['form_data']
del request.session['form_data'] # Delete the key once done
else:
data = request.POST
...
form = AnswerForm(data) if data else AnswerForm()
...
...
Hope it helps.
I am passing a some information to view function by submitting a form and view requires has #login_required decorator. Here is the template where i'm passing email ID using a from
<form action="{% url 'become_booster' %}" method="post">
{% csrf_token %}
<input type="hidden" name="email" value="{{ profile_user.email }}" />
<div class="form-group">
<div class="col-md-12 col-sm-12">
<input type="submit" class="btn btn-success btn-sm" value="Become a Booster">
</div>
</div>
</form>
Here is the view function
#login_required
def become_booster(request):
if request.method == "POST":
email = request.POST.get('email')
user = CustomUser.objects.filter(email= email)[0]
tiers = Tiers.objects.filter(user=user)
form = SubscriptionForm
return render(request,'select_tier.html',{'tiers':tiers,'form':form})
This is working fine when the user logedin already. When user didn't login, #login_required sends them to login and when it comes back request.method is no longer POST. It no longer has that email info. Can someone help me with this. Thanks!
#login_required decorator is used to available that function to registered user who are actually logged in or send to login page or registration page. if you remove #login_required from your view function it will be available for unregistered and all type of users.
Try this,
from django.shortcuts import *
#login_required(login_url='become_booster')
def become_booster(request):
if request.method == "POST":
email = request.POST.get('email')
user = get_object_or_404(CustomUser, email=email)
tiers = get_list_or_404(Tiers, user=user)
form = SubscriptionForm
return render(request,'select_tier.html',{'tiers':tiers,'form':form})
elif request.method == 'GET':
# Something like this
# return render(request, 'your_template.html', {'profile_user': user_object_which_contains_email})
I am using a custom user model for my Django project and I can log in via /admin/ perfectly fine. But when I go to /accounts/login and try to log in, it just bounces me back to the login page without logging in. I am using django-registration-redux with the simple backend.
Via logging I discovered that the error happens in this method in django.contrib.auth.__init__.py:
def get_user(request):
"""
Returns the user model instance associated with the given request session.
If no user is retrieved an instance of `AnonymousUser` is returned.
"""
from .models import AnonymousUser
user = None
try:
#
# EXCEPTION THROWN ON BELOW LINE
#
user_id = _get_user_session_key(request)
backend_path = request.session[BACKEND_SESSION_KEY]
except KeyError:
pass
else:
if backend_path in settings.AUTHENTICATION_BACKENDS:
backend = load_backend(backend_path)
user = backend.get_user(user_id)
# Verify the session
if hasattr(user, 'get_session_auth_hash'):
session_hash = request.session.get(HASH_SESSION_KEY)
session_hash_verified = session_hash and constant_time_compare(
session_hash,
user.get_session_auth_hash()
)
if not session_hash_verified:
request.session.flush()
user = None
return user or AnonymousUser()
Any ideas? /accounts/register/ performs as expected, although I have overridden RegistrationView. Perhaps I have to do the same thing for logging in?
Login.html
{% extends "base.html" %}
{% load staticfiles %}
{% block body_block %}
<link href="{% static 'css/signin.css' %}" rel="stylesheet">
<div class="container">
<div class="jumbotron">
<h1 class="display-3" align="center">Login</h1>
</div>
<form method="post" action=".">
{% csrf_token %}
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Username</label>
<input type="text" name="email" id="id+username" class="form-control" placeholder="Username" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="id_password" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit" value="Submit">Login</button>
</form>
Not a member?
Register
</div>
<p>
</p>
{% endblock %}
Urls.py
class MyRegistrationView(RegistrationView):
success_url = '/'
form_class = UserProfileRegistrationForm
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def register(self, form):
logging.debug("THIS IS MY REGISTER")
new_user = form.save(commit=False)
new_user.set_password(form.cleaned_data['password1'])
new_user.save()
login(self.request, new_user)
logging.debug("Logged in")
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=self.request)
logging.debug("After signals")
return new_user
urlpatterns = [
url(r'^', include('base.urls')),
url(r'^admin/', admin.site.urls),
url(r'^accounts/register/$', MyRegistrationView.as_view(), name="registration_register"),
url(r'^accounts/password/change/$', MyRegistrationView.as_view(), name="auth_password_change"),
url(r'^accounts/password/change/done/$', MyRegistrationView.as_view(), name="auth_password_changed"),
url(r'^accounts/', include('registration.backends.simple.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
EDIT:
I have a temporary fix of throwing a view into login in urls.py. Something tells me this is extremely dirty but it seems to work... for now. I'm open to better alternatives.
url(r'^accounts/login/$', my_view, name="login"),
def my_view(request):
if request.POST:
username = request.POST['email']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return render(request, 'index.html', {})
# Redirect to a success page.
else:
# Return an 'invalid login' error message.
pass
else:
return render(request, 'registration/login.html', {})
Try using {{ form }} in your login template, instead of rendering the fields manually. This can show whether the problem is in your template or elsewhere.
In this case, I think that the form fields should be username and password, not email and password as you have.
<input type="text" name="username" id="id_username" class="form-control" placeholder="Username" required autofocus>
<input type="password" name="password" id="id_password" class="form-control" placeholder="Password" required>