Saving image fails without error in django model form - django

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

Related

Django - Passing the creator of a form to the form

I am making an auction site. I need to know per listing who the creator was (so the creators will have the possibility to delete the listing). It works for me to manually change the user in Django Admin, but I want it to be automatically saved when someone creates a new listing.
How do I pass the creator of a form to the form?
These are the relevant models:
class User(AbstractUser):
pass
class AuctionListing(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=512, default="")
starting_bid = models.DecimalField(max_digits=6, decimal_places=2, default=0.01, validators=[MinValueValidator(Decimal('0.01'))])
url = models.URLField(max_length=200, blank=True)
category = models.CharField(max_length = 20)
user = models.ForeignKey(User, on_delete=models.CASCADE, db_constraint=False, related_name="items")
def __str__(self):
return self.title
Here is my forms.py:
class CreateListing(forms.ModelForm):
category = forms.ModelChoiceField(queryset=Category.objects.all(), empty_label="No category")
class Meta:
model = AuctionListing
fields = ('title', 'description', 'starting_bid', 'url', 'category', 'user')
widgets = {
'title': forms.TextInput(attrs={'placeholder':'Write your listing title here...'}),
'description': forms.Textarea(attrs={'placeholder':'Write your comment here...', 'rows':3}),
'user': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super().__init__(*args, **kwargs)
self.fields['user'].initial = user.id
And here was my attempt for the view:
def create_listing(request):
form = CreateListing(request.POST, user=request.user)
if request.method == "POST":
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse("index"))
else:
print("RIP")
return render(request, "auctions/create_listing.html", {"form": form})
return render(request, "auctions/create_listing.html", {
"form" : CreateListing(user=request.user)
})
auctions/create_listing.html looks like this:
<h1> Create new listing </h1>
<form action="" method="POST">
{% csrf_token %}
<label>Name*</label>
<br>
{{ form.title }}
<br>
<label >Description*</label>
<br>
{{ form.description }}
<br>
<label >Starting bid*</label>
<br>
{{ form.starting_bid }}
<br>
<label > Image url (optional) </label>
<br>
{{ form.url }}
<br>
<label > Category (optional) </label>
<br>
{{ form.category }}
<br>
{{ form.user }}
<button type="submit" class="btn btn-primary save">Create your listing</button>
</form>
The error I get with this is: "BaseModelForm.init() got an unexpected keyword argument 'user'"
How can I fix this so the user will automatically be saved each time a listing is created?
Add user argument in the __init__ method of the form. You can set the user right there and there is no need for even displaying the user field. You can completely hide it.
class CreateListing(forms.ModelForm):
category = forms.ModelChoiceField(queryset=Category.objects.all(), empty_label="No category")
class Meta:
model = AuctionListing
fields = ('title', 'description', 'starting_bid', 'url', 'category', 'user')
widgets = {
'title': forms.TextInput(attrs={'placeholder':'Write your listing title here...'}),
'description': forms.Textarea(attrs={'placeholder':'Write your comment here...', 'rows':3}),
'user': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super().__init__(*args, **kwargs)
self.fields['user'].initial = user.id
Remember to use the user kwarg in the view:
def create_listing(request):
form = CreateListing(request.POST, user=request.user)
if request.method == "POST":
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse("index"))
else:
print("RIP")
# If form is invalid you should render the same template again
# with the errors
return render(request, "auctions/create_listing.html", {"form": form})
return render(request, "auctions/create_listing.html", {
# For the empty form, this needs to be an instance of the form,
# and not a class
"form" : CreateListing(user=request.user)
})
Also, you can replace your HTML with:
{{ form.user }}
Replace {{ form.user }} by <input type="hidden" name="user" value="{{request.user}}">
User has to come automatically so you don't need to display user field in the front-end
by the above method you'll get logged in user but still hard to save as it is foreign key, what ever you get from front-end it'll be string type.
So best suggestion is the below code.
if form.is_valid():
form_data = form.save()
form_data.user = request.user
form_data.save()

How to have pre/post populated id field in django form submission

