What's difference between two methods and which is better for long run ? Is there any advantage one over other?
To add a staff:
(1st Method)
views.py
def add_staff(request):
return render(request, 'hod_template/add_staff_template.html')
def add_staff_save(request):
if request.method != 'POST':
return HttpResponse('Method not allowed')
else:
first_name = request.GET.get('first_name')
last_name = request.GET.get('last_name')
username = request.GET.get('username')
email = request.GET.get('email')
password = request.GET.get('password')
address = request.GET.get('address')
try:
user = CustomUser.objects.create_user(username=username, password=password, email=email, last_name=last_name, first_name=first_name, user_type=2)
user.staffs.address = address
user.save()
messages.success(request, 'Staff Added Successfully')
return HttpResponseRedirect('/add_staff')
except:
messages.error(request, 'Failed to Add Staff')
return HttpResponseRedirect('/add_staff')
urls.py
path('add_staff/', add_staff),
path('add_staff_save/', add_staff_save),
add_staff.html
<form role="form" action="/add_staff_save">
{% csrf_token %}
<div class="card-body">
<div class="form-group">
<label>Email address</label>
<input type="email" class="form-control" name="email" placeholder="Enter email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" placeholder="Password" name="password">
</div>
<!-- same for first_name, last_name, username, address -->
<div class="card-footer">
<button type="submit" class="btn btn-primary btn-block">Add Staff</button>
</div>
</div>
</form>
(2nd Method)
make a form in forms.py of all fields first_name, last_name, username, address
and then call in view and validate it.
forms.py
class StaffForm(forms.ModelForm):
class Meta:
model = Staff
fields = ('first_name', 'last_name', 'username', 'address')
views.py
def add_staff(request):
if request.method == 'POST':
form = StaffForm(data=request.POST)
if form.is_valid():
messages.success(request, 'Staff Added Successfully')
form.save()
else:
form = StaffForm()
return render(request, 'staff.html', {'form':form})
urls.py
path('add_staff/', add_staff),
staff.html
<form role="form" action="/">
{% csrf_token %}
{{ form.as_p }} <!-- render form as paragraph -->
</form>
Both methods work well and staff model have all the required field.
Sorry for long question since its getting too long I'm not adding staff model. If you need plz let me know.
of course the second method is much way better than the first one
because you should do cleaning and validation in other files like forms.py in each individual section
and also you can add more options and other things that maybe will be useful after a time
and you should be aware of that and predict some changes for improvement too!
and with making forms and use generics , you will write less code than doing it by yourself in hardcode in views.
so don't hesitate and choose method2
2nd method is better than 1st one. 2nd method give more flexibility you only have to make a form in forms.py and you can use it in different locations while for 1st method you have to use 2 urls just to show form and save it . Also you can use filters like crispy_forms_tags on form as {{ form|crispy }}. So obviously in long run 2nd method is better.
Related
I am not using django default admin dashboard and i am using my own custom template for the admin.but here i got some problem while editing and updating the user.I want to make email of every user unique in the database this code in my forms.py does pretty well while adding the user but while updating it i got some problem regarding the email.Since I have done the email unique in forms.py it is giving me error while updating also.How can i update users so that the edited user can have the same email but not same as the other user's email address.
forms.py
class RegisterForm(UserCreationForm):
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise ValidationError('Email Already Exists')
return email
class Meta:
model = User
fields = ['username', "email", "password1", "password2",'is_superuser','is_staff','is_active']
views.py
def register(request):
if not request.user.is_superuser:
messages.warning(request, 'Permission Denied.You have no permission to register users.')
return redirect('students:home')
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.save()
messages.success(request,'user created with username {}'.format(user.username))
return redirect('students:our_users')
else:
form =RegisterForm()
return render(request,'students/register.html',{'form':form})
def editusers(request,id):
if not request.user.is_superuser:
messages.warning(request, 'Permission Denied.You have no permission to perform this action.')
return redirect('students:our_users')
user = User.objects.get(id=id)
return render(request,'students/edit_users.html',{'user':user})
def updateusers(request,id):
if not request.user.is_superuser:
messages.warning(request, 'Permission Denied.You have no permission to perform this action.')
return redirect('students:our_users')
user = User.objects.get(id=id)
form = RegisterForm(request.POST,instance=user)
if form.is_valid():
user = form.save(commit=True)
user.save()
messages.success(request,'{} updated'.format(user.username))
return redirect('students:our_users')
else:
messages.error(request,'Error in Form')
return redirect('students:edit_user',user.id)
register template
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<div class="text-xs-right">
<button type="submit" class="btn btn-info">Add</button>
</div>
</form>
edituser template
<form action="{% url 'students:update_user' user.id %}" method="post">
{% csrf_token %}
<div class="form-group"><label for="id_username">Username</label><input type="text" name="username" maxlength="150" autofocus class="form-control" value="{{user.username}}" placeholder="Username" title="Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only." required id="id_username">
<small class="form-text text-muted">Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.</small>
</div>
<div class="form-group"><label for="id_email">Email</label><input type="email" name="email" value="{{user.email}}" class="form-control" placeholder="Email" title="" required id="id_email"></div>
<div class="form-group"><label for="id_password1">Password</label><input type="password" name="password1" value="{{user.password}}" class="form-control" placeholder="Password" title="Your password must contain at least 8 characters.Your password can't be entirely numeric." required id="id_password1">
<small class="form-text text-muted"><ul><li>Your password must contain at least 8 characters.</li><li>Your password can't be entirely numeric.</li></ul></small>
</div>
<div class="form-group"><label for="id_password2">Password confirmation</label><input type="password" name="password2" value="{{user.password}}" class="form-control" placeholder="Password confirmation" title="Enter the same password as before, for verification." required id="id_password2">
<small class="form-text text-muted">Enter the same password as before, for verification.</small>
</div>
<div class="form-group"><div class="form-check"><input type="checkbox" name="is_superuser" {% if user.is_superuser %}checked="checked" {% endif %}
class="form-check-input" id="id_is_superuser"><label class="form-check-label" for="id_is_superuser" title="Designates that this user has all permissions without explicitly assigning them.">Admin status</label>
<small class="form-text text-muted">Designates that this user has all permissions without explicitly assigning them.</small>
</div></div>
<div class="form-group"><div class="form-check"><input type="checkbox" name="is_staff" {% if user.is_staff %}checked="checked" {% endif %} class="form-check-input" id="id_is_staff"><label class="form-check-label" for="id_is_staff" title="Designates whether the user can log into this admin site.">Staff status</label>
<small class="form-text text-muted">Designates whether the user can log into this admin site.</small>
</div></div>
<div class="form-group"><div class="form-check"><input type="checkbox" {% if user.is_active %}checked="checked" {% endif %} name="is_active" class="form-check-input" id="id_is_active"><label class="form-check-label" for="id_is_active" title="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.">Active</label>
<small class="form-text text-muted">Designates whether this user should be treated as active. Unselect this instead of deleting accounts.</small>
</div></div>
<div class="text-xs-right">
<button type="submit" class="btn btn-info">Update</button>
</div>
</form>
You can do it like this:
def clean_email(self):
email = self.cleaned_data['email']
if self.instance and self.instance.pk:
return email
else User.objects.filter(email=email).exists():
raise ValidationError('Email Already Exists')
return email
Here I am checking if form has any instance and if that instance has any primary key. This instance attribute is set in form when you pass it from view, for example in your code: form = RegisterForm(request.POST,instance=user).
I am trying to style errors using twitter bootstrap in my Django project. Right now, I have a simple form that asks for a person's email address, has them press a button, and then submits it to the database. It also has validation checking to see if the email is unique in the database. If it is not unique, it raises an error saying "This email is already registered". However, when the error is raised, for a duplicate email, it brings an ugly bullet point list next to the input field with the text This email is already registered. I'm trying to style it to where it has a little dialog show under the input text with a yellow i icon like it does when the input does not include an # sign, i.e. it isn't an email. The ugly bullet point also appears when a valid domain isn't included in the email, e.g. there isn't a .com appended.
I think the problem lies with the way my form html is set up, or how the view handles the form's errors. Maybe, because the form field is an EmailField, the is_valid indicator doesn't validate and therefore shows the twitter bootstrap alert.
How do I get it to show the alert every time? Below is my code:
form part of the index.html
<form class="form-inline" method="post">
<div class="input-group input-group-newsletter">
<div class="form-group">
{% csrf_token %}
{{ form }}
</div>
<div class="form-group">
<div class="input-group-append">
<button class="btn btn-secondary" type="submit">Button Text</button>
</div>
</div>
</div>
</form>
views.py
from django.shortcuts import render, HttpResponse
from django.views.generic import TemplateView
from appname.forms import AppForm
class AppView(TemplateView):
template_name = 'apps/index.html'
def get(self, request):
form = AppForm()
return render(request, self.template_name, {'form': form})
def post(self, request):
form = AppForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
form.save()
form = AppForm()
args = {'form': form, 'email': email, 'signedup': True}
else:
args = {'form': form, 'signedup': False}
return render(request, self.template_name, args)
forms.py
from django import forms
from .models import AppModel
class AppForm(forms.ModelForm):
email = forms.EmailField(required=True,
label='',
widget=forms.EmailInput(attrs={'class': 'form-control',
'placeholder': 'Enter email...',
'name': 'email',
'aria-label': 'Enter email...',
'aria-describedby': 'basic-addon'}))
class Meta:
model = AppModel
fields = ('email',)
def clean_email(self, *args, **kwargs):
email = self.cleaned_data.get("email")
if AppModel.objects.filter(email__iexact=email).exists():
raise forms.ValidationError("This email is already registered.")
return email
You may want to try Django messages framework. This site shows how its done. I have tried it myself and works fine, though I haven't tried putting icons into it.
https://simpleisbetterthancomplex.com/tips/2016/09/06/django-tip-14-messages-framework.html
Update based on the comment below:
Here are the snippets in my project
in settings.py
from django.contrib.messages import constants as messages
...
MESSAGE_TAGS = {
messages.DEBUG: 'alert-info',
messages.INFO: 'alert-info',
messages.SUCCESS: 'alert-success',
messages.WARNING: 'alert-warning',
messages.ERROR: 'alert-danger',
}
messages.html template which can be included in any template where you want to have notifications
{% if messages %}
{% for message in messages %}
<div class="alert {{ message.tags }} alert-dismissible " role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
log-in.html template
<body>
{% include 'trip_monitor/messages.html' %}
<div class="login-form">
<form method="post">
{% csrf_token %}
<h2 class="text-center">Materials Management</h2>
<p align="center">Please <strong>log in</strong> to continue.</p>
<div class="form-group">
<input name="username" type="text" class="form-control" placeholder="Username" required="required" autofocus>
</div>
<div class="form-group">
<input name="password" type="password" class="form-control" placeholder="Password" required="required" id="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Log in</button>
</div>
</form>
</div>
</body>
views.py
from django.contrib import messages
def login(request):
if request.method == 'POST':
_username = request.POST['username']
_password = request.POST['password']
user = authenticate(request, username=_username, password=_password)
if user is not None:
auth_login(request, user)
return redirect('/trip/')
else:
messages.error(request, 'Username or Password is incorrect!') # this will be shown as pop-up message
return render(request, 'trip_monitor/login.html')
elif request.method == 'GET':
if request.user.is_authenticated:
return redirect('/trip/')
else:
return render(request, 'trip_monitor/login.html')
My symptom is when I click the modify button and then I write down the information on new window that is implemented by bootstrap div part. However, my database doesn't change at all. Please ignore ... in codes, I delete attributes that looks messy. Codes can have typo, because I wrote it down manually to find a bug, but I didn't find.
I tried in view.py, address_modify makes return Httpresponse(street), but It returned None.
view.py
def address_modify(request, adid):
cat = get_object_or_404(Address, adid=adid)
if request.method == "POST":
old_adid = adid
email = request.user.email
street = request.POST.get("street", None)
city = request.POST.get("city", None)
...
Address.objects.filter(adid=adid).update(..., street=street, city=city, state=state, ...)
return redirect('/address/')
return redirect('/address/')
template ( I name it address.html)
<button class="btn btn-success" data-toggle="modal" data-target="#modify">MODIFY</button>
<div class ="model fade" id="modify" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<from action="" method="POST">{% csrf_token %}
</div>
<div class="modal-body">
<input type="text" name="street">
<input type="text" name="city">
...
...
<input type="text" name="zipcode">
</div>
<div class="modal-footer">
<a href="{% url 'address_modify' i.adid %}">{% csrf_token %}
<button type="button" class="btn btn-primary">Save Change</button></a>
<div></form>
urls.py
url(r'^address_modify/(?P<adid>[0-9]+)/$', MyAppView.address_modify, name='address_modify'),
In django the best practice is to create a forms.py file to handle forms, its really easy you can read the doumentation on it, basically the form will ensure that all your data are read.
That is not how you implement form and form submit. Your link is not submitting anything, it's just opening a link. This is the standard form syntax:
<form method="POST">
{% csrf_token %}
... your form input fields here ...
<input type="submit" value="Save changes">
</form>
You must submit the form. Note type="submit" there.
Next to that, Django has forms feature. Use it. Create forms.py as #Saumel-Omole suggested. Form for model Address would look like this:
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
Then you modify your view to use the form like:
def address_modify(request, adid):
cat = get_object_or_404(Address, adid=adid)
form = AddressForm(instance=cat)
if request.method == 'POST':
form = AddressForm(request.POST, instance=cat)
if form.is_valid():
form.save()
return redirect('/address/')
else:
print(form.errors) # change to logging
return render(request, 'address.html', {'form': form})
Go over the official Django tutorial. These basics are all there. Maybe it is going to take you a day or two to get through it, but long-term that's going to be far less than guessing and googling around for days for basic stuff.
I was trying to to edit a user using the form that i used to create the user,
I have no idea why i'm getting an error A user with that username already exists.
Here is my view:
def registration_edit(request):
""" Registration Step2:
The user should be authenticated to reach this step.
Authentication is provided by first step or user login.
"""
if request.user.is_authenticated():
if request.POST:
form = RegistrationForm(request.POST or None, instance=request.user)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('reg_step_2'))
else:
form = RegistrationForm(instance=request.user)
page = 'account'
title = 'Editing User Registration'
context = {'title': title, 'form': form, 'page': page}
template = 'customer/registration.djhtml'
return render_to_response(template, context, context_instance=RequestContext(request))
else:
messages.info(request, '<strong>Note</strong>: You must logged in to edit your account.')
return HttpResponseRedirect('/')
forms.py I did this form because I want to include firstname and lastname field be included on the registration.
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class RegistrationForm(UserCreationForm):
class Meta:
model = User
exclude = ('is_staff', 'is_active', 'is_superuser', 'last_login', 'date_joined', 'groups', 'user_permissions', 'password')
and here is my template
<form class="form-horizontal" action='.' method="POST">
{% csrf_token %}
<fieldset>
<div id="legend">
<legend class="">
{{ title|title }}
</legend>
</div>
{% for f in form %}
<div class="control-group">
<label class="control-label" for="username">{{ f.label }}</label>
<div class="controls">
{{ f }} <i style="color: orange">{{ f.errors|striptags }}</i>
</div>
</div>
{% endfor %}
<div class="controls">
<button class="btn btn-success">
Continue
</button>
</div>
</fieldset>
</form>
Anyone tell me where i was messing around here?
Any help would be much appreciated.
Your from inherits from UserCreationForm which cleans the username field.
In this case see UserChangeForm instead.
I have a form with an email property.
When using {{ form.email }} in case of some validation error, Django still renders the previous value in the input tag's value attribute:
<input type="text" id="id_email" maxlength="75" class="required"
value="some#email.com" name="email">
I want to render the input tag myself (to add some JavaScript code and an error class in case of an error). For example this is my template instead of {{ form.email }}:
<input type="text" autocomplete="on" id="id_email" name="email"
class="email {% if form.email.errors %} error {% endif %}">
However, this does not display the erroneous value (some#email.com in this example) to the user.
How do I get the field's value in the template?
This was a feature request that got fixed in Django 1.3.
Here's the bug: https://code.djangoproject.com/ticket/10427
Basically, if you're running something after 1.3, in Django templates you can do:
{{ form.field.value|default_if_none:"" }}
Or in Jinja2:
{{ form.field.value()|default("") }}
Note that field.value() is a method, but in Django templates ()'s are omitted, while in Jinja2 method calls are explicit.
If you want to know what version of Django you're running, it will tell you when you do the runserver command.
If you are on something prior to 1.3, you can probably use the fix posted in the above bug: https://code.djangoproject.com/ticket/10427#comment:24
You can do this from the template with something like this:
{% if form.instance.some_field %}
{{form.instance.some_field}}
{% else %}
{{form.data.some_field}}
{% endif %}
This will display the instance value (if the form is created with an instance, you can use initial instead if you like), or else display the POST data such as when a validation error occurs.
I have a simple solution for you!
{{ form.data.email }}
I tried this and it worked. This requires your view to populate the form class with the POST data.
Very simple example:
def your_view(request):
if request.method == 'POST':
form = YourForm(request.POST)
if form.is_valid():
# some code here
else:
form = YourForm()
return render_to_response('template.html', {'form':form})
Hope that helps you. If you have any questions please let me know.
This seems to work.
{{ form.fields.email.initial }}
{{ form.field_name.value }} works for me
The solution proposed by Jens is correct.
However, it turns out that if you initialize your ModelForm with an instance (example below) django will not populate the data:
def your_view(request):
if request.method == 'POST':
form = UserDetailsForm(request.POST)
if form.is_valid():
# some code here
else:
form = UserDetailsForm(instance=request.user)
So, I made my own ModelForm base class that populates the initial data:
from django import forms
class BaseModelForm(forms.ModelForm):
"""
Subclass of `forms.ModelForm` that makes sure the initial values
are present in the form data, so you don't have to send all old values
for the form to actually validate.
"""
def merge_from_initial(self):
filt = lambda v: v not in self.data.keys()
for field in filter(filt, getattr(self.Meta, 'fields', ())):
self.data[field] = self.initial.get(field, None)
Then, the simple view example looks like this:
def your_view(request): if request.method == 'POST':
form = UserDetailsForm(request.POST)
if form.is_valid():
# some code here
else:
form = UserDetailsForm(instance=request.user)
form.merge_from_initial()
I tried a few of the mentioned possibilities, and this is how I solved my problem:
#forms.py
class EditProfileForm(forms.ModelForm):
first_name = forms.CharField(label='First Name',
widget=forms.TextInput(
attrs={'class': 'form-control'}),
required=False)
last_name = forms.CharField(label='Last Name',
widget=forms.TextInput(
attrs={'class': 'form-control'}),
required=False)
# username = forms.CharField(widget=forms.TextInput(
# attrs={'class': 'form-control'}),
# required=True)
address = forms.CharField(max_length=255, widget=forms.TextInput(
attrs={'class': 'form-control'}),
required=False)
phoneNumber = forms.CharField(max_length=11,
widget=forms.TextInput(
attrs={'class': 'form-control'}),
required=False)
photo = forms.ImageField(label='Change Profile Image', required=False)
class Meta:
model = User
fields = ['photo', 'first_name', 'last_name', 'phoneNumber', 'address']
# 'username',
#views.py
def edit_user_profile(request, username):
user = request.user
username = User.objects.get(username=username)
user_extended_photo = UserExtended.objects.get(user=user.id)
form = EditProfileForm(request.POST or None, request.FILES, instance=user)
user_extended = UserExtended.objects.get(user=user)
if request.method == 'POST':
if form.is_valid():
# photo = UserExtended(photo=request.FILES['photo'] or None, )
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user_extended.address = request.POST['address']
user_extended.phoneNumber = request.POST['phoneNumber']
user_extended.photo = form.cleaned_data["photo"]
# username = request.POST['username']
user_extended.save()
user.save()
context = {
'form': form,
'username': username,
'user_extended_photo': user_extended_photo,
}
return render(request, 'accounts/profile_updated.html', context)
else:
photo = user_extended.photo
first_name = user.first_name
last_name = user.last_name
address = user_extended.address
phoneNumber = user_extended.phoneNumber
form = EditProfileForm(
initial={'first_name': first_name, 'last_name': last_name,
'address': address, 'phoneNumber': phoneNumber,
'photo': photo})
context = {
'form': form,
'username': username,
'user_extended_photo': user_extended_photo,
}
return render_to_response('accounts/edit_profile.html', context,
context_instance=RequestContext(request))
#edit_profile.html
<form action="/accounts/{{ user.username }}/edit_profile/" method="post" enctype='multipart/form-data'>
{% csrf_token %}
<div class="col-md-6">
<div class="form-group">
{{ form.as_p }}
</div>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button type="submit" value="Update Profile" class="btn btn-info btn-fill pull-right">Update Profile</button>
<div class="clearfix"></div>
</form>
I am trying to explain this in a way so that beginners may find it easier to understand. Pay close attention to the else:
photo = user_extended.photo
first_name = user.first_name
last_name = user.last_name
address = user_extended.address
phoneNumber = user_extended.phoneNumber
form = EditProfileForm(
initial={'first_name': first_name, 'last_name': last_name,
'address': address, 'phoneNumber': phoneNumber,
'photo': photo})
It is what gets the value attrib, e.g.:
<p><label for="id_first_name">First Name:</label> <input class="form-control" id="id_first_name" name="first_name" type="text" value="Emmanuel" /></p>
<p><label for="id_last_name">Last Name:</label> <input class="form-control" id="id_last_name" name="last_name" type="text" value="Castor" /></p>
If you've populated the form with an instance and not with POST data (as the suggested answer requires), you can access the data using {{ form.instance.my_field_name }}.
I wanted to display the value of a formset field. I concluded this solution, which should work for normal forms too:
{% if form.email.data %} {{ form.email.data }}
{% else %} {{ form.initial.email }}
{% endif %}
The above solutions didn't worked very well for me, and I doubt they would work in case of prefixed forms (such as wizards and formsets).
The solutions using {{ form.data.email }} can't work, because it is a dictionary lookup, and with prefixed forms your field name would look something like '1-email' (wizard and prefixed form) or 'form-1-email' (formset), and the minus sign (-) are not allowed in dotted template lookup expressions.
{{form.field_name.value}} is Django 1.3+ only.
For check box with its items:
{% for item in people.q %}
<div class="form-check form-switch ">
<label class="form-check-label" for="{{ item.id_for_label }}">{{ item.data.label }}</label>
<input class="form-check-input" type="checkbox" id="{{ item.id_for_label }}" value="{{ item.data.value }}">
</div>
{% endfor %}
q is field name.
On Django 1.2, {{ form.data.field }} and {{ form.field.data }} are all OK, but not {{ form.field.value }}.
As others said, {{ form.field.value }} is Django 1.3+ only, but there's no specification in https://docs.djangoproject.com/en/1.3/topics/forms/. It can be found in https://docs.djangoproject.com/en/1.4/topics/forms/.
{{form.fields.email}}