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
Related
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'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 }}">
...
What I'm trying to do is execute a function when the user clicks the "add to cart" button, the product displayed on the screen will be added to the cart model. So far i've figured out how to add objects to the cart from the shell. What i don't know is how to call a python function with html and how to pass the object to it. Thank you in advance.
my template.html:
{% extends 'templates/header.html' %}
<title>{% block head_title %}{{ object.name }} - {{ block.super }}{% endblock head_title %}</title>
{% block head %}
{{ block.super }}
{% load staticfiles %}
<link rel = "stylesheet" href = "{% static 'css/products_detail.style.css' %}" type = "text/css"/>
{% endblock head %}
{% block content %}
<div id='Product-Page'>
<p>{{ object.name }}</p>
<hr>
<div id='Product-Image'>
<img src='{{ object.image.url }}' alt='{{ object.image.name }}'/>
</div>
<div id='Product-Details'>
<p id='Product-Name'>{{ object.name }}</p>
<p id='Product-Description'><small>{{ object.description }}</small></p>
</div>
<div id='Product-Buy'>
<p id='Product-Price'>{{ object.price }} лв.</p>
<p id='Product-Quantity'>{{ object.quantity }} </p>
<form class='Product-Form' method='post' action='#'>
{% csrf_token %}
<input class='Product-Button' type='submit' value='Buy Now'>
</form>
<form class='Product-Form' method='get' action=''>
{% csrf_token %}
<input class='Product-Button' type='submit' value='Add to cart'>
</form>
</div>
<hr>
</div>
{% endblock content%}
my view:
class ProductDetailView(DetailView):
template_name = 'products/products_detail.html'
def get_object(self, *args, **kwargs):
slug = self.kwargs.get('slug')
return get_object_or_404(Product, slug=slug)
You can add hidden inputs to each form (both of which should be POST methods, not GET) then add a post method to your view. Something like:
<form class='Product-Form' method='post'>
{% csrf_token %}
<input name="buy-now" hidden>
<input name="pk" value="{{ object.pk }}" hidden>
<button type="submit" class="btn">Buy Now</button>
</form>
<form class='Product-Form' method='post'>
{% csrf_token %}
<input name="add-to-cart" hidden>
<input name="pk" value="{{ object.pk }}" hidden>
<button type="submit" class="btn">Add to cart</button>
</form>
Then in your view:
class ProductDetailView(DetailView):
template_name = 'products/products_detail.html'
def get_object(self, *args, **kwargs):
slug = self.kwargs.get('slug')
return get_object_or_404(Product, slug=slug)
def post(self, request, *args, **kwargs):
name = request.POST.get("pk")
product = Product.objects.get(pk=pk)
if "buy-now" in request.POST:
#Do something to buy.
print('buy now ' + product.name)
elif "add-to-cart" in request.POST:
#Add to cart.
print('add to cart ' + product.name)
return redirect('home')
Or you can do it via AJAX if you don't want to reload the page.
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",
)