I have a form created in mysite/new_player.html. It accepts 3 fields, user_name, real_name, and site_played that correspond to the Player table in the database.
<h1> New Player </h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="/stakeme/new/" method="post">
{% csrf_token %}
User Name: <input type="text" name="user_name" id="user_name"/><br>
Real Name: <input type="text" name="real_name" id="real_name"/><br>
Site Played: <input type="text" name="site_played" id="site_played"/><br><br>
<input type="submit" value="New Player" />
</form>
I am stuck on how to add this to my mysite/views.py file. I have gone through the polls tutorial, but the only form that is used in the tutorial is a multiple choice "choice" of the "poll" and I can't seem to adapt that to text fields.
def new_player(request):
return render_to_response('stakeme/new_player.html',
context_instance=RequestContext(request))
So as I understand it, I would need to create something like def add(request): return render_to_response('stakeme/new/'.. etc and add the POST data in here, but that's where I am lost. I am not sure how to get the data into the database.
I am reading the Django docs, but I feel like I am just compounding something that I do not understand. If someone could point me in the right direction, I would really appreciate it.
Firstly, you don't need to define a new view to process the form data. Also, you are creating your form directly in HTML - it's possible to work this way (see later section of post) but it's better (easier) to use the Django Forms library.
Using Django Forms
The documentation (v1.3 forms documentation) from the start up to and including ''Displaying a form using a template'' explains the basics of using the forms library, so I'll copy & paste liberally from there. I'll also assume that you're familiar with basic python constructs & have Django 1.3 installed. Without further ado, here's my adhoc forms tutorial.
Start a new django project:
$ django.admin.py startproject mysite
Add a new app:
$ ./mysite/manage.py startapp myapp
Lets create our contact form (modified from example in Django forms doc). Create a file in side the myapp/ directory called called forms.py and put the following in it:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField(max_length=100)
Next, since you mentioned storing data from received contact forms in a database, we'll add a model, Feedback, to track received contact forms. In your models.py file, add the following:
class Feedback(models.Model):
subject = models.CharField(max_length=100)
message = models.TextField()
sender = models.CharField(max_length=100)
def __unicode__(self):
return "Subject:{subject}\nSender:{sender}\n{msg}".format(subject=self.subject,
sender=self.sender,
msg=self.message)
(You may notice this is very similar to the form we defined earlier; normally in a scenario like this, one would use Django model forms to create a form directly from a model, but we are building our forms by hand as a learning experience)
We also need to get Django to create the required table in our database for this Feedback model, so at the top of your settings.py insert the following useful code:
import os
PROJECT_DIR = os.path.dirname(__file__)
And change the DATABASES setting in settings.py to the following to use a sqlite database:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': os.path.join(PROJECT_DIR, "sqlite.db").replace('\\', '/'), # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
Finally, change the INSTALLED_APPS setting to the following to include our recently created application myapp in the list of installed applications for mysite:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
)
Now run the syncdb command to get Django to create the tables in your sqlite database (which, since it's sqlite, will be created if it doesn't exist yet):
$ ./mysite/manage.py syncdb
(Django will prompt you to create a superuser as well: you don't have to create a superuser now since we don't need it and you can use django-admin.py createsuperuser to create one when you need it, but you can create now now if you like)
Now we need a view to display the contact form, and a view to thank people for submitting it. In your views.py file, add the following (modified slightly from Django forms docs):
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from myapp.forms import ContactForm
from myapp.models import Feedback
def thanks(request):
return render_to_response('thanks.html')
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
feedback = Feedback(subject=subject, message=message, sender=sender)
feedback.save()
return HttpResponseRedirect(reverse('thanks')) # Redirect after POST
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
}, context_instance=RequestContext(request))
Now we need to map URLs to views. Open mysite/urls.py and make it look like the following
from django.conf.urls.defaults import patterns, include, url
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
# Examples:
url(r'^thanks/$', 'myapp.views.thanks', name='thanks'),
url(r'^$', 'myapp.views.contact', name='contact'),
# url(r'^mysite/', include('mysite.foo.urls')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
# url(r'^admin/', include(admin.site.urls)),
)
Now we need some templates to display the contact form & the thankyou page. Create a directory mysite/templates/, create a file contact.html inside it, and put the following in it:
<html>
<head>
<title>Contact Us</title>
</head>
<body>
<p>Please fill out the following information and click submit:</p>
<form action="{% url contact %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</body>
</html>
Also create a thanks.html page for the thank you page, and put the following in it:
<html>
<head>
<title>Thanks</title>
</head>
<body>
<p>Thank you. Your feedback is important to us</p>
<p>Please leave some more feedback at the Contact page</p>
</body>
</html>
Next, we need to make sure Django can find our templates, so modify the TEMPLATE_DIRS in mysite/settings.py setting to the following:
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.join(PROJECT_DIR, "templates").replace('\\', '/'),
)
Now, (finally!), you can run the debug server and test that everything works:
$ ./mysite/manage.py runserver 8080
Go to http://localhost:8080/ and try to enter some feedback. When you click Submit, it should put your entered details into the database & show the thank you page. You can check the details are entered into the database:
$ ./mysite/manage.py shell
Into the shell, type:
>>> from myapp.models import Feedback
>>> for f in Feedback.objects.all(): print f
(note that you need to press enter twice after entering the last line)
You should see the feedback entries you have created.
Creating forms manually in HTML
If you insist on doing this, you can access the form's request variables directly in your view using the request.POST dictionary, and then instantiating a model of your object manually & calling save (like in the contact() view function above).
I would not recommend doing this, because you lose a whole bunch of nice features that Django Forms provides (CSRF protection, validation, etc).
Other Tutorials
Since the original form of this question asked for some tutorials: the official Django wiki has a page listing some tutorials, some of which deal with forms. Be aware that a lot of those tutorials are quite old (mostly from 2007-2009).
Sounds like you want to have a good and thorough look at the
Getting started guide https://docs.djangoproject.com/en/dev/intro/
Forms documentation https://docs.djangoproject.com/en/dev/topics/forms/
After which you may come up with something along these lines. Untested and quickly scribbled together, likely to be riddled with bugs.
models.py
from django.db import models
class Person(models.Model):
user_name = models.CharField(max_length=30)
real_name = models.CharField(max_length=30)
site_played = models.CharField(max_length=30)
forms.py
from django import forms
class PlayerForm(forms.Form):
user_name = forms.CharField(max_length=30)
real_name = forms.CharField(max_length=30)
site_played = forms.CharField(max_length=30)
views.py
def player_form(request):
if request.method == 'POST':
form = PlayerForm(request.POST)
if form.is_valid():
user_name = form.cleaned_data['user_name']
real_name = form.cleaned_data['real_name']
site_played = form.cleaned_data['site_played']
player = Player(user_name=user_name,
real_name=real_name,
site_played=site_played)
player.save()
# Redirect to a thanks page maybe?
else:
form = ContactForm()
return render_to_response('contact.html', { 'form': form,})
contact.html
... lots of fancy html ...
{{ form }}
... more fancy html
You need something like this (read about form fields validation yourself):
models.py:
from django.db import models
class Player(models.Model):
user_name = models.CharField()
real_name = models.CharField()
site_played = models.CharField()
forms.py:
from django import forms
MyForm(forms.Form):
user_name = forms.CharField()
real_name = forms.CharField()
site_played = forms.CharField()
views.py:
from forms import MyForm
from models import Player
def new_player(request):
#...
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
player = Player()
player.user_name = form.cleaned_data.get('user_name')
player.real_name = form.cleaned_data.get('real_name')
player.site_played = form.cleaned_data.get('site_played')
player.save()
#...
return render_to_response('stakeme/new_player.html',
context_instance=RequestContext(request))
UPDATE:
After you get the idea, you might want to have a look at WTForms library.
Related
I have a ModelForm with a FilteredSelectMultiple widget
from django import forms
from django.contrib import admin
class PortFolioForm(forms.ModelForm):
class Meta:
model = PortFolio
fields = ['title', 'description', 'keywords']
class Media:
css = {'all':['admin/css/widgets.css']}
js = ['/admin/jsi18n/']
keywords = forms.ModelMultipleChoiceField(label='Mots clés', widget=admin.widgets.FilteredSelectMultiple('Mots clés', False), queryset=Keyword.objects.all())
I'm using the form outside the admin, inside a view
c = {'form': PortFolioForm() }
return render(request, 'portfolio.html', c)
......
form = PortFolioForm(request.POST)
if form.is_valid():
form.save()
......
{{ form | crispy }}
When I'm already logged in as admin, the widget is dispayed as normal
If not it does not appear
I get the following js errors :
Refused to execute script from 'http://localhost/admin/login/?next=/admin/jsi18n/' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
Uncaught ReferenceError: interpolate is not defined
at Object.init (SelectFilter2.js:38)
at SelectFilter2.js:233
at NodeList.forEach ()
at SelectFilter2.js:231
As the website I'm working on is meant to be used by other users, I would like to use just the widget itself, because all the saving is done within the views, using form.save()
This could be because you are accessing a script under the admin url:
class Media:
css = {'all':['admin/css/widgets.css']}
js = ['/admin/jsi18n/']
You need to access the js outside the /admin/ location. Either copy the script to a folder not under admin/ and then change the location, or provide an url not under admin. For instance add to urls.py:
url(r'^jsi18n/$',
'django.views.i18n.javascript_catalog',
name='jsi18n')
And then change the form script url to just:
class Media:
css = {'all':['admin/css/widgets.css']}
js = ['jsi18n/']
Check Django's FilteredSelectMultiple widget only works when logged in
I'm using the built in django admin site for the application's admin site in a sense that POST requests are built identically to its equivalent admin site, and sent to the same urls. So it's like the application admin site is just a wrapper for the admin site.
My problem is, I don't know how to redirect back to url where it was originally posted. Currently it redirects to the Change User admin page. I'd like it to redirect back to the page.
Here's my change-password-template.html:
<div>
<form action="{% url 'admin:auth_user_password_change' user.pk %}" method="post" id="change-password-form">
{% csrf_token %}
# ... here goes the password fields
<input type="submit" value="Change password">
</div>
<input type="hidden" name="next" value="{% url 'change_password' id=user.pk%}"> # my attempt at trying to redirect back to the original webpage
</div>
</form>
</div>
So, it does correctly post to admin/auth/user/{{user.pk}}/password/ but instead of redirecting back to the that page it instead redirects to: admin/auth/user/{{user.pk}}/change/. How can I make it do so?
The wrong way to do it...
You would need to overwrite the user_change_password method in your User admin, since that is where the redirect happens:
# contrib.auth.admin.py
def user_change_password(self, request, id, form_url=''):
...
if request.method == 'POST':
form = self.change_password_form(user, request.POST)
if form.is_valid():
...
return HttpResponseRedirect(
reverse(
'%s:%s_%s_change' % (
self.admin_site.name,
user._meta.app_label,
user._meta.model_name,
),
args=(user.pk,),
)
)
Since this ModelAdmin is registered in the auth app, you will need to unregister that, add your own custom UserAdmin. There are clear instructions on how to do this in the django docs. Once you have done that simply overwrite the method above and edit the redirect.
This would be much more effort than it's worth however, and more importantly it would also be a nasty hack. It's not what the admin interface is intended for. (It would also have the unintended side-effect that when you actually do use the admin app, it will now redirect to wherever you now have told it to - this would be very unusual behaviour).
A better solution...
If you want to add an end-point where a user can change their password it's not difficult to do it yourself, and that would be the best solution in this case.
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.urls import reverse
def change_password(request, user_id):
new_password = request.POST["password"]
user = User.objects.get(id=user_id)
user.set_password(new_password)
user.save()
return HttpResponseRedirect(reverse('your_url_here))
You'll need to add some additional checks (e.g. make sure the user has the appropriate permissions, make sure the request is a POST etc.).
Probably better still...
Django actually has a built in view for doing this, that you can subclass to customise.
# views.py
from django.contrib.auth.views import PasswordChangeView
class MyPasswordChangeView(PasswordChangeView):
success_url = reverse("url_to_redirect_to")
# urls.py
urlpatters = [
path('change_password', MyPasswordChangeViews.as_view())
]
You can read more about these built in views here.
Level: Absolute Beginner, trying to build an app to perform some db operation through web UI
models.py
from django.db import models
class MysqlUser(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=50)
environment = models.CharField(max_length=50)
forms.py
from django import forms
from onboard_app.models import MysqlUser
class MysqlUserForm(forms.ModelForm):
CHOICES = (
('test', 'Test'),
('develop', 'Develop'),
('staging', 'Staging'),
)
environment = forms.MultipleChoiceField(choices=CHOICES)
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = MysqlUser
fields = ('username', 'password', 'environment')
views.py
from django.shortcuts import render
from onboard_app.serializers import MysqlUserSerializer
from rest_framework import generics
from onboard_app.forms import MysqlUserForm
from onboard_app.models import MysqlUser
from django.views.generic.edit import CreateView, UpdateView, DeleteView
class MysqlCreateView(CreateView):
model = MysqlUser
form_class = MysqlUserForm
template_name = 'mysqluser_form.html'
success_url = '/mysql/user/add/'
mysqluser_form.html
{% extends "myapp/base.html" %}
{% block title %}MyApp{% endblock %}
{% block content %}
<h1>MySQL User Access</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="Grant Access">
</form>
{% endblock %}
I'm trying to get Value(s) of field or MultipleChoiceFiled environment after the user Form Submit, and loop through the entered values to perform some action. I have been trying this for long, still can't figure out how. I don't want to process anything in the frontend html. I'm thinking it has to be processed in the Views but not sure how to get the values of the field and loop over.
Any examples or any django concepts to look into will help me a lot. Any help is appreciated, thanks in advance!
Unless you have already done so, I recommend going through Django docs on class-based views (https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/) to get an overview of how the whole thing works.
So after you submit a form, a post() method of your view is called. CreateView provides a default implementation, which validates the user input using the MysqlUserForm you have provided and then creates an instance of MysqlUser and redirects to the success_url.
If you want to add more logic, you need to overwrite the post() method (or some other method, called by post(), in particular, the form_valid method) and put your logic there. To get a complete sense of how things work, I recommend you to read through the CreateView, BaseCreateView, ProcessFormView, and ModelFormMixin source code, although the inheritance looks a bit complicated (and it is). More to that, I really advise you to walk through the request processing from the View.dispatch method all way to the form_valid method using the debugger and see how things really work. Trust me, it will really contribute to your development skills improvement and understanding. Actually, I've discovered the form_valid method to write this answer by reading the source code (I use rest-framework nowadays and don't remember a lot about Django views).
So, what you need is
class MysqlCreateView(CreateView):
model = MysqlUser
form_class = MysqlUserForm
template_name = 'mysqluser_form.html'
success_url = '/mysql/user/add/'
def form_valid(self, form):
environment = form.cleaned_data['environment']
# insert your code here
return super().form_valid(form)
P.S. A good IDE like a PyCharm is really much much more convenient to read source code, jump to relevant parts and debug than any text editor and PDB debugger.
I am new to Django and am using Django's user auth package (django.contrib.auth) for user login, password reset, etc.
Now, while everything works just fine, on the logon form, I'd like to use the html-placeholder property. How can I use / populate this? I did find some answers (e.g. this one) but I do not understand where to place this code, how to extend the view / form or even the model (e.g. adding new fields) as this gets delivered with the standard package.
Right now, I have added the following:
forms.py
from django import forms
from django.contrib.auth.forms import AuthenticationForm
class LoginForm(forms.Form):
username = forms.CharField(label='username')
password = forms.CharField(label='password')
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['placeholder'] = 'Username'
self.fields['password '].widget.attrs['placeholder'] = 'Password'
I am not sure what I need to do in urls.py or models.py or anywhere else for the code to be executed.
I found the following solution:
installed bootstrap4
using the following tag in my html:
{% bootstrap_field form.password field_class="field" placeholder="Password" show_label=False %}
I believe by adding the widgets to your forms init, when you instantiate the form in your template the placeholder should appear like intended. Did you just try rendering your form such as {{form}} in the template and see if it rendered it? I dont think bootstrap4 is necessary but it is a great tool.
Django has a built in admin page where it comes with a feature to add/edit/remove user (and its authentication).
However, i need to create a custom form involving the following models
employee/models.py
# Stores profile details such as DoB, Martial Status, TFN and so on
class Profile(models.Model):
user = models.OneToOneField(User)
MARTIAL_STATUS = (
('s', 'Single'),
('m', 'Married'),
('d', 'Divorced'),
('w', 'Widowed')
)
martial = models.CharField(max_length=1, choices=MARTIAL_STATUS, null=True)
tfn = models.CharField(max_length=200, blank=False)
What i want to do is to have one form where user can enter information about the username, first_name, and so on along with all fields required in my models.
So far this is what i have done
Notice how an account needs to be created first, before additional information (from different model) can be inserted
ps: i am using Django ver 1.6
If I understand correctly, you need to create custom users for adding it to your profile form in admin site. Why don't you use django shell? For example:
where manage.py resides, open terminal/command prompt and type:
>>python manage.py shell
In [1]: from django.contrib.auth.models import User
In [2]: i=User(username="test")
In [3]: i.save()
In [4]: i.set_password('test')
In [5]: i.save()
You can use this username/password to login into site.
EDIT:
Assuming your admin url is like www.mysite.com/admin, you can access user directly using this like: www.mysite.com/admin/auth/user/add/. Also admin interface looks like this: .
And if you want to add email address and other data, you can press save and continue editing like below:
This will lead you to updating user contents.
If you want to create user not from admin site, then less painful way to implement user registration is using UserCreationForm.
from django.views.generic.edit import CreateView
from django.contrib.auth.forms import UserCreationForm
urlpatterns = patterns('',
url('^register/', CreateView.as_view(
template_name='register.html',
form_class=UserCreationForm,
success_url='/'
)),
url('^accounts/', include('django.contrib.auth.urls')),
# rest of your URLs as normal
)
you have to create a register.html here though like:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Create" />
</form>
details: http://www.obeythetestinggoat.com/using-the-built-in-views-and-forms-for-new-user-registration-in-django.html
I usually start from the documentation full example then I adapt it for my needs. You keep the Django permissions but you also add some custom permissions.
I don't know how far are you in your project but if you're just starting I recommend you to use twoscoops templates or cookiecutter-django of Daniel Greenfield. It also implements django all auth library which is very useful for social authentifcations.
There should be + symbol near by user model dropdown box which eases the user to quick add, like the below one.
If the user model in registered with admin i think you could get access to create it on the fly.
OR
As Ruddra's above answer, you have create all user profiles, then you can fillup the form in straight manner.