How to set the html form fields without using django-forms.
If you do not wish to use django.forms, but get data from a model and display it into a html form, you could do something like this:
views.py
from django.shortcuts import render_to_response, redirect
from myApp.models import MyModel
def editForm(request, model_pk):
model = MyModel.objects.get(pk=model_pk)
return render_to_response('formUpdate.html',{ 'model' : model })
def updateForm(request, model_pk):
model = MyModel.objects.get(pk=model_pk)
model.firstname = request.POST['firstname']
model.lastname = request.POST['lastname']
model.save()
return redirect('home', message='your name has been updated')
template - formUpdate.html
{% extends "base.html" %}
{% block content %}
<form action="/updateForm/{{ model.id }}/" method="post">
First name: <input type="text" name="firstname" value="{{ model.firstname }}" /><br />
Last name: <input type="text" name="lastname" value="{{ model.lastname }}" /><br />
<input type="submit" value="submit" />
</form>
{% end block %}
models.py
from django.db import models
class MyModel(models.Model):
firstname = models.CharField(max_length=20)
lastname = models.CharField(max_length=20)
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^$', 'views.home', name="home"),
(r'^editForm/(?P<model_pk>\d+)/$', 'views.editForm'),
(r'^updateForm/(?P<model_pk>\d+)/$', 'views.updateForm'),
)
This is very similar to how forms are processed in PHP or similar, the model is passed into the template where the existing values are rendered. The id or pk (primary key) of the model is passed to the view via the URL and then updated values then returned to the storing view in the POST data where they can be retrieved and the updated values stored in the database.
One of the beauties of Django is how it balances speed of development with plugability - pretty much any of it's parts can be replaced or altered.
Having said this, is there a reason why you don't want to use django.forms? To my understanding a form simply performs most of the hard work in the example above for you, this is what django.forms are for. They also have other features, to help prevent malicious access of your web app, for example, OOTB. It is fairly easy to create ajax helper methods to retrieve and update them also.
You can do that as you would create a normal form in html. Just be careful to place the {% csrf_token %}. And the name of the input in the form, as they will be used in the view.
Eg:
<form method="post" action="#the url for the view">
{% csrf_token %}
...
...
<!-- fields that you want Eg: -->
<label for="username">User name:</label>
<input type="text" name="username" id="username" />
...
...
<input type="submit" value="Submit" />
</form>
Hope this helped.
Related
I have a base template file that holds the form for the users to subscribe to the email newsletter. All of my templates inherit from the base template file, as I'd like to display this form on every web page.
I don't know how do I make the form submit the data the user inputs into the database. So far, I dealt with views and each view was specific to a URL, so it's not really obvious to me how do I do this for all URLs, since the base template is present on all URLs.
base.html (the base template file):
{% load static %}
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
Homepage
Post a job
{% block content %}{% endblock %}
<p> Subscribe to new jobs: </p>
<form method="post">
<p> Email: <input type="email" name="email" /> </p>
<p> First name: <input type="text" name="first_name" /> </p>
<p> Last name: <input type="text" name="last_name" /> </p>
<input type="submit" value= "Submit">
</form>
</body>
</html>
I also made a form in my forms.py file which constructs the form from my email subscriber model, but I don't use it anywhere so far:
EmailSubscriberForm = modelform_factory(EmailSubscriber, fields=["email", "first_name", "last_name"])
How do I achieve what I want?
you need to use a ModelForm, that will link a form to a model when calling save() method. (this will add a lot of security too)
from django.forms import ModelForm
from myapp.models import EmailSubscriber
# Create the form class.
class EmailSubscriberForm(ModelForm):
# if email is an EmailField, `is_valid` method will check if it's an email
class Meta:
model = EmailSubscriber
fields = ["email", "first_name", "last_name"]
Then in the view you can create and pass as a context or get the response and save to the database
if request.method == "POST":
form = EmailSubscriberForm(request.POST)
if form.is_valid():
email_subscriber = form.save()
# generally call `return HttpResponseRedirect` here
else:
form = EmailSubscriberForm()
# generally call `return render(request, 'page.html', {'form': form})
and you just call this in your template :
<form method="post">
{{ form }}
</form>
Ref : https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/
models.py
class Prueba(models.Model): #collection name
cantidad = models.PositiveIntegerField(default=1)
def __str__(self):
return str(self.cantidad)
urls.py
from django.urls import path
from . import views
app_name = "home_app"
urlpatterns = [
path(
'confirmar_viaje/',
views.SampleView.as_view(),
name='userviajes',
),
]
View.py
class SampleView(CreateView):
model=Prueba
template_name='testpag.html'
form_class=TestForm
success_url = '/'
def init_page(request):
print(request.GET)
pasajeros = self.request.form['pasajeros']
print(pasajeros)
forms.py
class TestForm(forms.ModelForm):
class Meta:
model=Prueba
fields=['cantidad']
I use a DetailView, inside html have a form(html).
The result is /test/?pasajeros=99
I want to take from de url params. pasajeros=99 and fill a textfield from form.
The code dont have errors but i need to recuperate the param or params.
Any Idea?
in your form put for exmple in code html
link to your forms
It is code call the CreateView than i want fill
<form action="/confirmar_viaje/" method="get">
<p>name: <input type="text" name="fullname" size="40" value={{user.username}} disabled></p>
<p>Numeber: <input type="number" name="pasajeros" ></p>
<p>
<input type="submit" value="Submit">
</p>
</form>
Why I do this, it si because this part the code it is inside of DetailView, and no its posible have two views point to one adress, so my solution its send datas via GET, and the other View catchs it the params from de URL and fill automatic my filds, so this way i have two Views with his own url.
It is the code than recive the url
<div>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<button type="submit">Registrar</button>
</form>
</div>
</div>
I have a generic view and a form template.
my view is:
class BlogCreateView(CreateView):
model = Post
template_name = "post_new.html"
fields = "__all__"
and my form template is:
{% extends "base.html" %}
{% block content %}
<h1>New Post</h1>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
{% endblock content %}
now my question is about form.as_p or specifically form.
Where did that come from?
help me please. thanks a lot
.as_p() [Django-doc] is a method on a Form. It produces a SafeText object [Django-doc] that contains HTML code to be included in the template.
The fact that it is SafeText is important, since the Django render engine will otherwise "escape" it: without using SafeText, it would replace < with <; > with >, etc. Unless of course you wrap it in a SafeText object yourself, for example through the |safe template filter [Django-doc].
We can for example define a form like in the documentation:
class OptionalPersonForm(forms.Form):
first_name = forms.CharField()
last_name = forms.CharField()
nick_name = forms.CharField(required=False)
If we then construct a form object, we can call the .as_p() method:
>>> OptionalPersonForm().as_p()
'<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" required id="id_first_name"></p>\n<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" required id="id_last_name"></p>\n<p><label for="id_nick_name">Nick name:</label> <input type="text" name="nick_name" id="id_nick_name"></p>'
>>> type(OptionalPersonForm().as_p())
<class 'django.utils.safestring.SafeText'>
Django forms have three popular rendering methods: .as_p, .as_table() [Django-doc] and .as_ul() [Django-doc]. The difference is that these render the HTML slightly differently: as paragraphs, a table or unordered HTML list.
I have just started with creating Django app. I have a class in models.py, which have a class variable CATEGORY_CHOICES with values for choices field.
#models.py
from django.db import models
from django.utils import timezone
class Entry(models.Model):
CATEGORY_CHOICES = (
('c1','choice 1'),
('c2','choice 2'),
('c3','choice 3'),
('c4','choice 4'),
)
date = models.DateField(default=timezone.now)
time = models.TimeField(default=timezone.now)
category = models.CharField(choices=CATEGORY_CHOICES,blank=False,null=False,max_length=2)
value = models.TextField()
I want to make form for creting instanes of class Entry. I'm having problem with the select menu, where I want to put values from CATEGORY_CHOICES but I can't figure out how.
<!-- homepage.html -->
{% load staticfiles %}
{% load app_filters %}
<HTML>
<HEAD>
<TITLE>Website title</TITLE>
<link rel="stylesheet" href="{% static "css/app.css" %}">
</HEAD>
<BODY>
<form method="POST" class="form-inline">{% csrf_token %}
<input type="date" class="form-control" id="date-input">
<input type="time" class="form-control" id="time-input">
<select class="form-control">
{% for choice in Entry.CATEGORY_CHOICES %}
<option>{{ choice|get_at_index:1 }}</option>
{% endfor %}
</select>
<input type="text" class="form-control" id="value-input" placeholder="Value">
<input type="submit" value="OK">
</form>
</BODY>
</HTML>
It's a 4 elements list, so {% for choice in Entry.CATEGORY_CHOICES %} should be saving single 2-elements lists (first ('c1','choice 1') then ('c2','choice 2') etc) into variable choice. There I pick the second element of the list with the help od custom filter get_at_index.
#app_filters.py
from django import template
register = template.Library()
#register.filter(name='get_at_index')
def get_at_index(list, index):
return list[index]
I get no errors, but in the final form, there are no options in select menu.
What could be wrong and how to fix it?
#views.py
from django.shortcuts import render
from .forms import EntryForm
def home_page(request):
form = EntryForm()
return render(request, 'app/homepage.html', {'form':form})
And forms.py
#forms.py
from django import forms
from .models import Entry
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ('date','time','category','value',)
In your view, you're passing down the form to the template, but you don't use the form in your template the way you're supposed to. To use the form you've passed down, write your form code in the template more like this:
<form method="POST" class="form-inline">
{% csrf_token %}
{{ form }}
<input type="submit" value="OK">
</form>
And it will render the entire form for you. You can read more about it in the official documentation: Building a form in Django
Or, if you want to build the form yourself, then you need to send the coices down to your template in your view:
def home_page(request):
form = EntryForm()
return render(request, 'app/homepage.html', {
'form': form,
'entry_choices': Entry.CATEGORY_CHOICES
})
And then access it in your template using the key entry_choices.
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