I have a user creation form in my Django web application. I am able to create a user normally.
I have a model in my application called user_type, which has the is_admin field, is_manager field and the user field linked to the User Foreign Key. I have added a dropdown in my user creation form to enable the Admin create a user and as well assign the user_type of the user using the dropdown.
I am now confused of how to grab the admin choice and enable the user_type depending on that.
models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
# CUSTOM USER FIELDS
firstname = models.CharField(max_length=30, blank=True, null=True)
lastname = models.CharField(max_length=30, blank=True, null=True)
telephone = models.IntegerField(blank=True, null=True)
address = models.CharField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def get_absolute_url(self):
return "/users/%i/" % (self.pk)
class user_type(models.Model):
is_admin = models.BooleanField(default=False)
is_manager = models.BooleanField(default=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
if self.is_manager == True:
return User.get_email(self.user) + " - is_manager"
else:
return User.get_email(self.user) + " - is_admin"
views.py
def AddUser(request):
if request.method == "POST":
email = request.POST.get('email')
telephone = request.POST.get('telephone')
firstname = request.POST.get('firstname')
lastname = request.POST.get('lastname')
address = request.POST.get('address')
zipcode = request.POST.get('zipcode')
city = request.POST.get('city')
region = request.POST.get('region')
country = request.POST.get('country')
password = User.objects.make_random_password()
# is_manager = request.POST.get('is_manager')
try:
user = User.objects.create_user(email=email, telephone=telephone, firstname=firstname, password=password,
lastname=lastname, address=address, zipcode=zipcode, city=city, country=country)
user.send_welcome_mail(new_password)
# if is_manager == True:
# user.user_type.is_manager == True
# else:
# user.user_type.is_admin == True
user.save()
messages.success(request, "User Created Successfully!")
return redirect('users')
except Exception as e:
messages.error(request, "Failed to Create User!" + str(e))
return redirect('users')
return render(request, "core/adduser.html")
adduser.html
<form method="POST">
{% csrf_token %}
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<input type="text" name="email" placeholder="Email Address" class="form-control">
</div>
</div>
<div class="col-md-6 col-sm-12">
<div class="form-group">
<input type="text" name="telephone" placeholder="Telephone" class="form-control">
</div>
</div>
<div class="col-md-4 col-sm-12">
<div class="form-group">
<input type="text" name="firstname" placeholder="Firstname" class="form-control">
</div>
</div>
<div class="col-md-4 col-sm-12">
<div class="form-group">
<input type="text" name="lastname" placeholder="Lastname" class="form-control">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<select class="custom-select2 form-control" name="user_type" style="width: 100%; height: 38px;">
<optgroup label="Select User Type">
<option value="M" name="is_manager">Manager</option>
<option value="A" name="is_admin">Admin</option>
</optgroup>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 col-sm-12">
<div class="form-group">
<textarea name="address" placeholder="Address" class="form-control"></textarea>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">Create User</button>
</form>
Few changes to code style before explaining:
Rename user_type to UserType as it is suggested in Django Models.
Rename the view AddUser to add_user as it is suggested in PEP8 for function names.
In your add_user view:
if request.method == "POST":
# ...get your fields from the form
user_type = request.POST.get("user_type")
# ...create your user here
# assign default values first
is_admin = False
is_manager = False
# parse value from the form input
if user_type == "M":
is_manager = True
elif user_type == "A":
is_admin = True
# now create 1-to-1 field
user_type = UserType.objects.create(
user=user, is_admin=is_admin, is_manager=is_manager
)
Few more suggestions:
It is better to use user = User.objects.get(email=email) first to check if that user exists and handle that scenario. .get() function will give User.DoesNotExist exeption, handle that one for creating the user. Try to avoid generic Exception class as much as it is possible.
Use a Model Form for checking the input from the client, it will make sure that your inputs are good for the model requirements like required fields, field lengths and etc. before even trying to create that model.
Related
I try to add a validation state like "this already exist." (like registration form, see picture) just under my form input.
But when I submit my form i'v this error 'UNIQUE constraint failed'
this is my code
model
class Company(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
siret = models.CharField(max_length=50, unique=True)
forms
class CheckoutForm(forms.Form):
siret = forms.CharField(required=True, widget=forms.TextInput(attrs={'placeholder': 'Ton SIRET'}))
class Meta:
model = Company
fields = ('siret')
def clean(self):
siret = cleaned_data.get('siret')
if siret:
raise forms.ValidationError("This siret exist.")
else:
return siret
view
def post(self, request, *args, **kwargs):
form = CheckoutForm(self.request.POST)
if form.is_valid():
siret = form.cleaned_data.get('siret')
company = Company(
user = self.request.user,
siret = siret,
)
company.save()
context = {
'company': company,
}
return redirect("core:payment")
else:
messages.info(self.request, "Please fill in the shipping form properly")
return redirect("core:checkout")
template
{% load crispy_forms_tags %}
<main>
<div class="container wow fadeIn">
<h2 class="my-5 h2 text-left">Checkout form</h2>
<div class="row">
<div class="col-md-8 mb-4">
<div class="card">
<form method="post" class="card-body">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" id="checkout-button" data-secret="{{ session_id }}">
Checkout
</button>
</form>
</div>
</div>
Thanks a lot
you have to add errors_messages to your email field like this:
email = models.EmailField(
_('email address'),
blank=True,
unique=True,
null=True,
error_messages={
'unique': _("A user with that email address already exists."),
}
)
I tried creating a new user but it didn't work, I have tried debugging it but don't get a way about this. I have a User Model but want to try and create different user types like students, teachers something like that which would all be in the user user model as well as their various user models.
View.py
def AddCustomerManager(request):
if request.method == "POST":
email = request.POST.get('email')
username = request.POST.get('username')
password = request.POST.get('password')
try:
user = User.objects.create_user(email=email, username=username, password=password, user_type=2)
user.save()
messages.success(request, "Customer Manager Added Successfully")
except:
messages.error(request, "Failed to Add Customer Manager")
return render(request, "pusheat_admin/addcm.html")
models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
user_type_choice = ((1, "SuperUser"), (2, "CustomerManager"))
user_type = models.CharField(default=1, choices=user_type_choice, max_length=10)
objects = UserManager()
class CustomerManager(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
fullname = models.CharField(max_length=50, blank=False)
email = models.EmailField()
password = models.CharField(max_length=32)
addcm.html
<form role="form" method="POST">
{% csrf_token %}
<div class="card-header"><h4>Add Customer Manager</h4></div>
<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>Username</label>
<input type="text" class="form-control" name="username" placeholder="Username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" placeholder="Password">
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary">Add Customer Manager</button>
</div>
</form>
Change this line in models.py:
user_type = models.CharField(default=1, choices=user_type_choice, max_length=10)
to:
user_type = models.PositiveSmallIntegerField(default=1, choices=user_type_choice, max_length=10)
I have created small stock web app.
I created a stock model with unique part_number field. In my update template I send all item information to be displayed. Then I get an error in the part_number field that it is already there.
How can I avoid this validation for that part_number only?
I mean for same part_number suppose validation will not work. But if I modified to another part_number that already exists I get an error that it's being duplicated.
Model:
class Stock(models.Model):
part_number = models.CharField(max_length=30, blank=False, unique=True)
part_name = models.CharField(max_length=70)
quantity = models.IntegerField(blank=False)
location = models.CharField(max_length=3, blank=True)
model = models.CharField(max_length=40, blank=True, null=True, default="")
min_quantity = models.IntegerField(unique=False, blank=True, default=0)
max_quantity = models.IntegerField(unique=False, blank=True, default=0)
class Meta:
ordering = ['part_number']
def clean(self):
self.part_number = self.part_number.upper()
def __str__(self):
return self.part_number
Form.py:
class StockUpdateModelForm(forms.ModelForm):
class Meta:
model = models.Stock
fields = ['part_name', 'quantity', 'location','part_number']
views.py:
def stock_update_form_view(request, part_id):
item = Stock.objects.get(id=part_id)
item_id = Stock.objects.get(id=part_id).pk
form = StockUpdateModelForm({
'part_number' : item.part_number,
'part_name' : item.part_name,
'quantity' : item.quantity,
'location' : item.location
})
if request.method == 'POST':
form = StockUpdateModelForm(request.POST)
if form.is_valid():
s = Stock.objects.get(pk=item_id)
s.part_name = form.cleaned_data['part_name']
s.part_number = form.cleaned_data['part_number']
s.quantity = form.cleaned_data['quantity']
s.location = form.cleaned_data['location']
print("form is valid")
s.save()
return redirect('/stock/')
return render(request, 'stock/stock_update.html', {'form': form, 'pn': item.part_number})
html:
<form class="bg-light shadow" method="POST">
<div style="margin-left:10%; margin-top:30px">
<h4>Part Number : {{ pn }}</h4>
</div>
<hr style="width:100%">
{% csrf_token %}
<div class="row" style="margin-left:30px; margin-top:40px ">
<div class="col-sm-4" style="margin-left:6%">
{{ form.part_name|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.part_number|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:6%">
{{ form.quantity|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.location|as_crispy_field }}
</div>
<div class="col-sm-4" style="height: 100px; margin-top:30px ; margin-left:6%">
<hr style="width:100%">
<input class="btn btn-primary" type="submit" value="Save"
style="width: 150px;">
</div>
</div>
</form>
try this
if request.method == 'POST':
form = StockUpdateModelForm(request.POST, instance=item)
if form.is_valid():
form.save()
Very new to Django.
I created a custom user model as below. I also created a page for the users to update their details. I want the two user 'groups' to use the same page 'account.html' to update their details. But if the user is an 'Employee' I want to display additional fields.
Simply put, I'm trying to achieve the following logic:
If users group = 'Client' then display fields A & B to update
If users group = 'Employee' then display fields A, B, C & D update
Any help much appreciated
Models.py
group_types = [('Client', 'Client'), ('Employee','Employee')]
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
groups = models.CharField(choices=group_types, default="client", max_length=60)
company_name = models.CharField(verbose_name='company name', max_length=30)
account.html
<form class="form-signin" method="post">{% csrf_token %}
<h1 class="h3 mb-3 font-weight-normal">Account Details</h1>
<p> Email Address </p>
<input type="email" name="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus value={{account_form.initial.email}}>
<br>
<p> Username </p>
<input type="text" name="username" id="inputUsername" class="form-control" placeholder="Username" required autofocus value={{account_form.initial.username}}>
<br>
<p> Company Name </p>
<input type="text" name="company_name" id="inputCompany_Name" class="form-control" placeholder="Company Name" required autofocus value={{account_form.initial.company_name}}>
You can use modelform_factory to generate a form dynamically, you can pass different fields depending on the user
FIELDS = {
'Client': ['a', 'b', 'c'],
'Employee': ['a', 'b', 'c', 'd', 'e']
}
def view(request):
form_class = modelform_factory(Account, fields=FIELDS.get(request.user.groups))
form = form_class(instance=request.user)
...
How to set image field as optional? I am trying to set image field as optional(None or selected). Image field is None its throwing "MultiValueDictKeyError" when submit the form. I want to make this image field as None.
models.py
class Profile(models.Model):
first_name = models.CharField(max_length=255, blank=True, null=True)
last_name = models.CharField(max_length=255, blank=True, null=True)
image = models.ImageField(upload_to='images', blank=True, null=True)
forms.py
class Meta:
model = Profile
fields = '__all__'
views.py
def profile(request):
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid:
first_name = request.POST.get('first_name')
last_name = request.POST.get('last_name')
image = request.FILES['images']
file_storage = FileSystemStorage()
obj = Profile(first_name=first_name, last_name=last_name, image=file_storage.save(image.name, image))
return render(request, 'index.html',{})
return render(request, 'index.html',{})
return render(request, 'index.html',{})
index.html
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="first_name" class="form-control form-control" id="fname">
<input type="text" name="last_name" class="form-control form-control" id="lname">
<input type="file" name="images" class="form-control" id="image">
<button type="submit" class="btn btn-primary mt-5 mb-5">Save</button>
</form>
use the same method you're using in the other fields:
image = request.FILES.get('images')
this will make image = None if it doesn't exist in the request. then:
image_saved = None
if image is not None:
image_saved = FileSystemStorage().save(image.name, image)
obj = Profile(first_name=first_name, last_name=last_name, image=image_saved)