Django Saving A Model With Form + Current User Data - python

I'm writing my first app in django and i have encountered a problem. I'm trying to make a booking system. I'm trying to save the reservation model. It works just fine while the user is logged out. But once i click submit while logged in nothing really happens. The site simply reloads. Can anyone point out what I'm doing wrong?
That's my model code:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
name = models.CharField(max_length = 100)
surname = models.CharField(max_length = 100)
phone = models.CharField(max_length = 9)
class Reservation(models.Model):
reservationID = models.AutoField(primary_key = True)
name = models.CharField(max_length = 100)
surname = models.CharField(max_length = 100)
phone = models.CharField(max_length = 9)
email = models.EmailField()
bookIn = models.DateField('Book in date', default = timezone.now)
bookOut = models.DateField('Book out date', default = timezone.now)
roomType = models.ForeignKey(Room_type, on_delete = models.CASCADE)
My form:
class Booking(forms.ModelForm):
class Meta:
model = Reservation
fields = ('name', 'surname', 'phone', 'email', 'roomType', 'bookIn', 'bookOut',)
widgets = {
'bookIn': forms.DateInput(attrs={'class': 'datepicker'}),
'bookOut': forms.DateInput(attrs={'class': 'datepicker'})
}
And my view:
form = Booking()
if request.method == 'POST':
form = Booking(request.POST)
if form.is_valid():
if request.user.is_authenticated:
reservation = Reservation()
guest = Profile.objects.get(user=request.user)
reservation.name = guest.name
reservation.surname = guest.surname
reservation.phone = guest.phone
reservation.email = guest.user.email
reservation.bookIn = form.cleaned_data.get('bookIn')
reservation.bookOut = form.cleaned_data.get('bookOut')
reservation.roomType = form.cleaned_data.get('roomType')
reservation.save()
else:
reservation = form.save()
reservation.save()
n = reservation.pk
return redirect('bookSuccess', n)
return render(request, 'hotel/bookRoom.html', {'form' : form})

