I just started my first app with django. I have built forms previously with bootstrap and custom styling. Now i came to know about django built-in forms with models. i have written the code for this but found that there is not styling and it's look so ugly. i want to add my custom styling to this form how can i do this. here is my code.
model.py
class Message(models.Model):
MessageID = models.AutoField(verbose_name='Message ID',primary_key=True)
MessageSubject = models.CharField(verbose_name='Subject',max_length=255,null=True,blank=True)
MessageContent = models.TextField(verbose_name='Content',null=True,blank=True)
MessageType = models.CharField(verbose_name='Message Type',max_length=255,default='Email',null=True,blank=True)
forms.py
from django import forms
from django.forms import ModelForm
from Apps.SendMessage.models import Message
class Message_form(ModelForm):
class Meta:
model = Message
views.py
def add_message(request):
message_form = {'message_form': Message_form}
print request.POST.get('Subject')
return render_to_response('sendmessage_form.html', message_form, context_instance=RequestContext(request))
and sendmessage_form.html
{% extends "base.html" %}
{% block Content %}
<div class="container">
<!-- Contacts -->
<div id="contacts">
<div class="row">
<!-- Alignment -->
<div class="col-sm-offset-3 col-sm-4">
<!-- Form itself -->
<form name="sentMessage" action="" method="POST" class="well" id="contactForm" novalidate>
{% csrf_token %}
{{ message_form }}
<button type="submit" class="btn btn-primary btn-sm pull-right">Send</button><br />
</form>
</div>
</div>
</div>
</div>
{% endblock %}
You're looking for Widgets!
From the documentation:
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField(widget=forms.Textarea)
In your example:
You're using Bootstrap and therefore a simple css class (form-control) in each field will make it look great:
class Message_form(ModelForm):
class Meta:
model = Message
fields = ['MessageSubject', 'MessageContent', 'MessageType']
widgets = {'MessageSubject': forms.TextInput(attrs={'class': 'form-control'}),
'MessageContent': forms.Textarea(attrs={'class': 'form-control'}),
'MessageType': forms.TextInput(attrs={'class': 'form-control'}),}
Another thing, you don't need to explicit define MessageID. All Django models have a primary key like the one you defined (check the docs).
Use Django Bootstrap3 app. It provides form fields and template tags for displaying horizontal and vertical bootstrap forms:
{% load bootstrap3 %}
<form action="." method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
I've been using crispy_forms and it's working very well with bootstrap.
pip install django-crispy-forms
In your template:
{% load crispy_forms_tags %}
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
</form>
In template:
{{ form|as_p}}
in forms.py:
select = forms.CharField(widget=forms.Select(choices=select_choices, attrs={'class ':'form-control'}))
name = forms.CharField(widget=forms.TextInput(attrs={'class ':'form-control'}))
Related
I'm trying to get just a basic model and form to show up with mongoengine and WTF forms, and following the basic instructions from the website aren't working for me. I'm sure it's something simple that is missing, but I've never used flask, mongoengine, or WTFforms, so I'm sort of
Here is my schema definition in models.seed
class PlandoSeed(db.Document):
def __init__(self, preset:str='open', num_players:int=2, num_plants:int=1, **entries: dict):
self.__dict__.update(entries)
self.preset = preset
self.num_players = num_players
self.num_plants = num_plants
preset: db.StringField()
num_players: db.IntField(min=2, max=6)
num_plants: db.IntField(min=1, max=6)
seeds :List[PlandoSeed] = [PlandoSeed('standard',2,2), PlandoSeed('open',4,1), PlandoSeed()]
PlandoSeedForm = model_form(PlandoSeed)
Then this is the route/view that I created in views.py:
#app.route('/seeds/create', methods = ['GET', 'POST'])
def create_seed():
form = PlandoSeedForm(request.form)
if request.method == 'POST' and form.validate():
# todo
redirect('/seeds/')
return render_template('new_seed.jinja', form=form)
Finally, this is my 'new_seed.jinja' template:
{% extends 'base.jinja' %}
{% block content %}
<h1>{% block title %} Create Seed {% endblock %}</h1>
<form method="POST" action="/seeds/create/">
{{ form.csrf_token }}
{% for field in form %}
{{ field }}
{% endfor %}
<input type="Submit" value="Go">
</form>
{% endblock %}
My expectation is that the Create Seed page will have a form with the default input for a text field and integer fields. However, the only field that is in the form object in the jinja template is the CSRF token.Here is what it looks like.
And this is the generated HTML for the form:
<h1> Create Seed </h1>
<form method="POST" action="/seeds/create/">
<input id="csrf_token" name="csrf_token" type="hidden" value="ImZkNzMwMTE1NDJmNDM4NmFjY2EwZDU1ODBjNGJiMjZiMDBhNzFmZGQi.YsRdgg.I8r_Q5RXpmV-r2AzlUNAQ0le7XY">
<input id="csrf_token" name="csrf_token" type="hidden" value="ImZkNzMwMTE1NDJmNDM4NmFjY2EwZDU1ODBjNGJiMjZiMDBhNzFmZGQi.YsRdgg.I8r_Q5RXpmV-r2AzlUNAQ0le7XY">
<input type="Submit" value="Go">
</form>
I've just started my first app with Django by following a video on YouTube.
The app is a students dashboard with 8 tools and features to help the student to make note, search for help, save books, etc.
When I follow the steps I get stuck in the creation of a new note but note from the admin side but from the actual notes template that has a crispy form and a create button.
The program is supposed for writing a title and description (the content of the note) and then press the create button. When I try to click, nothing is happening.
#This is the view.py page in the dashboard app :
from django.shortcuts import render
from . forms import *
from django.contrib import messages
# Create your views here.
def home(request):
return render(request, 'dashboard/home.html')
def notes(request):
if request.method == "POST":
form = NotesForm(request.POST)
if form.is_valid():
notes = Notes(user=request.user,title=request.POST['title'],description=request.POST['description'])
notes.save()
messages.success(request,f"Notes Added from {request.user.username} Successfully")
else:
form = NotesForm()
notes = Notes.objects.filter(user=request.user)
context = {'notes':notes,'form':form}
return render(request,'dashboard/notes.html',context)
and this is the notes.html page in the dashboard app > template folder > dashboard folder :
{% extends 'dashboard/base.html' %}
<!-- Load the static files here -->
{% load static %} {% load crispy_forms_tags %}
<!-- loading the crispy files must be here so now i write anything to
create some space and lines here we go baby lets add more -->
{% block content %}
<div class="container">
<div class="row">
{% for note in notes %}
<div class="col-md-3">
<a href="#">
<div class="card">
<div class="card-header">{{note.title}}</div>
<div class="card-body">{{note.description|slice:"0:100"}}</div>
<div class="card-footer mt-auto">
<i class="fa fa-trash fa-2x"></i>
</div>
</div>
</a>
</div>
{% endfor %}
<br /><br />
</div>
</div>
<br /><br />
<div class="container">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Notes</legend>
</fieldset>
{% crispy form %}
<div class="form-group">
<button href="" class="btn btn-outline-info" type="submit">Create</button>
</div>
</form>
</div>
{% endblock content %}
so, this the models.py file too
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Notes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
def __str__(self):
return self.title
class Meta:
verbose_name = "notes"
verbose_name_plural = "notes"
in case the problem is not here, please take a look on the inside this forms.py
from dataclasses import fields
from django import forms
from . models import *
class NotesForm(forms.ModelForm):
class Meta:
model = Notes
fields = ['title', 'description']
and .. urls.py
from django.urls import path
from . import views
urlpatterns = [
path('',views.home, name='home'),
path('notes',views.notes, name="notes")
]
There are many minor mistakes in the code:
It is {{form|crispy}} to display the form not {% crispy form %}.
You are also not using HttpResponseRedirect[django-doc] for redirecting, after saving form from POST data, you should always return an HttpResponse, its a good practice.
Try below code:
Notes.html
{% block content %}
{% load crispy_forms_tags %}
<div class="container">
<div class="row">
{% for note in notes %}
<div class="col-md-3">
<a href="#">
<div class="card">
<div class="card-header">{{note.title}}</div>
<div class="card-body">{{note.description|slice:"0:100"}}</div>
<div class="card-footer mt-auto">
<i class="fa fa-trash fa-2x"></i>
</div>
</div>
</a>
</div>
{% endfor %}
<br /><br />
</div>
</div>
<br /><br />
<div class="container">
<form method="POST" action="{% url 'notes' %}" novalidate>
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Notes</legend>
</fieldset>
{{form|crispy}}
<input type="submit" value="Create">
</form>
</div>
{% endblock content %}
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.shortcuts import render
from . forms import *
from django.contrib import messages
from django.urls import reverse
def home(request):
return render(request, 'dashboard/home.html')
def notes(request):
if request.method == "POST":
form = NotesForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
descrip = form.cleaned_data['description']
notes = Notes(
user=request.user, title=title, description=descrip)
notes.save()
messages.success(
request, f"Notes Added from {request.user.username} Successfully")
return HttpResponseRedirect(reverse('thanks'))
else:
form = NotesForm()
notes = Notes.objects.filter(user=request.user)
context = {'notes': notes, 'form': form}
return render(request, 'dashboard/notes.html', context)
def thanks(request):
return render(request, 'dashboard/thanks.html')
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('notes/', views.notes, name="notes"),
path('thanks/', views.thanks, name='thanks')
]
thanks.html
<body>
<h2>The form successfully submitted</h2>
</body>
Your forms.py can be remain same as it is.
I want the user to login using three fields, username, password and OTP ONLY.
Here is my .html file
{% extends "base.html" %}
{% load static %}
{% load bootstrap4 %}
{% block head %}
<title>HomePage</title>
{% endblock %}
{% block content %}
<div class="container">
<div style='width:500px;margin:0 auto;' class="panel panel-default">
<div class="panel-body">
<h1>Login</h1>
<form method="POST" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Login</button>
{% endbuttons %}
</form>
</div>
</div>
</div>
{% endblock %}
Here is the browser view of the .html file
I want to remove Otp Device and Otp Challenge as they are unnecessary for my case.
Here is my models.py file
from django.contrib.auth.models import AbstractUser
class ProjectUser(AbstractUser):
# add additional fields in here
def __str__(self):
return self.email
Here is my urls.py file
from django_otp.forms import OTPAuthenticationForm
from django.contrib.auth.views import LoginView
urlpatterns = [
path('user_login/', LoginView.as_view(template_name="accounts_app/user_login.html",
authentication_form=OTPAuthenticationForm), name='user_login'), ]
Here is the reference I used
Solution 1:
The straight forward way is to Subclass OTPAuthenticationForm to replace the form fields used for otp_device and otp_challenge by using the HiddenInput widget. In your app folder, create a new python file called forms.py and add the following
from django_otp.forms import OTPAuthenticationForm
from django import forms
class SimpleOTPAuthenticationForm(OTPAuthenticationForm):
otp_device = forms.CharField(required=False, widget=forms.HiddenInput)
otp_challenge = forms.CharField(required=False, widget=forms.HiddenInput)
In your urls.py file inside your app, add the import and replace the LoginView with the following
from .forms import SimpleOTPAuthenticationForm
path('user_login/', LoginView.as_view(template_name="accounts_app/user_login.html",
authentication_form=SimpleOTPAuthenticationForm), name='user_login'),
Solution 2:
Alternative option but requires more styling to fit the bootstrap form warning and other features. Start with using the following
Only display the fields you want in your template: Since otp_device and otp_challenge are not required, you can just leave them out. Use {% bootstrap_field form.<field> %} for each of the fields you want to display instead of {% bootstrap_form form %}. See here for all the options to customise the rendering of each field. Errors for each field can be displayed with {{ form.errors.<field> }} but you have to style them yourself.
In your case
{% bootstrap_field form.username %}
{% bootstrap_field form.password %}
{% bootstrap_field form.otp_token %}
I have simple user registration page, but its not saving to the database.
Issue: Register form displays, upon clicking submit button, doesn't do anything! Stays there (it should show a HttpResponse('User Registered') And save to db
I've know I'm missing something, but what? ideas please.
Views.py
from django.shortcuts import render
from django.views.generic import CreateView
from website.forms import RegisterUserForm
from django.http import HttpResponseForbidden
# Create your views here.
class RegisterUserView(CreateView):
form_class = RegisterUserForm
template_name = "account/register.html"
# Overide dispatch func - check if the user is authenticated or return forbidden
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated():
return HttpResponseForbidden()
return super(RegisterUserView, self).dispatch(request, *args, **kwargs)
# Overide form valid method behaviour
def form_valid(self, form):
# False commit - don't save to db, locally cleaning users password first
user = form.save(commit=False)
user.set_password(form.cleaned_data['password'])
user.save();
# Change to redirect - later one!
return HttpResponse('User Registered')
def Home(request):
return render(request, 'account/home.html')
Register.html
{% extends 'base.html' %}
{% block title %}
Register
{% endblock %}
{% block head %}
{% load static %}
<link href="{% static 'forms.css' %}" rel="stylesheet">
{% endblock %}
{% block heading %}
<h1>Register</h1>
{% endblock %}
{% block body %}
<div class="bg-contact2" style="background-image: url('images/bg-01.jpg');">
<div class="container-contact2">
<div class="wrap-contact2">
<form class="contact2-form validate-form">
<span class="contact2-form-title">
<h2> Teacher's Register </h2>
</span>
{% csrf_token %}
{{ form.as_p }}
<div class="container-contact2-form-btn">
<div class="wrap-contact2-form-btn">
<div class="contact2-form-bgbtn"></div>
<button class="contact2-form-btn">
Send Your Message
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!--
<h2>FORM</h2>
<form action="{% url 'register' %}" class="contact2-form validate-form" method="post ">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Register">
</form> -->
{% endblock %}
forms.py
from django import forms
from django.contrib.auth.models import User
class RegisterUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(widget=forms.PasswordInput)
class Meta:
# Connect to the user model and select which fields we want input for user model
model = User
fields = ['username', 'email']
# Validate password matched / and clean them
def clean_password2(self):
cd = self.cleaned_data
if cd['password2'] != cd['password']:
raise ValidationError("Password don't match")
return cd['password2']
I think you are missing the type in your button tag:
<form method="POST">
<span class="contact2-form-title">
<h2> Teacher's Register </h2>
</span>
{% csrf_token %}
{{ form.as_p }}
<div class="container-contact2-form-btn">
<div class="wrap-contact2-form-btn">
<div class="contact2-form-bgbtn"></div>
<button type="submit" class="contact2-form-btn">
Send Your Message
</button>
</div>
</div>
</form>
form tag should have an attribute action to tell where to take the data of your form to. So in Register.html you should add
action="{% url 'nameofyourviewgiveninurls.py'%}"
in your form tag
Is it possible to write some attributes to a model field which can be used later to differentiate the different fields in the template?
model.py
from django.db import models
class Person(models.Model):
first_name = models.CharField("i am the Label", max_length=30)
last_name = models.CharField("i am other Label", max_length=30, customattr="Custom")
forms.py
class PersonForm(ModelForm):
class Meta:
Person
template.html
<form action="" method="post">{% csrf_token %}
{% for field in form %}
{% ifequal field.customattr 'Custom' %} # HOW COULD THIS WORK?
<p>Hello world.</p>
{{ field }}
{% else %}
<p>This is not Custom</p>
{{ field }}
{% endifequal %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
Any hints?
Not really possible; field in your template code is a form field, not a model field. I would shift the presentation logic from the model into the template, and do something like this:
<form action="" method="post">{% csrf_token %}
{% for field in form %}
{% if field.name == 'last_name' or field.name == 'another_field' %}
<p>Hello world.</p>
{{ field }}
{% else %}
<p>This is not Custom</p>
{{ field }}
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
(the == operator was added in Django 1.2)
I don't understand why yo would like to do this. If you would like to define custom html to your ModelForm field you can override it like this:
class PersonForm(ModelForm):
class Meta:
Person
first_name = forms.CharField(
required = True,
widget = forms.TextInput(attrs={'style':'width:100px;'},
)
Like this you can tell Django how you would like to render your html.
You can find more detail in the doc https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets