Submit without refresh in django - python

i have a html form and submit button (It adds or removes relations in manytomanyfield "users"):
{% if user in event.users.all %}
<form action="/event/{{ event.id }}/" method="GET">
<input type="hidden" value="{{ event.id }}" name="remove">
<input type="submit" value="Remove">
</form>
{% else %}
<form action="/event/{{ event.id }}/" method="GET">
<input type="hidden" value="{{ event.id }}" name="add">
<input type="submit" value="Add">
</form>
in views.py:
def show_event(request, event_id):
...
event = get_object_or_404(Event, id=event_id)
user = request.user
if request.GET.get('add'):
event.users.add(user)
event.save()
if request.GET.get('remove'):
event.users.remove(user)
event.save()
return render(request, 'events/event.html', {'event':event, 'user':user,})
This function works fine, but the page refreshes after submitting form. I need no refresh and i need to change button text just like "Follow" button in Twitter. I tried to use some jquery\ajax but i dont exactly understand how it should work. Can please anyone explain how to do it? Thanks.

Here's an extremely basic ajax example. In your form, you can fire your ajax method with:
<a onclick="AjaxFormSubmit()" href="#">Submit</a>
Then your ajax method would be as follows:
function AjaxFormSubmit() {
$.ajax({
url : '/event/{{ event.id }}/',
type : "POST",
data : { the_post : $('#id-of-your-field').val() }
}).done(function(returned_data){
// This is the ajax.done() method, where you can fire events after the ajax method is complete
// For instance, you could hide/display your add/remove button here
});
}
I recommend looking at the Ajax documentation to see all of the Ajax methods available to you.
Also, in your view, you'll need to return (in this example) json data via an HttpResponse. i.e.
return HttpResponse(json.dumps(your_data))
# I like to return success/fail Booleans, personally
*Note, this is untested code.

Related

Autosave user input in textarea in Django

I'd like to save user input in a text area automatically without any submit button. The UI I'm looking for is google docs kind of thing. Ideally there should be a time interval of 2-3 seconds after the input to prevent submitting requests every-time something is typed.
Here's my current implementation.
model:
class ActionField(models.Model):
content = models.TextField()
def __str__(self):
return self.content
view:
def action_view(request):
all_todo_items = ActionField.objects.all()
return render(request, 'action.html',
{'all_items': all_todo_items})
and html displaying the form and the submit button I'd like to remove:
<form action="/add/" method='post'>{% csrf_token %}
<textarea name="content" rows="30" cols="100"></textarea>
<br><br>
<input type="submit" value="enter">
</form>
After some quick research, it seems this would be normally done with AJAX or Jquery but is there any simple approach using purely Django? I'm new to the framework as well as html / FE.
I've never heard about that possibility. Django (just like any other backend framework) can only send or receive data to or from your browser. It can't somehow make your browser send something without any script at the browser's side.
However, there is a script that you can use:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<form action="/add/" method='post'>{% csrf_token %}
<textarea name="content" rows="30" cols="100"></textarea>
<br><br>
<input type="submit" value="enter">
</form>
<script>
$("textarea[name='content']").on("change", function() {
$.ajax({
url: '/add/', // or better {% url 'view-name-in-urls.py' %}
method: 'POST',
data: {
content: $(this).val(),
csrfmiddlewaretoken: '{{ csrf_token }}'
}
}).done(function(msg) {
alert("Data saved");
})
});
</script>
</body>
I know that the ability to do everything on the server-side is very convenient and looks nice but it's just impossible.
You need to learn how to deal with the server on the client-side too.
You can read more about forms here https://docs.djangoproject.com/en/3.1/topics/forms/
and ajax https://api.jquery.com/jquery.ajax/

Django POST dict empty, use simple html form

I am use Django 1.8 and Python 3.5.2, and try recive POST data from simple html form
<form action="/shop/order" method="POST">
{% csrf_token %}
<input type="hidden" name="product-code" value="{{ product.product_code }}">
<input type="text" name="email">
<input type="submit">
</form>
It view where I try get need for me data, but QueryDict empty for POST, when I change POST to GET in form and view all work.
def order_product(request):
test = request.POST.get('product-code', '')
mail = request.POST.get('email', '')
# logger.info(test)
return render(request, 'shop/test.html', dict(test=test, email=mail))
And I'am not understand why is that. Similarly I try parse(decode binary to utf-8 etc) body and I recive empty string.
urls.py
url(r'^order/?$', views.order_product),
Thanks all, the moral of this fable is as follows, use name argument in urls, and use {% url 'name' %} in template. I have i18n in urls(from djangoCMS) and when I harcode url in form isn't work for POST method.

How to send data to view without using html forms?

I have some data(checkbox and input field) in template file which I want to send to views.Due to page refresh upon submit checkbox field is unchecked.So how to send data to django view without using html form.Is it possible using jquery/ajax?
<form id="myform">
{% csrf_token %}
<p id=id3>Categories</p>
{% for i in My_Cat %}
<input type="checkbox" id="mycheck" name="cat_name" value="{{i.category}}">{{i.category}}<br>
<!--category is db column -->
<!--My_Cat is the context from the view -->
{% endfor %}
<p>Price</p>
₹<input type="text" name="min_price" maxlength="4" size="3" >
to ₹<input type="text" name="max_price" maxlength="4" size="3"><br>
<input type="submit" value="Go" style="margin-top: 6px;">
</form>
It is possible indeed.
Using javascript, catch the form submit event.
In the function, serialize the form (exemple using jquery : https://api.jquery.com/serialize/), or get the field values using selectors.
Craft your ajax request, then send it.
And on view side, don't render a template, use jsonresponse instead : https://docs.djangoproject.com/en/1.9/ref/request-response/#jsonresponse-objects

Processing POST request in Django

Hi I got a simple form for a POST request and it works when I'm only having one input, but not two inputs together. Can someone show me some light on this?
index.html
<form name="input" action="{% url 'sending' %}" method="post">
{% csrf_token %}
Recipient: <input type="text" name="recipient">
<br>
Message: <input type="text" name="content">
<br>
<input type="submit">
</form>
views.py
def sending(request):
recipient = request.POST.get('recipient','')
content = request.POST.get('content','') #not working when I am doing this...
someMethod(recipient, content)
return HttpResponseRedirect(reverse('results'))
Adding a "forms" portion to your setup will help you greatly... see the quickstart docs on forms here: https://docs.djangoproject.com/en/1.6/topics/forms/
In particular, check out "using a form in a view": https://docs.djangoproject.com/en/1.6/topics/forms/#using-a-form-in-a-view
Basically, you end up with a "forms.py" file which defines your form fields. Then, after it all processes, you get a simplier API into your form fields that looks like this:
form.cleaned_data['recipient']
form.cleaned_data['content']
etc.

How to redirect django.contrib.auth.views.login after login?

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

Categories

Resources