I am assuming your form is not validating for some reason, and you need to catch it to see what might be going wrong. So you can update your view like this:
form = Booking(request.POST or None)
if request.method == 'POST':
if form.is_valid():
if request.user.is_authenticated:
reservation = form.save(commit=False)
# optimized the code
guest = Profile.objects.get(user=request.user)
reservation.name = guest.name
reservation.surname = guest.surname
reservation.phone = guest.phone
reservation.email = request.user.email
reservation.save()
else:
reservation = form.save() # removed duplicate save
n = reservation.pk
return redirect('bookSuccess', n)
return render(request, 'hotel/bookRoom.html', {'form' : form})
Update
You don't need to put null true and blank true in the model fields. You can pass the user data from view to form. and if the user is authenticated then pop the fields which is not necessary for authenticated user. Like this:
class Booking(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(Booking, self).__init__(*args, **kwargs)
if user.is_authenticated:
self.fields.pop('name') # or make them required false like this: self.fields['name'].required = False
self.fields.pop('surname')
# other fields unnecessary for authenticated user
# rest of the code
And use this form in view like this:
form = Booking(request.POST or None, user=request.user)

Related

how can I set instance in model when using form in django?

in model.py I have this code:
class wallet(models.Model):
User = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
coin= models.PositiveIntegerField(default= 50000)
password = models.CharField(blank=True , max_length = 50)
def __str__(self):
return str(self.wallet)
this is one-to-one relationship between User and wallet
in my form.py I Have this code :
class WalletForm(forms.ModelForm):
User = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = wallet
fields = (
'User',
'coin',
'password'
)
def __init__(self , user , *args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['User'].widget.attrs['value'] = Profile.objects.get(pk = user.id)
self.fields['User'].widget.attrs['readonly'] = True
self.fields['coin'].widget.attrs['value'] = 50000
self.fields['coin'].widget.attrs['readonly'] = True
self.fields['password'].widget.attrs['placeholder'] = 'Wallet Password'
I am trying to make wallet for every user .. the question is :
how can I set User in wallet model to the already user who is logged in my site
when the form submitting ...
thanks
You can utilise the form_valid function in order to set the user before saving the model:
class WalletForm(forms.ModelForm):
...
def form_valid(self, form):
form.instance.user = User.objects.get(user=self.request.user)
form.instance.save(commit=False)
return super().form_valid(form)
Also, you should use attributes in lowercase, ie. change the following from
class wallet(models.Model):
User = ... # From this
user = ... # To this
i think you can exclude the user field from your form
then in the view function do this:
form = SampleForm(request.POST)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.user = request.user
new_obj.save()

How to assign value of field of one model to field of another model?

Say, I have a view function that creates a Vacancy object on saving the form, and it has the field company that, if the form is valid, has to be assigned with value of field name, that is on the other model named EmployerProfile, how can I do that? I have company as a foreign key on my model.
My models
class EmployerProfile(models.Model):
name = models.CharField(max_length = 64)
description = models.TextField()
username = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete = models.CASCADE)
class Vacancy(models.Model):
name = models.CharField(max_length = 64)
competences = models.CharField(max_length = 32)
salary = models.DecimalField(decimal_places = 2, max_digits = 10)
description = models.TextField(null = True)
company = models.ForeignKey(EmployerProfile, on_delete = models.CASCADE)
featured = models.BooleanField(default = False)
My view
#login_required(login_url = 'login')
def vacancyAddView(request):
if request.method == 'POST':
form = VacancyAddForm(request.POST)
if form.is_valid():
form.save()
return redirect('profile')
else:
form = VacancyAddForm()
context = {
'form':form
}
return render(request, "addVacancy.html", context)
My form
class VacancyAddForm(forms.ModelForm):
class Meta:
model = Vacancy
fields = [
'name',
'competences',
'description',
'salary',
]
P.S. I have tried adding this piece of code to my view, rigth after form.is_valid():
obj = EmployerProfile.objects.get(username = request.user)
form.instance.company = obj.name
but it didn't work, it returned the ValueError with text "Vacancy.company" must be a "EmployerProfile" instance.
P.P.S. I also tried to override the save method in my model like this
def save(self, *args, **kwargs):
self.company = self.EmployerProfile.name
super(Vacancy, self).save(*args, **kwargs)
but it didn't work either.
You can't do what you want. Your Vacancy model defines company as a foreign key, but you're trying to set it as a string.
class Vacancy(models.Model):
company = models.ForeignKey(EmployerProfile, on_delete = models.CASCADE)
However, here's what your view should change to be to work with your models as you've defined them currently.
#login_required(login_url = 'login')
def vacancyAddView(request):
if request.method == 'POST':
form = VacancyAddForm(request.POST)
if form.is_valid():
# Set the company
form.instance.company = request.user.employerprofile
form.save()
return redirect('profile')
else:
form = VacancyAddForm()
context = {
'form':form
}
return render(request, "addVacancy.html", context)
The basic issue here is that you can't set a ForeignKey field to be a string. If you want the user to be able to set the Company from the form, you have a couple of choices. One is to take what you have now in the form and use it to filter, e.g. something like:
company = EmployerProfile.objects.filter(name__iexact=form.cleaned_data['company'])
form.instance.company = company
Another would be to change the form so that instead of a text input, company is a ModelChoiceField, or a regular ChoiceField populated with the company choices available to the user.
In either case the end goal will be to ensure that the company field contains a foreign key to an EmployerProfile object, rather than the string name of a company.

How to display a ModelChoiceField's Selected Value in Django

I need to display just the selected value from a forms.ModelChoiceField on a view page. How would I do that?
I've looked at many different forums and couldn't get a clear answer on what I should do in my case. I am new at Python.
form:
class Manufacturer1Form(ReadOnlyFormMixin, ModelForm):
manufacturer = forms.ModelChoiceField(queryset=Vendor.objects.filter(vendor_type='manufacturer').order_by('name'))
class Meta:
model = Manufacturer1Relationship
exclude = ('part',)
model:
class Manufacturer1Relationship(models.Model):
part = models.ForeignKey(Part, on_delete=models.CASCADE)
manufacturer = models.ForeignKey(Vendor, on_delete=models.CASCADE,
limit_choices_to={'vendor_type': 'manufacturer'},)
partNumber = models.CharField(max_length=40, blank=True)
class Meta:
permissions = (
('modify_admin_site', 'Can modify, add, view, or delete manufacturer relationships'),
)
view:
def PartView(request, type_id, id):
partType = Type.objects.get(id=type_id)
instance = get_object_or_404(Part, id=id)
selection = None
if request.method == 'POST':
form = ViewPartForm(type_id, request.POST, request.FILES, instance=instance)
manu1_formset = ManufacturerFormSet(request.POST, instance=instance)
location1_formset = LocationFormSet(request.POST, instance=instance)
if form.is_valid():
selection = form.cleaned_data['active_feed']
part = form.save(commit=False)
part.partType_id = type_id
if manu1_formset.is_valid() and location1_formset.is_valid():
part.save()
manu1_formset.save()
location1_formset.save()
url = reverse('list_parts', args=[partType.pk])
return HttpResponseRedirect(url)
else:
form = ViewPartForm(type_id=type_id, instance=instance)
manu1_formset = ManufacturerFormSet(instance=instance)
location1_formset = LocationFormSet(instance=instance)
return render(request, 'part_view.html', {'view_part_form': form,
'location_formset': location1_formset,
'manu_formset': manu1_formset,
'selection': selection,
'partType': partType,
'part': instance})
class Manufacturer1Form(ReadOnlyFormMixin, ModelForm):
manufacturer = forms.ModelChoiceField(queryset=Vendor.objects.filter(vendor_type='manufacturer').order_by('name'))
class Meta:
model = Manufacturer1Relationship
exclude = ('part',)
def __init__(self, *args, **kwargs):
initial_manufacturer = kwargs.pop("manufacturer",None)
super().__init__(*args, **kwargs)
self.fields["manufacturer"].initial = initial_manufacturer
ManufacturerFormSet(request.POST, instance=instance, manufacturer=specific_manufacturer)

Django ModelForm - Get value from ManyToManyField

I need to get the selected value(s) of year from the PreceptorForm. I can get the internal_tel using post.internal_tel but I can't do that with year because it's a ManyToManyField. I need something like preceptor.year.add(post.year) but it gives me an error. What is the best way to do it?
models.py
class Year(models.Model):
year_number = models.IntegerField(choices=YEAR_CHOICES)
division = models.CharField(choices=DIVISION_CHOICES, max_length=1)
def getStudents(self):
results = Student.objects.filter(year=self)
return results
def __str__(self):
return "{}-{}".format(self.year_number, self.division)
class Preceptor(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete = models.CASCADE)
internal_tel = models.IntegerField(blank=True)
year = models.ManyToManyField(Year,blank=True,related_name='preceptores')
def getYear(self):
results = self.year.all()
return results
def __str__(self):
return "{} {}".format(self.user.first_name, self.user.last_name)
forms.py
class PreceptorForm(ModelForm):
class Meta:
model = Preceptor
fields = '__all__'
exclude = ['user']
views.py
def register_user(request):
if request.method == "POST":
form = PreceptorForm(request.POST)
username = request.POST['username']
password = request.POST['password']
sec_pass = request.POST['sec_password']
email = request.POST['email']
first_name = request.POST['first_name']
last_name = request.POST['last_name']
if form.is_valid():
if password == sec_pass:
user = User.objects.create_user(username, email, password)
user.is_active = True
user.first_name = first_name
user.last_name = last_name
user.save()
print "form"
post = form.save(commit=False)
post.user = user
preceptor = Preceptor(user=user,internal_tel=post.internal_tel)
preceptor.save()
preceptor.year.add(post.year)
preceptor.save()
return redirect('/')
else:
form = PreceptorForm()
return render(request, 'register.html', {'form': form})
I'm having this error at preceptor.year.add(post.year):
< Preceptor: 'name' > needs to have a value for field "id" before this many-to-many relationship can be used.

Django - duplicate key value violates unique constraint

In my Django project i create an app to have additional information about registered users. So my model looks like this:
class UserProfile(models.Model):
class Meta:
verbose_name_plural = u'User Profile'
user = models.OneToOneField(User)
birthday = models.DateField(blank=True, null=True)
avatar = models.ImageField(upload_to='media/profile/avatar', blank=True, null=True)
name = models.CharField(blank=True, null=True, max_length=20)
surname = models.CharField(blank=True, null=True, max_length=50)
phone = models.CharField(blank=True, null=True, max_length=12)
def __unicode__(self):
return '%s' % self.user
Here is my registration form:
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'Username'))
email = forms.EmailField(label=(u'Email'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
password1 = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model = UserProfile
exclude = ('user',)
fields = ('username', 'email', 'password', 'password1')
def clean_email(self):
email = self.cleaned_data['email']
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError("User with same email already exist, please change your email")
And here is view of my registration form:
def UserProfileRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password=form.cleaned_data['password'])
user.save()
user_profile = UserProfile(user=user)
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/registration.html', {'form':form})
else:
form = RegistrationForm()
context = {'form':form}
return render (request, 'profiles/registration.html', context)
In user profile i create modelform where user can fill the fields from UserProfile model:
class ExtraProfileDataForm(ModelForm):
name = forms.CharField(label=(u'Enter your name'))
surname = forms.CharField(label=(u'Enter your surname'))
phone = forms.CharField(label=(u'Enter your phone'))
birthday = forms.DateField(label=(u'Enter birthday'))
avatar = forms.ImageField(label=(u'Enter avatar'))
class Meta:
model = UserProfile
fields = ('name', 'surname', 'phone', 'birthday', 'avatar')
def __init__(self, *args, **kwargs):
super(ExtraProfileDataForm, self).__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = False
This is the view of the model form:
#login_required
def UserFullDataForm(request):
if request.method == 'POST':
form = ExtraProfileDataForm(request.POST)
if form.is_valid():
profile_user = request.user
user_profile = UserProfile(user=profile_user)
user_profile.name = form.cleaned_data['name']
user_profile.surname = form.cleaned_data['surname']
user_profile.phone = form.cleaned_data['phone']
user_profile.birthday = form.cleaned_data['birthday']
user_profile.avatar = form.cleaned_data['avatar']
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/extra_profile.html', {'form':form})
else:
form = ExtraProfileDataForm()
context = {'form':form}
return render (request, 'profiles/extra_profile.html', context)
But when I fill this form I got the error:
duplicate key value violates unique constraint "profiles_userprofile_user_id_key" DETAIL: Key (user_id)=(23) already exists.
On the traceback i see that error in this line user_profile.save(). As i understand it happens because this script create new item with same id but not update it. What i have to change on my code to update existing item but not to create. Thank you.
You need to use get_or_create, which will return an existing item if it was found; otherwise create a new instance of the model.
In your user profile update view:
user_profile, created = UserProfile.objects.get_or_create(user=profile.user)
Now, instead of creating a new profile each time - you are updating if a profile for that user already exists.

Categories

Resources