What I am trying to achieve is to have my "student_id" auto-generated field to be part of the form submission in the sense that the "student_id" field does not have to be manually input in form submission:
The "student_id" field needs to be either pre-generated upon displaying the form or to be generated upon form submission.
I have tried and currently facing error when submitting form as bellow:
KeyError at 'student_id'
Exception Value: 'student_id'
Removing the "student_id = form.cleaned_data['student_id']" syntax in views.py does not help either.
I have the following model, which generates an auto "student_id" field
class Student(models.Model):
student_id = models.AutoField(primary_key=True,unique=True, max_length=10, blank=False)
name = models.CharField(max_length=200, blank=False)
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.name
my forms.py:
Class StudentForm(forms.ModelForm):
class Meta:
model = Student
fields = [
'student_id','name', 'first_name', 'last_name'
]
my views.py:
def index(request):
if request.method == 'POST':
form = StudentForm(request.POST, or None)
if form.is_valid():
student_id = form.cleaned_data['student_id']
form.save()
else:
FormError = StudentForm.errors
return redirect(f'/card/{student_id}')
else:
form = StudentForm()
template_name = 'index.html'
context = {
'form' : form,
}
return render(request, template_name, context)
my html:
<form method="POST" action="{% url 'student:index' %}" enctype="multipart/form-data">{% csrf_token %}
<div class="form-group">
{{ form | crispy }}
</div>
<input type="submit" value="Envoyer" class="btn btn-primary btn-lg btn-block">
</form>
Will appreciate any help

UNIQUE constraint failed: user_profile.StudentID error

I am getting this error(IntegrityError at /register/) every time I try to create a new user. In user creation form I am creating both User and profile.
here is my models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
StudentID = models.CharField(max_length=8,unique=True)
Branch = models.CharField(max_length=255,choices=Departments,default="CSE")
YearOfStudy = models.IntegerField(default=1)
ContactNumber = PhoneField(help_text='Contact phone number')
image = models.ImageField(default='default.jpeg' , upload_to='profile_pics')
parentsContactNumber = PhoneField(help_text="Parent's phone number")
def __str__(self):
return f'{self.user.username} Profile'
here is forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
class Meta:
model = User
fields = ['username','email','first_name','last_name','password1','password2']
class ProfileCreationForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['StudentID','Branch','YearOfStudy','ContactNumber']
here is views.py
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
form1 = ProfileCreationForm(request.POST)
if form.is_valid() and form1.is_valid():
form.save()
form1.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('login')
else:
form = UserRegisterForm()
form1 = ProfileCreationForm()
context = {
'form': form,
'form1': form1
}
return render(request, 'user/register.html', context)
here is register.html
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">JOIN TODAY</legend>
{{ form|crispy }}
{{ form1|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
</div>
{% endblock content %}
please help me with this error
You are set unique=True in...
StudentID = models.CharField(max_length=8,unique=True)
So, when you pass student_id from your form at that time you pass the same id in form which is already in your database thus this error is coming.

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.

'PersonForm' object has no attribute 'as_widget'

I am trying to pass string to a hidden field scenario of a form whose data is stored in a database. The goal is to be able to retrieve extra information on client side without having it as another field of the form.
I am getting 'PersonForm' object has no attribute 'as_widget' error.
This is my Model:
class Person(models.Model):
region = models.CharField(max_length=30)
industry = models.CharField(max_length=30)
uuid = models.CharField(max_length=50, blank=True, unique=True, default=uuid.uuid4)
scenario = models.ForeignKey(Scenario, on_delete=models.CASCADE,)
def __str__(self):
return "{}".format(self.uuid)
My Form
class PersonForm(forms.ModelForm):
class Meta:
model=Person
scenario = forms.CharField(widget=forms.HiddenInput())
fields = ['industry', 'region','scenario']
My View
def personforms(request):
persons = Person.objects.all()
if request.method == 'POST':
filled_form = PersonForm(request.POST)
if filled_form.is_valid():
created_person = filled_form.save()
#DEBUG
print(filled_form.cleaned_data['scenario'])
created_person_pk = created_person.id
filled_form = PersonForm()
return redirect('/scenariopage', {'persons':persons})
else:
created_person_pk = None
return render(request, 'core/scenario-landing-page.html', {'personform':filled_form, 'created_person_pk':created_person_pk})
else:
form = PersonForm()
return render(request, 'core/scenario-landing-page.html', {'personform':form})
And my template
<form action="{% url 'personform' %}" method="post" class="custom-form">
{% csrf_token %}
{% render_field personform class="form-control" %}
{% render_field personform.scenario class="form-control form-control-sm" value='{{ scenario.name }}' %}
<input type="submit" class="btn color-btn" value="Go to Scenario page" data-dismiss="gallery-item"/>
</form>
Questions I have:
I have no Error message. But debug print is indicating that filled_form.is_valid(): seems to be invalid.
And this line in the View never print result:
#DEBUG
print(filled_form.cleaned_data['scenario'])
What I am doing wrong?
How could I possibly pass the data to the field scenario.