How to set image field as optional? - django

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)

Related

Using Dropdown values to set user ranks on creation

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.

Saving image fails without error in django model form

I want to try to save an image to my model:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class Leverandor(models.Model):
ID = models.AutoField(primary_key=True)
UserID = models.ForeignKey('Stamdata', on_delete=models.CASCADE)
Name = models.CharField('Name', max_length=200)
URL = models.URLField('URL', max_length=200)
ImageURL = models.ImageField('ImageURL',blank=True, null=True, upload_to=user_directory_path)
To this Form.py:
class EditLeverandorForm(forms.ModelForm):
Name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control', 'autofocus': True}))
URL = forms.URLField(widget=forms.TextInput(attrs={'class': 'form-control', 'autofocus': True}))
ImageURL = forms.ImageField
class Meta:
model = Leverandor
labels = {
'Name' : 'Leverandør',
'URL' : 'Webside',
'ImageURL' : 'Logo',
}
fields = ['UserID', 'Name', 'URL', 'ImageURL']
And rendererd to this view.py
def add_leverandorer(request):
user_id = request.user.id
# if this is a POST request we need to process the form data
if request.method == 'POST':
print (user_id)
form = EditLeverandorForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
form.save()
return HttpResponseRedirect('/backend/leverandorer')
else:
print ('somethin goes wrong')
print (user_id)
form = EditLeverandorForm()
return render(
request,
'backend/add_leverandorer.html',
{
'title':'WestcoastShop - Backend',
'form': form,
}
)
The problem is that before I add the instance=request.user part its saves the entry correct but without image. Now I add the part from Django documentation like provided for save to an variable path but nothing happened after i click to save button.
<form action="/backend/leverandorer/add" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="simpleinput">Leverandør</label>
{{ form.Name }}
</div>
<div class="form-group">
<label for="simpleinput">Webside</label>
{{ form.URL }}
</div>
<div class="form-group">
<label for="simpleinput">Logo</label>
{{ form.ImageURL }}
<!--<input type="file" name="ImageURL" accept="image/*" required="" id="id_ImageURL" class="form-control-file">-->
</div>
<input type="hidden" id="UserID" name="UserID" value="{{ user.id }}">
<button type="submit" class="btn btn-primary">Gem</button>
</form>
I didnt see an error but now its not saving the form in models also if ImageField is empty.
regards
Christopher.
You are using UserID as a hidden field. The hidden field will not pass the form-validation. So your following code will be false.
if form.is_valid():
form.save()
return HttpResponseRedirect('/backend/leverandorer')
One of the solutions is, remove the UserID field from your template and update your view as follows.
if form.is_valid():
user_form = form.save(commit=False)
user_form.UserID = request.user
user_form.save()
I I change the function in models.py to:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.UserID, filename)
class Leverandor(models.Model):
ID = models.AutoField(primary_key=True)
UserID = models.ForeignKey('Stamdata', on_delete=models.CASCADE)
Name = models.CharField('Name', max_length=200)
URL = models.URLField('URL', max_length=200)
ImageURL = models.ImageField('ImageURL',blank=True, null=True, upload_to=user_directory_path)
its works, but the Path is Username and not user.id

How to post one html form data into two models in django?

