Heres the scenario:
I have a email subscriber/un-subscriber app. I am stuck up in the un-subscribing a user part. The user is given a link, which if he/she follows will be able to un-subscribe. The link is typically a view, in the following format:
r^'/unsub_view/(?P<user_id>\w+)/$'
So, when the user follows this links he/she is doing a GET request on the view unsub_view with a parameter user_id. So I have coded up my view as:
def unsub_view(request, user_id):
if request.method == 'GET':
### Do some DB lookup to determine if it is a valid user or not
if user_is_valid:
return direct_to_template(request, '/app/unsub.html', {'user': user})
Now when a valid user is doing the GET, a confirmation dialogue is shown, along with a button. If he/she clicks on the button, I want the template to post the 'user' to the same view, thus the unsub_view also has this piece of code:
if request.method == 'POST':
if user_is_subscribed:
#Unsubscribe the user.
else:
#Show error meessage.
My question is how can I have the button in my template to post to this view ? I have looked around but I got POST-ing to a .php or .asp
Please help.
Note: If there is a better workflow idea, I am also open to that, so please do suggest if there is one.
In the template unsub.html rendering the form with the button, you should pass the url of your view using the reverse method
from django.code.urlresolvers import reverse
def unsub_view(request, viewid):
if request.method == 'POST':
if user_is_subscribed:
#Unsubscribe the user.
submit_url = reverse('unsub_view', viewid)
return direct_to_template(request, '/app/unsub.html', {'user': user, 'submit_url'})
else:
#Show error meessage.
in your template you can then render the form like follows :
...
<form method='post' action='{{ submit_url }}'>
{% csrf_token %}
<input type="hidden" value="{{ user_id }}" name="user_id" />
<input type="submit" value="unsubscribe"/>
</form>
...
Django also has a full framework dedicated to form modeling and rendering. You could take advantage of that to generate the form.
Related
I have a simple form and whenever the user does something wrong on the form I'd like to raise a validation error on Django. The problem is that I set up the form validation but when the form is submitted with wrong values, it goes through. I was wondering why it's happening and how I can avoid that?
Here is the html form:
<form id="ask-project" method="post" action="{% url 'ask-project' %}">
{% csrf_token %}
<input required="required" class="form-control form-text required" id="prenom" name="prenom" type="text">
<button class="btn btn-default submit">Submit</button>
</form>
views.py:
def askProject(request):
if request.method == 'POST':
form = AskProjectForm(request.POST)
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
return redirect('/merci/') #success
forms.py:
class AskProjectForm(forms.ModelForm):
class Meta:
model = AskProject
fields = ['prenom']
def clean_prenom(self):
prenom = self.cleaned_data['prenom']
if len(prenom) < 3:
raise ValidationError('Votre prénom doit etre plus long que 1 caractère.')
return prenom
Am I doing something wrong?
With the pattern that you are using, this sort of problem is inevitable and order of the day. The first thing is not to render the form manually as you appear to be doing. That means you are not showing any feedback when the user enters invalid data. Consider using {{ form }}, {{ form.as_table }} etc or rendering the fields with all information as described here: https://docs.djangoproject.com/en/1.11/topics/forms/#rendering-fields-manually
Second problem is that you are redirecting when the form is submitted, regardless of whether it's valid or not. The recommended pattern is to redirect only when the form is valid. So even if you apply the suggestion in the first para, you are still not getting the required feedback. Consider implementing the form as suggested in the manual. A straight copy past follows
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
Finally getting onto the specific case of why your form validation doesn't work, add a print statement in your clean method to print out both the string and it's length see if it tallies (or if your method even gets called)
This is my first django project and I'm struggling to finish it.
I've been working to function that editing post. When user clicks button, it send no(int)for that article, and get information related to no and display on page. User can edit that post in the same form and when user click submit, it redirect to home.html
However, the function I made keep sending me an error message that it takes 2 arguments even though I did not use any function that takes 2 arguments.
Here is views.py
#login_required
def edit_article(request, article_no):
article = Article.objects.filter(pk=article_no)
form = ArticleForm(request.POST, instance=request.article)
if form.is_valid():
form.save()
messages.add_message(request, messages.SUCCESS, _('Article correctly saved.'))
# If the save was successful, redirect to another page
redirect_url = reverse('blog/home.html')
return HttpResponseRedirect(redirect_url)
else:
form = ArticleForm(instance=request.article)
return (request, {'form': form}, context)
This is form in detail.html where send no value to edit_article.html
<form action="{% url 'blog:edit_article' %}" method="post" style="display: inline;">
{% csrf_token %}
<input type="hidden" name="no" value="{{ item.no }}" />
<button type="submit">edit></button>
</form>
The article_no arg does not magically find its way into the function call via the POST submit. You need to provide it to the url tag:
{% url 'blog:edit_article' item.no %}
This assumes, of course, that you have a url pattern with an appropriate named group associated with this view/view name.
If You are talking about this function, it does recieve more than one Arg, it recieves the No you are talking about, and the request object
def edit_article(request, article_no):
...
If your view needs arguments you must give the arguments in the url templatetag, like this :
{% url 'accounts:detail_account' username = username %}
I have such problem:
I have form, that displays on every page of a web-site. So, the action is for specified(separate) view:
def subscribe(request):
if request.method == "POST":
form = SubscriptionForm(data=request.POST)
if form.is_valid():
form.save()
return redirect() # there is a problem
else:
raise Http404
After success handling of form, I want to redirect a user to the page, from which form was sent.
But if I use request.path - it returns me an url that handles this form. But I need the url of a page...
Do you understand? What should I do?
Thanks a lot!
You'll need to add an additional field to your form to let your view know where to redirect to. The simplest way to do this is to add a hidden input to your form:
<form action="/some/url/" method="post">
...
<input type="hidden" name="next" value="{{ request.path }}">
</form>
The value of request.path is the path of the page before the user submits the form.
In your view, you can use the parameter next to redirect the user back to the page they came from.
def subscribe(request):
...
next = request.POST.get('next', '/some/default/url/here/')
return redirect(next)
I want to build a very simple webapp that takes a user's text, runs a function on it that alters it and then displays the altered text. I have the code for the function but everything else is unclear.
I am very new to django and just need a push in the right direction with this problem. At the very least, tell me what to google, I've went through several tutorials but neither of them dealt with this kind of task.
Thanks in advance!
Define a form; in forms.py under your app's folder
class MyForm(forms.Form):
myinput = forms.forms.CharField(max_length=100)
Define a function in your views.py
import .forms
def handle_form(request):
if request.method == 'POST': # If the form has been submitted...
form = MyForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = MyForm() # An unbound form
return render(request, 'handle_form.html', {
'form': form,
})
Add a template
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Of course you need to add it to your urls.py
Most info was copy pasted from: https://docs.djangoproject.com/en/1.8/topics/forms/
I'm using Pyramid to build a webapp, and I've got two views where one leads to the other:
config.add_route("new", "/workflow/new")
config.add_route("next", "/workflow/{id}/next")
The new view is really very simple and presents only an HTML form as a Jinja2 template for the user to fill in some information:
<form method="post" action="{{ request.route_url('next',id='') }}" >
<input type="text" name="id" value="Identifier" />
...
<input type="submit" name="next" value="Next" />
</form>
The question here regards the action of that form: how can I use the content of the text input field id, perhaps process it a little, and then pass it on in the route request?
Note that in this scenario the form data is passed from the new view to the next view, and that should stay the same.
When the form is posted, the forms fields will be available in the request object, see
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/webob.html#request
I believe it is also a good idea to post to the same url (<form action="#" method="post">), so that you can validate the form. Then you can process and redirect to the next url when the form is valid, or recreate the form with errors if it isn't.
So your view may end up something like this;
from pyramid.httpexceptions import HTTPFound
from pyramid.url import route_url
def myview(request):
if request.method == 'POST':
# Validate the form data
if <form validates successfully>:
# Do any processing and saving here.
return HTTPFound(location = route_url('next', id=request.params['id'], request=self.request))
else:
request.session.flash("The form isn't valid.")
# Do some stuff here to re-populate your form with the request.params
return { # globals for rendering your form }
There are already many questions/answers addressing this, such as How can I redirect after POST in Pyramid?