I have a PatientRegistrationForm and a PatientBillingForm form in a single view RegisterPatient.
When when I submit the patient form (form), the submitted date is stored in the database, nut the billing form (form1) only updates the staff and patient fields and nothing is stored in the payment_type, amount and receipt_number.
Please can anyone help point out why the second form is not being updated on the database?
Here is the views, models, forms and template code:
views.py
def RegisterPatient(request):
# bills = obj.bill_set.all()
form = PatientRegistrationForm(request.POST or None)
form1 = PatientBillingForm(request.POST or None)
if form.is_valid() and form1.is_valid():
instance = form.save(commit=False)
instance1 = form1.save(commit=False)
payment_type = form1.cleaned_data["payment_type"]
amount = form1.cleaned_data["amount"]
receipt_number = form1.cleaned_data["receipt_number"]
first_bill = Billing()
first_bill.payment_type = payment_type
first_bill.amount = amount
first_bill.receipt_number = receipt_number
# first_bill.saff
# first_bill.patients
print first_bill.payment_type, first_bill.amount, first_bill.receipt_number
first_name = form.cleaned_data["first_name"]
last_name = form.cleaned_data["last_name"]
other_name = form.cleaned_data["other_name"]
phone_number = form.cleaned_data["phone_number"]
new_patient = Patient()
new_patient.patient_number = UniquePatientNumber()
new_patient.first_name = first_name
new_patient.last_name = last_name
new_patient.other_name = other_name
new_patient.save()
first_bill.save()
model.py
class Patient(models.Model):
patient_number = models.CharField(max_length=120, unique = True, )
first_name = models.CharField(max_length = 120)
last_name = models.CharField(max_length=120)
other_name = models.CharField(max_length = 120, blank=True, null=True)
phone_number = models.CharField(max_length=15)
def _unicode_(self):
return self.patient_number
class Billing(models.Model):
staff = models.ForeignKey(MyUser, default=1)
patients = models.ForeignKey(Patient, default=1)
payment_type = models.CharField(max_length=100)
amount = models.DecimalField(max_digits=100, decimal_places=2, default=0.00)
receipt_number = models.CharField(max_length=120)
payment_date = models.DateTimeField(auto_now=False, auto_now_add=True)
def _unicode_(self):
return self.staff.username
def new_user_receiver(sender, instance, created, *args, **kwargs):
if created:
new_patient, is_created = Billing.objects.get_or_create(patients=instance)
post_save.connect(new_user_receiver, sender=Patient)
def new_user_creator(sender, instance, created, *args, **kwargs):
if created:
new_user, is_created = Billing.objects.get_or_create(staff=instance)
post_save.connect(new_user_creator, sender=MyUser)
form.py
class PatientRegistrationForm(forms.ModelForm):
class Meta:
model = Patient
exclude = ["patient_number"]
class PatientBillingForm(forms.ModelForm):
class Meta:
model = Billing
fields = ["payment_type","amount","receipt_number"]
forms.html
<form method="POST action="">{% csrf_token %}
{{ form }}
{{ form1 }}
<input type="submit" value="Submit"/>
</form>
In your view function you always create new Billing to MyUser with pk=1 and Patients with pk=1 because you set the default values in Billing fields default=1. You should remove default=1 and set null=True,blank=True instead.
If I understand your logic. You want to create new Billing information to every new User oder new Patient. I guess that in your view function you want to update or create Billing information to a patient. If so you should call
Billing.objects.filter(patients__pk=new_patient.pk).update(payment_type=payment_type,amount=amount,receipt_number=receipt_number)
after new_patient.save() then you could comment out lines with first_bill.
Update
1) comment out the line Billing.objects.filter(...)
2) comment out post_save.connect(new_user_receiver, sender=Patient) in models.py
3) activate the lines with first_bill again and add:
first_bill.patients=new_patient after new_patient.save()
Related
I'm trying to pass lesson.price, and lesson.invoice_id from Lesson model and student.student_id from Student Model into the single view so that I can display them in a template.
However, Lesson model has a field "student" which has a foreign key to User, not to Student model. You will see my code for view class is wrong since I have no clue how to get a proper student object with a primary which is used for lesson object.
How could I get a proper student object with lesson_id primary key in view class?
class User(AbstractUser):
'''User model for authentication and lessons authoring.'''
class Role(models.TextChoices):
ADMIN="ADMIN",'Admin'
STUDENT="STUDENT",'Student'
TEACHER="TEACHER",'Teacher'
id = models.AutoField(primary_key=True)
username = models.CharField(
max_length=30,
unique=True,
validators=[RegexValidator(
regex=r'^#\w{3,}$',
message='Username must consist of # followed by at least three alphanumericals.'
)]
)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(unique=True, blank=False)
gender = models.CharField(max_length=255)
address = models.TextField(default='')
baseRole = Role.ADMIN
role = models.CharField(max_length=50, choices=Role.choices)
created_at = models.DateTimeField(default=timezone.now, blank=True)
updated_at = models.DateTimeField(default=timezone.now, blank=True)
def save(self, *args, **kwargs):
self.role = self.baseRole
return super().save(*args, **kwargs)
def __str__(self):
return self.first_name+" "+self.last_name
class Student(User):
student_id = models.CharField(max_length=10, default=uuid.uuid4)
baseRole = User.Role.STUDENT
student = StudentManager()
class Lesson(models.Model):
lesson_id = models.AutoField(primary_key=True)
lesson_name = models.CharField(max_length=255)
student = models.ForeignKey(User,on_delete=models.DO_NOTHING,related_name='studying', unique=True)
teacher = models.ForeignKey(User,on_delete=models.CASCADE, related_name='teaching')
start_time = models.DateTimeField(default=timezone.now)
interval = models.IntegerField()
duration = models.IntegerField()
created_at = models.DateTimeField(default=timezone.now, blank=True)
updated_at = models.DateTimeField(default=timezone.now, blank=True)
is_request = models.BooleanField()
number = models.IntegerField(default=0)
invoice_id = models.CharField(max_length=10, default=uuid.uuid4)
#property
def price(self):
return self.duration/5 * self.number
#staticmethod
def durations():
return [20, 30, 40, 45, 60]
#staticmethod
def subjects():
return ['Guitar','Violin','Piano', 'Voice', 'Cello','Ukulele','Recorder', 'Drums']
#staticmethod
def intervals():
return [2, 5, 7, 10, 14]
def __str__(self):
return "Lesson id: "+str(self.lesson_id)+", Student id: "+str(self.student.id)+", Student: "+str(self.student)
views.py
def invoice(request, lesson_id):
lesson = Lesson.objects.get(lesson_id=lesson_id)
student = Lesson.student.get(student_id=lesson.student.student_id)
return render(request, 'invoice.html', {'lesson':lesson, "student":student})
invoice.html
{% extends 'student/student_home_base.html' %}
{% block student_content %}
<head>Your Invoice</head>
<p>Your invoice reference number is{{lesson.student_id}}-{{lesson.invoice_id}}</p>
<p>Your Total Payable is {{lesson.price}}</p>
<p>Once you're done paying, please click this button below.</p>
<input type="submit" value="submit">
{% endblock %}
lesson = Lesson.objects.get(lesson_id=lesson_id) # you get the Lesson object
student = lesson.student # call the student attribute on the variable "lesson" not the Class Lesson
Note that the variable lesson contains an instance of the Lesson class.
Note that the variable student will actually contain an instance of the User class.
If you want the Student instance you should do:
student = lesson.student.student
where lesson in the Lesson object, the first .student calls the foreignkey relationship with User and the second .student is the relative Student object related by an OneToOne implicit relationship (with User) thanks to the multi-table inheritance.
all details here.
So i'm working on job application portal.
the logic is as follows :
Applicant ---> Applies for ---> Job
Models are (Job, User, Application)
I used the User model from django and i extend it.
Now the dilemma is when i render the ApplicationForm, because i have to update the foreign key and i want it to be updated automatically.
Here is my code :
Models.py
class Job(models.Model):
owner = models.ForeignKey(User,related_name='job_owner',on_delete=models.CASCADE)
title = models.CharField(max_length=100)
#location
job_type = models.CharField(max_length=15,choices=JOB_TYPE)
description= models.TextField(max_length=1000)
published_at = models.DateTimeField(auto_now=True)
vacancy = models.IntegerField(default=1)
salary = models.IntegerField(default=0)
experience = models.IntegerField(default=1)
category = models.ForeignKey('Category',on_delete=models.CASCADE)
icon = models.ImageField(upload_to ='job_icons/',default='job_icons/job.png')
slug = models.SlugField(blank = True,null=True)
class Application(models.Model):
job = models.ForeignKey(Job, related_name="job_applied",on_delete=models.CASCADE)
applicant = models.ForeignKey(User,related_name='job_applicant',on_delete=models.CASCADE)
first_name= models.CharField(max_length=40)
last_name= models.CharField(max_length=40)
email = models.EmailField(max_length=60)
website = models.URLField()
cv = models.FileField(upload_to='application/')
coverletter = models.TextField(max_length=550)
application_date = models.DateTimeField(auto_now=True)
def __str__(self):
return self.last_name+"\t"+self.first_name
Forms.py
class JobApplication(ModelForm):
class Meta:
model = Application
fields = ['first_name', 'last_name','email', 'website','cv','coverletter']
vews.py
def job_detail(request,slug):
job_specific = Job.objects.get(slug=slug)
form = JobApplication(instance=request.user)
if request.method == 'POST':
form = JobApplication(request.POST,request.FILES)
if form.is_valid():
my_form = form.save(commit=False)
my_form.job = job_specific
Application.applicant.user = request.user
Application.job = job_specific
my_form.save()
context ={'job_specific':job_specific, 'form':form,}
return render(request,"job/job_details.html",context)
So once the user submit their application, i wanted to updated the fields that are "foreign key" without prompting the user.
I do not know how to arrange this in the views.py or if it's even possible this way?
thanks to everyone in advance
So i solved the problem, it was really simple solution:
my_form = form.save(commit=False)
my_form.job = job_specific
my_form.applicant = request.user
I'm trying to create an appointment app using Django
but when I add the form it show me all the users
how can i change that to only one type of user
and make the user who register the appointment him self
this is my models.py
class User(AbstractUser):
STATUS_CHOICES = (('paitent', 'paitent'), ('Doctor', 'Doctor'), ('reception', 'reception'), ('temporary', 'temporary'))
STATUS_CHOICES_2 = (('yes', 'yes'), ('no', 'no'))
type_of_user = models.CharField(max_length=200, choices=STATUS_CHOICES, default='paitent')
allowd_to_take_appointement = models.CharField(max_length=20, choices=STATUS_CHOICES_2, default='yes')
def is_doctor(self):
if self.type_of_user == 'Doctor':
return True
else:
return False
def is_paitent(self):
if self.type_of_user == 'paitent':
return True
else:
return False
class Appointement_P(models.Model):
user_ho_add = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_ho_add_appointement')
patient = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name='paitent_app')
doctor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='doctor_app')
date = models.Field(null=True, blank=True, default=timezone.now)
start_time = models.TimeField(null=True, blank=True, default=timezone.now)
end_time = models.TimeField(null=True, blank=True, default=timezone.now)
and this is my fomrs.py
class AppointementForm(forms.ModelForm):
class Meta:
model = Appointement_P
fields = ('doctor', 'date', 'start_time',)
and this is my fucntion in the views.py
def create_appointement_p(request):
user = User()
form_appointement = AppointementForm()
if request.method=='POST':
if request.user.is_paitent():
form_appointement = AppointementForm(request.POST or None)
if form_appointement.is_valid():
form_app = form_appointement.save(commit=False)
form_app.save()
messages.success(request, 'appointement added')
else:
messages.error(request, 'Error')
return render(request,'appointement/add_appointement1.html',)
else:
return HttpResponseRedirect(reverse("create_appointement_D"))
return render(request,'appointement/add_appointement1.html',{'form':form_appointement})
and this is the html file
<body>
<div class="container">
{{ form }}
{% csrf_token %}
<button>
ok
</button>
</form>
</div>
</body>
the problem is in the doctoral field, it show me all the user how can I change that to only users that have a type of doctors
how can I make the user_ho_add automatically the one ho register this appointment?
how can I make the end time of the appointment the start_time + 30 min?
For filtering the doctor field you can customize it in you ModelForm class, like this:
# import your User model first
class AppointementForm(forms.ModelForm):
doctor = forms.ModelChoiceField(queryset=User.objects.filter(type_of_user='Doctor'))
class Meta:
model = Appointement_P
fields = ('doctor', 'date', 'start_time',)
Then for filling the user_ho_add field, just add the user before saving the form_app instance, like this:
def create_appointement_p(request):
...
if form_appointement.is_valid():
form_app = form_appointement.save(commit=False)
form_app.user = request.user # user added here
form_app.save()
messages.success(request, 'appointement added')
...
Bonus tip: for the is_paitent and is_doctor methods, you can simply return the comparison, since the result is already a boolean, like this:
def is_doctor(self):
return self.type_of_user == 'Doctor'
def is_paitent(self):
return self.type_of_user == 'paitent'
UPDATE
As requested in the comment, for adding end_time = start_time + 30min you first need to import the timedelta class from the datetime library.
from datetime import timedelta
# your other imports
...
def create_appointement_p(request):
...
if form_appointement.is_valid():
form_app = form_appointement.save(commit=False)
form_app.user = request.user # user added here
form_app.end_time = form_app.start_time + timedelta(minutes=30) # end_time added here
form_app.save()
messages.success(request, 'appointement added')
...
Bonus tip 2: If you're using Django 3.1 (or above) you can use the models.TextChoices class to create a cleaner way to reference your choices, like this:
class TypeOfUser(models.TextChoices):
# REFERENCE_VALUE = 'string to save in the field', 'string to display (supports translation)'
PAITENT = 'paitent', 'Patient'
DOCTOR = 'doctor', 'Doctor'
RECEPTION = 'reception', 'Reception'
TEMPORARY = 'temporary', 'Temporary'
class AllowdToTakeAppointement(models.TextChoices):
YES = 'yes', 'Yes'
NO = 'no', 'No'
class User(AbstractUser):
type_of_user = models.CharField(max_length=200, choices=TypeOfUser, default=TypeOfUser.PAITENT)
allowd_to_take_appointement = models.CharField(
max_length=20, choices=AllowdToTakeAppointement.choices, default=AllowdToTakeAppointement.YES
)
def is_doctor(self):
return self.type_of_user == TypeOfUser.DOCTOR
def is_paitent(self):
return self.type_of_user == TypeOfUser.PAITENT
Then you can import the TypeOfUser class for your AppointementForm class:
# import your User model and TypeOfUser
class AppointementForm(forms.ModelForm):
doctor = forms.ModelChoiceField(queryset=User.objects.filter(type_of_user=TypeOfUser.DOCTOR))
class Meta:
model = Appointement_P
fields = ('doctor', 'date', 'start_time',)
Hi this is the model I am working with
from django.db import models
from users.models import CustomUser
class Project(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(CustomUser, on_delete=models.PROTECT, editable=False)
name = models.CharField(max_length=20, editable=False)
total = models.DecimalField(max_digits=6, decimal_places=2, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False, null=False, blank=False)
def __str__(self):
return self.name
The class is populated by an HTML form using this view:
def homepage(request):
if request.method == "POST":
project = Project()
name = request.POST.get('name')
total = request.POST.get('total')
created = datetime.datetime.now()
user = request.user
project.user = user
project.name = name
project.total = total
project.created = created
project.save()
#return HttpResponse(reverse("homepage.views.homepage"))
return render(request, 'homepage.html')
else:
return render(request, 'homepage.html')
and so I have added a custom tag into my app which is a function
#register.filter
def monthlyTotal(user):
this_month = now().month
return Project.objects.filter(
created__month=this_month,
user=user
).aggregate(
sum_total=Sum('total')
)['sum_total']
I call the tag like this in template
<p>Total monthly sales = {{ user.username|monthlyTotal }}</p>
however I get an error saying Field ID expected a number but got 'grandmaster' which is the name of my test user who has multiple Project objects.. if I switch to user.id I get no error but it displays None which makes sense because when I look at my project section in admin the field user is populated by the username not the id so there would be no project where user=id
You need to use the user, not the username, so:
<p>Total monthly sales = {{ user|monthlyTotal }}</p>
I want to be able to have a user update two models with one submit button. The first model will house all of the book titles (unique) and pages that users submit. The other will show which users submitted which books.
Ideally, I'd like to do something like this:
if request.method == "POST":
form = AddBookForm(request.POST)
if form.is_valid():
books = form.save(commit=False)
ub = UserBooks()
books.book_title = form.cleaned_data['book_title']
books.book_total_pages = form.cleaned_data['book_total_pages']
ub.user = request.user
ub.book_title = form.cleaned_data['book_title']
ub.save()
books.save()
return redirect('new_book')
But that's giving me the error:
Cannot assign "'Some Book Title'": "UserBooks.book_title" must be a
"Books" instance.
What would be the best way to update two models with one form?
Here are the other files.
models.py
class Books(models.Model):
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
book_title = models.CharField(max_length=100, unique=True)
book_total_pages = models.IntegerField()
class Meta:
ordering = ('-created',)
def __str__(self):
return '{0}'.format(self.book_title)
class UserBooks(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False)
book_title = models.ForeignKey(Books, on_delete=models.CASCADE, null=False, blank=False)
views.py
def new_book(request):
user = request.user
if request.method == "POST":
form = AddBookForm(request.POST)
if form.is_valid():
books = form.save(commit=False)
books.book_title = form.cleaned_data['book_title']
books.book_total_pages = form.cleaned_data['book_total_pages']
books.save()
return redirect('new_book')
else:
form = AddBookForm()
return render(request, 'main/addanewbook.html', {
'form': form,
'allBooks': allBooks,
'userbooks': userbooks,
})
forms.py
class AddBookForm(forms.ModelForm):
class Meta:
model = Books
fields = ('book_title', 'book_total_pages')
you need to change a bit in the view
if form.is_valid():
books = form.save(commit=False)
ub = UserBooks()
books.book_title = form.cleaned_data['book_title']
books.book_total_pages = form.cleaned_data['book_total_pages']
books = books.save()
ub.user = request.user
ub.book_title = books
ub.save()
return redirect('new_book')
this will do it