i tried the following code to create a form using Django crispy_forms but when it rendered gives simple html for layout
forms.py
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
class SimpleForm(forms.Form):
username = forms.CharField(label="Username", required="True")
password = forms.CharField(label="Password", required="True", widget=forms.PasswordInput)
remember = forms.BooleanField(label="Remember Me !")
helper = FormHelper()
helper.form_method = 'POST'
helper.add_input(Submit('login', 'login', css_class='btn-primary'))
index.html
{% load crispy_forms_tags %}
<html>
<head>
<link rel="stylesheet" type="text/css" href="/home/vish/demo/new_form/form_demo/templates/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="row">
{% crispy form %}
</div>
</div>
</body>
</html>
what's I'm doing wrong ? Please suggest the necessary improvements.
You can define the layout, for example:
self.helper.layout = layout.Layout(
Div(
Div(
Fieldset('',
Div(
Div(
'first_name',
css_class="col-sm-6",
),
Div(
'last_name',
css_class="col-sm-6",
),
css_class="row",
),
),
css_class='row'
),
)
Obs: I used bootstrap classes in this example, that what you should do!
Related
When the page loads I am seeing the error of - "This field is required" with the input form 'Title' highlighted with the red board. I would expect that this should only show after the Save button is pressed. I can toggle the message on and off with self.helper.form_tag but the behavior seems incorrect to me, it seems as though it is trying to submit before I click save.
Am I doing something wrong or is this expected behavior? If it is expected is there a way to change it to only show the warnings after Save?
forms.py
from django import forms
from .models import Request, RequestDocument
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Field, Div, Layout
class RequestForm(forms.Form):
title = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'title'}))
rfp_No = forms.CharField(widget=forms.TextInput(attrs={}), required=False)
company_Name = forms.CharField(widget=forms.TextInput(attrs={}), required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
#self.helper.form_tag = False
self.helper.help_text_inline = True
self.helper.layout = Layout(
Div(Field('title'), css_class='col-md-12', ),
Div(
Div(Field('rfp_No'), css_class='col-md-6', ),
Div(Field('company_Name'), css_class='col-md-6', ),
css_class='row',
),
)
create.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">
{% csrf_token %}
{% crispy form %}
<button type="submit" class=" d-block btn btn-lg btn-success mt-4 w-50 mx-auto">
Save
</button>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function(){
$(".active").removeClass("active");
$("#link-create").addClass("active");
});
</script>
adding self.helper.form_show_errors = False to the init hides the errors but this the block actual errors from showing such as if the max length was exceeded.
I eventually figured this out by splitting the POST and GET methods in my form.
forms.py
form = RequestForm()
if request.method == 'POST':
##Do Post Stuff
elif request.method == 'GET':
##Do Get Stuff
else:
context = {
}
return render(request, "requests/create.html", context)
I am using django crispy_forms.helper and crispy_forms.layout to create radio button with options. The label and radio button options are overlapping.
The code which i am using is :
forms.py
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, HTML, Layout, Row, Div, Fieldset,ButtonHolder,Column
from crispy_forms.bootstrap import InlineRadios, PrependedAppendedText, Div
ROUTER_OPTIONS = (
('', 'Choose router...'),
('FIP', 'First IP in range'),
('AM', 'Add Manually')
)
class DhcpForm(forms.ModelForm):
router = forms.ChoiceField(label='Router',
choices=ROUTER_OPTIONS,
initial='', widget=forms.RadioSelect)
def __init__(self, *args, **kwargs):
super(DhcpForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
self.helper.layout = Layout(
Row(
Column('dhcp_member', css_class='form-group col-md-6 mb-0'),
Column('router', css_class='form-group col-md-6 mb-0'),
css_class='form-row'
)
html
{% block content %}
{% crispy form %}
{% endblock %}
The view which i am getting:
overlapped view
In your Choice field Add the style function and set the display as flex given below.
Column('router', css_class='form-group col-md-6 mb-0', style='display: flex')
For some reason, suggestions from django-autocomplete-light 3.5.0 are displayed beyond the drop-down list, to the right (there's narrow blue rectangle visible that indicates suggestions):
I'm able to reverse the widget's url and obtain correct suggestions. Everything's working fine but rendering - when I click on this narrow rectangle, correct value appears in the edit box. I collected all the static files. I'm working on Linux 20.04 LTS, Chrome 83.0.4103.106, python 3.7.7, django 3.0.3, bootstrap 4.5.0 and font-awesome 4.7.0. Here is the code (except settings) that I wrote
forms.py
class OpinionForm(forms.ModelForm):
# user field is defined as hidden and disabled such that it couldn't be changed
user = forms.ModelChoiceField(
widget=forms.HiddenInput,
queryset=get_user_model().objects.all(),
disabled=True
)
# defining all the fields with autocomplete feature
country = forms.ModelChoiceField(
queryset=Country.objects.all(),
widget=autocomplete.ModelSelect2(url="country_autocomplete")
)
class Meta:
model = Opinion
fields = ("content",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["country"].label = "Kraj"
self.fields["content"].label = "Treść"
models.py
class Country(models.Model):
name = models.CharField(max_length=200, null=False)
def __str__(self):
return self.name
class Opinion(models.Model):
user = models.ForeignKey(to=settings.AUTH_USER_MODEL)
content = models.TextField()
created = models.DateTimeField(auto_now=True)
urls.py
urlpatterns = [
path("add_opinion", views.CreateOpinionView.as_view(), name="add_opinion"),
path("country-autocomplete/", CountryAutocomplete.as_view(create_field="name"),
]
views.py
class CountryAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated:
return Country.objects.none()
qs = Country.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
class CreateOpinionView(LoginRequiredMixin, CreateView):
form_class = OpinionForm
template_name = "opinions/create.html"
def get_initial(self):
"""
When our view is instantiating the form, it will pass the result of get_initial() as the 'initial'
argument and the POST data as the 'data' argument
:return:
"""
return {
"user": self.request.user.id
}
def form_valid(self, form):
"""
If a form is valid, CreateView will call form_valid.
If the form isn't valid, CreateView will re-render the template.
:param form:
:return:
"""
action = self.request.POST.get("action")
# when we want to save, we will call the original form_valid method
# the original method saves the new opinion
if action == "SAVE":
# save and redirect as usual
return super().form_valid(form)
return HttpResponseBadRequest()
create.html
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block title %}Dodaj opinię{% endblock %}
{% block content %}
<div class="col-md-12">
<h1>Dodaj opinię</h1>
<form method="post">
{{ form | crispy }}
{% csrf_token %}
<button class="btn btn-primary" type="submit" name="action" value="SAVE">Zapisz</button>
</form>
</div>
{% endblock %}
{% block footer %}
<script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
{{ form.media }}
{% endblock %}
Your code seems to work fine for me, so the error must be somewhere else, probably somewhere in your CSS.
Your code had two errors that prevented it from running though:
on_delete is a required argument for ForeignKey since Django 2.0. Are you sure about the versions you are running?
- user = models.ForeignKey(to=settings.AUTH_USER_MODEL)
+ user = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
I assume this one was a copy-paste error when creating the question
- path("country-autocomplete/", CountryAutocomplete.as_view(create_field="name"),
+ path("country-autocomplete/", CountryAutocomplete.as_view(create_field="name"), name='country_autocomplete'),
Here are additional details of my setup, perhaps you can find what is different from yours:
Versions:
Django==3.0.3
django-autocomplete-light==3.5.0
django-crispy-forms==1.9.1
base.html:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock title %}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
</head>
<body>
{% block content %}
{% endblock %}
{% block footer %}
{% endblock %}
</body>
</html>
settings.py:
# ...
INSTALLED_APPS = [
# ...
'dal',
'dal_select2',
'crispy_forms',
'yourappname'
]
# ...
# (everything else left at defaults)
I try to enhance my all auth's signup form with Crispy-form but it's not working :)
I modify the allauth form in the forms.py to hide the labels and add the button
My current problem is that the "self.helper.layout = Layout" in the forms.py makes the fields to disappear in the template, but if I comment the self.helper.layout = Layout, I don't have a button to validate my form x(
I would like to have my fields and a working submit button for my form,
Thanks for your help!
details below
forms.py
from django import forms
from allauth.account.forms import SignupForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit,Field
from crispy_forms.bootstrap import FormActions
class MySignupForm(SignupForm):
def __init__(self, *args, **kwargs):
super(MySignupForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
self.helper.layout = Layout(
FormActions(
Submit('submit', 'Sign-up', css_class = 'btn-primary')
),
)
I also define in my settings.py that I was using a custom form as signup
# CUSTOM : Allauth Setup part
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
# `allauth` specific authentication methods, such as login by e-mail
'allauth.account.auth_backends.AuthenticationBackend',
)
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False
SOCIALACCOUNT_QUERY_EMAIL = ACCOUNT_EMAIL_REQUIRED
#Since users don't have account on the landing page, sign up redirect to thank you page
LOGIN_REDIRECT_URL = '/thank-you'
ACCOUNT_FORMS = {'signup': 'public.forms.MySignupForm'}
I overrided the allauth template with this version
{% extends "base.html" %}
{% load socialaccount %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block head_title %}{% trans "Signup" %}{% endblock %}
{% block content %}
<section id="contact">
<div class="row">
<div class="container">
<div class="col-lg-12 text-center">
<h1 class="section-heading">{% trans "Sign Up" %}</h1>
</div>
<form class="signup" id="signup_form" method="post" action="{% url 'thankyou' %}">
{% crispy form %}
</form>
</div>
</div>
</section>
{% endblock %}
{% crispy form %} already declares by itself <form></form>.
I think this double declaration of <form> confuses the browser.
replace:
<form class="signup" id="signup_form" method="post" action="{% url 'thankyou' %}">
{% crispy form %}
</form>
by:
{% crispy form %}
and insert into forms.py:
class MySignUpForm(SignupForm):
def __init__(self, *args, **kwargs):
super(MySignUpForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'signup_form'
self.helper.form_class = 'signup'
self.helper.form_method = 'post'
self.helper.form_action = reverse('thankyou')
# and then the rest as usual:
self.helper.form_show_labels = False
self.helper.add_input(Submit('signup', 'Sign Up'), css_class='btn btn-primary'))
I am currently using the django auth_views.login to log my users into their accounts.
I need to pass a user's attributes such as pk/username/etc. to my user profile view.
my profile url is:
url(r'^(?P<pk>[\w.#+-]+)$', ProfileDashboardView , name='dashboard')
Once the user is logged in, how would I get their user attributes such as pk/id/username/etc. to pass into the url?
I am using TDD to test before actually moving forward with my view.
This is my view so far:
#login_required
def ProfileDashboardView(request, name=None):
usr_name = IbkUser.objects.get(name=name)
return render(request, 'profiles/profile_dashboard.html')
I am using an AbstractBaseUser model for my user accounts that extends the USER model and uses the email as the username for login purposes.
I am also using AuthenticationForm for the login form and crispy forms for styling.
my form:
class LoginAuthenticationForm(AuthenticationForm):
"""
A user login form for registered users.
"""
username = forms.EmailField(label='Email', required=True, widget=forms.TextInput(attrs={'id': 'login_username'}))
password = forms.CharField(label='Password', required=True,widget=forms.PasswordInput(attrs={'id': 'login_password'}))
def __init__(self, *args, **kwargs):
super(LoginAuthenticationForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'loginForm'
self.helper.form_method = 'post'
self.helper.layout = Layout(
PrependedText('username', "<span class='glyphicon glyphicon-envelope'></span>", active=True),
PrependedText('password', "<span class='glyphicon glyphicon-lock'></span>", active=True),
FormActions(
Submit('submit', 'Submit', css_class ='btn btn-success btn-lg btn-block'),
),
)
and this is my login template:
{% extends "auths/base.html" %}
{%load staticfiles%}
{% load crispy_forms_tags%}
{%block auths_title%}Login{%endblock auths_title%}
{%block auths_css%}{%endblock auths_css%}
{%block auths_body%}
<div class="row" id="signup-container">
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="page-header text-info text-center">
<h2>Login</h2>
</div>
{% crispy form form.helper %}
<p class="text-center">
Forgot your password? Reset Password
</p>
<p class="text-center">
<small>Don't have an account ? Sign up</small>
</p>
<div class="col-md-4"></div>
</div>
</div>
{%endblock auths_body%}
or should I just do my own custom view? lol
What you need is a redirect...
from django.shortcuts import redirect
from django.core.urlresolvers import reverse_lazy
def my_login(request)
# your login stuff...
return redirect(reverse_lazy('dashboard',kwargs={'name':request.user.username}))