I'm using Django's generic editing views CreateView, UpdateView, etc. together with the auto-generated HTML forms and it works fine:
# views.py
class TagCreate(CreateView):
template_name = 'app/tag_form.html'
model = Tag
fields = ['name', 'description', 'color']
class TagUpdate(UpdateView):
model = Tag
fields = ['name', 'description', 'color']
<!-- app/tag_form.html -->
{% extends 'app/base.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
{% endblock %}
Now, I want to customize the generated form {{ form.as_p }} with bootstrap:
{% extends 'app/base.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="nameInput">Name</label>
<input class="form-control" type="text" id="nameInput" placeholder="Name" value="{{ tag.name }}">
</div>
<div class="form-group">
<label for="descrInput">Description</label>
<input class="form-control" type="text" id="descrInput" placeholder="Description" value="{{ tag.description }}">
</div>
<div class="form-group">
<label for="colorInput">Color</label>
<input class="form-control" type="color" id="colorInput" placeholder="Color" value="{{ tag.color }}">
</div>
<input type="submit" value="Save">
</form>
{% endblock %}
The page renders nicely exactly how I want it to, but when I click the "Save" button, nothing happens and the data is no longer saved, nor am I forwarded to the detail view like I was before.
I tried following the Django documentation on how to render fields manually; again, it's rendered correctly, but the data isn't saved.
How can I properly customize forms and still use my generic editing views?
Edit: My full code his here.
Following the documentation you have to access the form inputs manually and django will populate them accordingly in the template.
{% extends 'app/base.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="nameInput">Name</label>
{{ form.name }}
</div>
<div class="form-group">
<label for="descrInput">Description</label>
{{ form.description }}
</div>
<div class="form-group">
<label for="colorInput">Color</label>
{{ form.color }}
</div>
<input type="submit" value="Save">
</form>
{% endblock %}
From there, to add classes, you will have to override the CreateView get_form in order to add in what we need:
class TagCreate(CreateView):
template_name = 'app/tag_form.html'
model = Tag
fields = ['name', 'description', 'color']
def get_form(self, form_class):
form = super(TagCreate, self).get_form(form_class)
form.fields['name'].widget = forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Name' })
form.fields['description'].widget = forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Description' })
form.fields['color'].widget = forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Color' })
return form
Although, this would be a lot cleaner if using ModelForms
in your form input tag set the "name" attribute, field name as value
something like this:
...
<input class="form-control" type="text" id="nameInput" placeholder="Name" name="name" value="{{ tag.name }}">
...
<input class="form-control" type="text" id="descrInput" placeholder="Description" name="description" value="{{ tag.description }}">
...
<input class="form-control" type="color" id="colorInput" placeholder="Color" name="color" value="{{ tag.color }}">
...
Related
I want to receive users that a user has chosen to create a group chat. In an Aiohttp to get variable from HTML select tag, I use self.request.post()['variablename']:
#login_required
async def post(self):
data = await self.request.post()
chat_topic = data.get('chat_topic', '').lower()
users = data['users']
await Chat.create(topic=chat_topic, users=group_users)
This is my rooms.html:
{% extends 'base.html' %}
{% block content %}
<form class="form-signin" method="POST" action="{{ app.router['create_chat'].url_for() }}">
<h2 class="form-signin-heading">Create new chat</h2>
<label for="chat_topic" class="sr-only">chat topic</label>
<input name="chat_topic" type="text" id="chat_topic" class="form-control" maxlength="32" placeholder="chat topic" required autofocus>
<label for="users"> Choose users: </label>
<select name="users" id="users" multiple="multiple">
{% for user in users %}
<option value="{{ user.id }}">
{{ user.username }}
</option>
{% endfor %}
</select>
<button class="btn btn-lg btn-primary btn-block" type="submit">create chat</button>
</form>
{% endblock %}
Unfortunately, I receive only the last selected user as a string, not all of selected users. How can I get an array of selected users in aiohttp from an HTML select tag?
I know that in Django, I could do something like this:
users = request.POST.getlist('users')
I will appreciate any help!
I wanted to modify the way my forms is displayed using html and css.
Here is the <form> part of my HTML:
<form action="" method="post" enctype='multipart/form-data'>
{% csrf_token %}
<div>
<input type="text" name="post_title" placeholder="Forum title" id="id_post_title">
<textarea name="post_body" placeholder="Forum content" id="id_post_body"></textarea>
<div class="authors"> <!-- This class is to call my Users model -->
<select name="author" id="id_author">
<option value="">----Select Author----</option>
{% for author in authors %}
<option value="{{ author.first_name }} {{ author.last_name }}">{{ author.first_name }} {{ author.last_name }}</option>
{% endfor %}
</select>
</div>
<div>
<label>
<input type="file" accept="image/" name="forum_image" required id="id_forum_image" >Upload Image
</label>
</div>
<input type="submit" value="Save Post" class="save_post">
</div>
</form>
I tried form.as_p and it all worked just fine. Did I made a mistake in my HTML? Here is my forms.py:
class AddForum(forms.ModelForm):
class Meta:
model = Forum
fields = 'all'
labels = {
'post_title': 'Title of your post:',
'post_body': 'Content of your post:',
'author': 'Author:',
'forum_image': 'Attach image:',
}
def __init__(self, *args, **kwargs):
super(AddForum, self).__init__(*args, **kwargs)
self.fields['forum_image'].required = False
The problem lies with my <option value="{{ something }}". What value needs is {{ something }}'s id and not the name itself.
The code should be:
<option value="{{ author.id }}">{{author.first_name }} {{ author.last_name }}</option>
I want to iterate over fields list in Django so as to create a generalized template for major of my forms.
The problem I face is that my form is not considered as valid when I'm using the input fields.
I want to stick to input fields as I'm using materialize css .
Below is my
form_template.html
<div class="row ">
{% for field in form %}
<div class="form-group">
{% ifequal field.name "password" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="password" class="{{
field.name }}">
<label for="{{ field.name }}">{{ field.label }}</label>
</div>
</div>
{% endifequal %}
{% ifnotequal field.name "password" %}
{% ifequal field.name "email" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="{{ field.name }}" class="validate">{{ form.field }}
<label for="{{ field.name }}" data-error="Not a valid email"
data-success="Valid Email">{{ field.label }}</label>
</div>
</div>
{% endifequal %}
<br>
{% ifnotequal field.name "email" %}
{% ifequal field.name "album_logo" %}
<div class="file-field input-field col s3 xl12">
<div class="btn">
<span>File</span>
<input type="file" multiple>
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload an album cover">
</div>
{% endifequal %}
{% ifnotequal field.name "album_logo" %}
{% ifequal field.name "date_joined" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="date" class="datepicker">{{ form.field }}
<label for="{{ field.name }}">{{ field.label }}</label>
</div>
</div>
{% endifequal %}
{% ifnotequal field.name "date_joined" %}
<div class="row">
<div class="input-field col s3 xl12">
<input id="{{ field.name }}" type="text">
<label for="{{ field.name }}">{{ field.label }}
</label>
</div>
</div>
{% endifnotequal %}
{% endifnotequal %}
{% endifnotequal %}
{% endifnotequal %}
</div>
{% endfor %}
</div>
and UserFormView Class in views.py
class UserFormView(View):
form_class = UserForm
template_name = "music/registration_form.html"
# Display a blank form for a new user
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
# Process form Data here
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
# Cleaned (Normalized or Formatted) Data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
# Returns User Objects if credentials are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request,user)
return HttpResponseRedirect('music:index')
else:
return render(request, self.template_name, {'form': form})
Would really appreciate some help, thanks.
When you want to style your form I would suggest to use Widget Tweaks. When you install it correctly you can use it in your template like:
Css:
.inputStyle{
width: 500px;
border: 1px solid black;
border-radius: 5px;
}
.slide{
...
}
HTML:
<form method='POST' action="/" enctype='multipart/form-data'>
{% load widget_tweaks %}
{% csrf_token %}
<span class="">Post the Image via Url: {{form.image_url|add_class:"inputStyle" }}</span>
<span class="" >Please select an option {{ form.Options|add_class:"slide" }}</span>
</form>
Another way to style your forms is to install Widgets in the forms.py
You can install things like Django Select and add it into the form like:
class PostForm(forms.ModelForm):
language = forms.MultipleChoiceField(widget=Select2MultipleWidget(attrs={'data-placeholder': 'Language'}),choices=settings.LANGUAGES)
class Meta:
model = Post
fields=[
'title',
'content',
'image_url',
'language',
.....
]
don't forget to use {{ form.media.js }}in the form.
I hope you get that going. The way you do it now is not the best way ;)
p.s. forgot to mention Django Crispy Form. They are fast to install and easy to handle but I would suggest using widget tweaks since you can style everything with CSS. Crispy can be tricky sometimes and you have to read into the docs...
I am using django-registration-redux and i have a login form in my navbar. I would like to stay on the same page after login. ie. if i am at mypage.com/polls/example after login i want to be back on mypage.com/polls/example not on url set in settings.
Login from in html looks like this:
{% url "auth_login" as login_url %}
{% if login_url not in request.get_full_path %}
<li>
<form class="navbar-form" method="POST" action={{ login_url }}>{% csrf_token %}
<input type="text" class="form-control top-bar" name="username" placeholder="email" />
<input type="password" class="form-control top-bar" name="password" placeholder={% trans "password" %} />
<button type="submit" class="btn btn-default">{% trans "Login" %}</button>
</form>
</li>
{% endif %}
How do i do that?
You could use next :
<form class="navbar-form" method="POST" action="{{ login_url }}?next={{request.path}}">
This will add a GET request to your form that points back to the current page.
For request.path to work you have to define template context processors in your settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
)
I have problem that in my login.html file the email field won't be displayed. Here is the html code:
<form method="POST" id="signup_form" action="{% url 'account_login' %}" class="registration-form">{% csrf_token %}
<div class="form-group">
<!-- <input type="text" name="email" placeholder="Email" class="form-email form-control" id="form-email"> -->
{{ form.email }}
</div>
<div class="form-group">
<!-- <input type="password" name="password" placeholder="Lozinka" class="form-about-yourself form-control" id="form-about-yourself"></input> -->
{{ form.password}}
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">
{% trans "Zaboravili ste oznaku?" %}
</a>
<br>
<button type="submit" class="btn">Prijavite se</button>
</form>
So the email field wont be displayed, but the passwod field is. Also the password field is displayed but I cannot customize it. Here is how I'm trying to do that:
class AuthenticationForm(forms.ModelForm):
"""
Login form
"""
class Meta:
model = get_user_model()
fields = ['email', 'password']
def __init__(self, *args, **kwargs):
super(AuthenticationForm, self).__init__(*args, **kwargs)
self.fields['email'].widget = forms.EmailInput(attrs={
'placeholder': 'Email adresa*',
'required': True,
'class': "form-email form-control"
})
self.fields['password'].widget = forms.PasswordInput(attrs={
'placeholder': 'Lozinka*',
'required': True,
'class': "form-first-name form-control"
})
I am having all of this for my signup page and it works fine. I tried with form.as_p and it works fine, but I want my own style. Thank you for your time.
Use {{ form.login }} to display the email field, instead of {{ form.email }}
From https://github.com/pennersr/django-allauth/blob/master/allauth/account/forms.py you can see that Django login form has three fields, login, password and remember. So in you case just do
<form method="POST" id="signup_form" action="{% url 'account_login' %}" class="registration-form">{% csrf_token %}
<div class="form-group">
<!-- <input type="text" name="email" placeholder="Email" class="form-email form-control" id="form-email"> -->
{{ form.login}}
</div>
<div class="form-group">
<!-- <input type="password" name="password" placeholder="Lozinka" class="form-about-yourself form-control" id="form-about-yourself"></input> -->
{{ form.password}}
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">
{% trans "Zaboravili ste oznaku?" %}
</a>
<br>
<button type="submit" class="btn">Prijavite se</button>
</form>
I'm not a django expert, but if you only want to style your inputs, it might be better to use django-widget-tweaks. It keeps styling and python code seperated.
So first you can install it with:
pip install django-widget-tweaks
Then add 'widget_tweaks' to INSTALLED_APPS.
Load widget_tweaks in your template:
{% load widget_tweaks %}
And in your case you would put something like:
{% render_field form.email placeholder='Email adresa*' required="required" class="form-email form-control" %}
{% render_field form.password placeholder='Lozinka*' required="required" class="form-first-name form-control" type="password" %}
in your template instead of:
{{ form.email }}
{{ form.password }}
If you choose to do this, I think you don't need __init__() method in your AuthenticationForm
EDIT1:
In my case I also had to add type="password" to the password render_field tag