I having a html form consisting of some fields with details and I want to post some details of the form to one model and some details to another model how this can be done?
my models.py
class room(models.Model):
id = models.IntegerField(primary_key=True)
image = models.ImageField(upload_to='images')
content = models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.content
# This is the model for goals
class goal(models.Model):
id=models.IntegerField(primary_key=True)
goal = models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.goal
# This is the model for designs
class design(models.Model):
id=models.IntegerField(primary_key=True)
image = models.ImageField(upload_to='images')
content = models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.content
# This is the model for furniture
class furniture(models.Model):
id=models.IntegerField(primary_key=True)
phrase=models.CharField(max_length=60,default='111111')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.phrase
# This is the users model
class user(models.Model):
username=models.CharField(max_length=20)
email=models.CharField(max_length=50,unique=True)
password=models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.username
class UserRequirement(models.Model):
id=models.IntegerField(primary_key=True)
user=models.ForeignKey(user,on_delete=models.CASCADE)
rooms = models.ForeignKey(room,on_delete=models.CASCADE)
goals = models.ManyToManyField(goal)
styles = models.ManyToManyField(design)
furn = models.ForeignKey(furniture,on_delete=models.CASCADE)
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
My views.py for posting:
def user_register(request):
if request.method == 'POST':
user_form = UserForm(data=request.POST)
if user_form.is_valid():
username=request.POST["username"]
email = request.POST['email']
password = request.POST['password']
rooms = request.POST['room']
g=goals=request.POST['goal']
g = g.split(',')
s=styles=request.POST['style']
s=s.split(',')
furn=request.POST['furn']
u = user(username=username,password=password,email=email)
u.rooms=room.objects.get(pk=rooms)
goals = goal.objects.filter(pk__in=g)
styles = design.objects.filter(pk__in=s)
u.furn = furniture.objects.get(pk=furn)
u.save()
u.goals.add(*goals)
u.styles.add(*styles)
messages.success(request,'Your project design has been registered')
return render(request,'register.html')
else:
messages.warning(request,'Cant be registered this email already exists')
return render(request,'register.html')
My form.html is
<form action="{% url 'modsy:user_register' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" class="form-control" required>
<div id="uname_error"></div>
</div>
<div class="form-group">
<input type="hidden" name="room" id="name" value="">
</div>
<div class="form-group" >
<input type="hidden" name="goal" id="goal" value="">
</div>
<div class="form-group">
<input type="hidden" name="style" id="style" value=" ">
</div>
<div class="form-group" >
<input type="hidden" name="furn" id="furn" value="">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" name="email" class="form-control" required><br>
<div id="name_error" style="color:red;"></div></div>
<div class="form-group">
<label for="password2">Password</label>
<input type="password" name="password" class="form-control" required>
<div id="pwd_error" style="color:red;"></div>
</div>
<div class="button"><input type="submit" value="Save the Project" style="background-color:#000080;" class="btn btn-secondary btn-block" onclick="return validation(form)">
</form>
Now here I want to post the username email and password to the user model and the user room goal furniture style should be stored in the user_requirement model how it can be done?
My forms.py
from django import forms
from . models import user
from django.contrib.auth.models import User
from . models import UserRequirement
from . models import room
from . models import goal
from . models import design
from . models import furniture
class UserForm(forms.ModelForm):
class Meta:
model = user
fields = ('email',)
def clean_email(self):
# Get the email
email = self.cleaned_data.get('email')
# Check to see if any users already exist with this email as a username.
try:
match = User.objects.get(email=email)
except User.DoesNotExist:
# Unable to find a user, this is fine
return email
raise forms.ValidationError('This email address is already in use.')
class UserRequirementForm(forms.ModelForm):
class Meta:
model = UserRequirement
fields=(user,rooms,goals,styles,furn)
Option 1: Create a form with all the fields you need and override the save method to store the data where you need them. You can use your User model as the base model and add any extra fields you need for other models.
Option 2: Use two different forms and process them separately.
if request.method == 'POST':
user_form = UserForm(data=request.POST)
user_requirement_form = UserRequirementForm(data=request.POST)
if user_form.is_valid() and user_requirement_form.is_valid():
user = user_form.save()
user_requirement = user_requirement_form.save(commit=False)
# Set user
user_requirement.user = user
user_requirement.save()
user_requirement_form.save_m2m()
redirect(...)
else:
# Handle errors
messages.warning(request, 'Please correct the errors below')
else:
# GET
user_form = UserForm()
user_requirement_form = UserRequirementForm()
return render(request,'register.html', {'user_form': user_form, 'requirements_form': user_requirement_form})
Then make sure you actually show the errors in your template, using {{ user_form.errors }} or {{ user_form.email.errors }} depending whether you show all the errors at once or per field.
I think the following approach would help.
Forms.py
class UserForm(forms.ModelForm):
class Meta:
model = user
fields = ['email',]
class UserRequirementForm(forms.ModelForm):
class Meta:
model = UserRequirement
fields=['rooms','goals','styles','furn']
Then 2. Views.py
from .forms import UserForm, UserRequirementForm
from django.shortcuts import redirect, render
def register_user(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
user_requirement_form = UserRequirementForm(request.POST)
if user_form.is_valid() and user_requirement_form.is_valid():
user = user_form.save()
user_requirement = user_requirement_form.save(commit=False)
user_requirement.user = request.user # <- Setting the user to currently logged in user
user_requirement.save()
redirect('name_of_url_to_redirect_to')
else:
user_form = UserForm()
user_requirement_form = UserRequirementForm()
context = {
'user_form': user_form,
'user_requirement_form' : user_requirement_form,
}
return render(request, 'path_to_template.html', context)
Then finally in the template (.html file):
<form method="POST">
{{user_form.as_p}}
{{user_requirement_form.as_p}}
<button type="submit"> Submit</button>
</form>
That should render your form and save data correctly on submit
PS: Avoid adding id field on your models as Django already gives you an id field by default.

How to upload multiple images with one value in Django

I'm trying to upload multiple images with one single field, in a Django application.
How to do this?
The following files are involved:
upload.html:
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="image_id" placeholder="Image Id">
<input type="file" name="file" multiple>
<button type="submit"> Upload </button>
</form>
Here, the single field image_id is meant to hold 5 images.
views.py:
def multi_image(request):
if request.method == 'POST':
img_id = request.POST.get('image_id')
file = request.FILES.getlist('file')
data_save = Res(image_id = img_id )
data_save.save()
filter_data = Res.objects.filter(image_id= img_id)
if len(filter_data) > 0:
for i in file:
print(i)
Res.objects.create(image= i)
return render(request, 'upload.html', {})
models.py:
class Res(models.Model):
image_id= models.CharField(max_length=10, blank=True, null=True)
image = models.FileField(upload_to='images', blank=True, null=True)
forms.py:
class FileForm(forms.Form):
class Meta:
model = Res
fields = '__all__'

How do I save user ratings in Django database?

This is my first project in Django. I am trying to save rating in Django database but when I click on radio buttons the value doesn't store in database. I have tried solutions of Stack Overflow previously uploaded but none helped me in resolving my issue. I was firstly using RadioSelect in forms.py but still having the same problem.
Here is the code:
Model.py
class Product(models.Model):
title = models.CharField(max_length=120)
brand = models.CharField(max_length=120,default="None")
model = models.CharField(max_length=120,default="None")
slug = models.SlugField(blank=True, unique=True)
category = models.CharField(max_length=120 , default="Phone")
price = models.DecimalField(decimal_places=2, max_digits=20, default=39.99)
class Rating(models.Model):
product=models.ForeignKey(Product,default=None, on_delete=models.PROTECT)
user=models.ForeignKey(User,default=None, on_delete=models.PROTECT)
rating = models.CharField(max_length=120)
Views.py
def add_rating(request,id):
product = get_object_or_404(Product, pk=id)
pro = Product.objects.get(id=id)
if request.method == "POST":
form = RatingForm(request.POST)
if form.is_valid():
product = form.cleaned_data['product']
user = form.cleaned_data['user']
rating = form.cleaned_data['rating']
product = request.POST.get('product', ''),
user = request.POST.get('user', ''),
rating = request.POST.get('rating', ''),
obj = Rating(product=product, user=user, rating=rating)
obj.save()
context = {'obj': obj}
return render(request, 'product/detail.html',context)
else:
form=RatingForm()
return HttpResponse('Please rate the product')
Forms.py
from django import forms
from .models import Rating
class RatingForm(forms.ModelForm):
class Meta:
model = Rating
fields = ('product', 'user','rating')
template.py
<form method="POST" action="{% url 'add_rating' product.id %}">{% csrf_token %}
<ul class="rate-area" style="display:inline;position:absolute">
<input type="radio" id="5-star" name="rating" value="5" /><label for="5- star" title="Amazing">5 stars</label>
<input type="radio" id="4-star" name="rating" value="4" /><label for="4-star" title="Good">4 stars</label>
<input type="radio" id="3-star" name="rating" value="3" /><label for="3-star" title="Average">3 stars</label>
<input type="radio" id="2-star" name="rating" value="2" /><label for="2-star" title="Not Good">2 stars</label>
<input type="radio" id="1-star" name="rating" value="1" /><label for="1-star" title="Bad">1 star</label>
<button type="submit" value="Rate">Rate</button>
</ul>
</form>
You're using a "CharField" on your model while you should be using a "ChoiceField", a ChoiceField would then become a dropdown select.
It would also be easier to use generic editing views; https://docs.djangoproject.com/en/2.2/ref/class-based-views/generic-editing/