How to create Quiz Instance from a m2m Model? - python

I want to create a Quiz App where user can sign in and solve the Quizes which is related to the specific Subject. And the user's data should be stored in the database. In other word, If the user solves the all questions, I have to create a Quiz Instance for him/her. Here i used M2M relationship where many user can solve one subject or one Subject can be solved by many users. When i create Quiz Instance from admin panel it is not giving me an error, But i couldn't create it from views.py. This is my Quiz Model:
from django.contrib.auth.models import User
ANSWER_CHOICES = (
("A", "A"),
("B", "B"),
("C", "C"),
("D", "D"),
)
# Create your models here.
class Subject(models.Model):
name = models.CharField(max_length=150, null=True, blank=True)
teacher = models.CharField(max_length=200, null=True, blank=True)
description = models.CharField(max_length=250, null=True, blank=True)
featured_image = models.ImageField(null=True, blank=True, default='default.jpg')
created = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return str(self.name)
class Meta:
ordering = ['id']
class Quiz(models.Model):
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, null=True, blank=True)
question = models.TextField(null=True, blank=True)
a = models.CharField(max_length=50, null=True, blank=True, unique=True)
b = models.CharField(max_length=50, null=True, blank=True, unique=True)
c = models.CharField(max_length=50, null=True, blank=True, unique=True)
d = models.CharField(max_length=50, null=True, blank=True, unique=True)
options = models.CharField(max_length=50, choices=ANSWER_CHOICES, blank=True, null=True, default='A')
answer = models.CharField(max_length=50, blank=True, null=True)
submitted = models.BooleanField(default=False)
def __str__(self) -> str:
return str(self.question)
class Meta:
ordering = ['question']
class QuizInstance(models.Model):
username = models.CharField(max_length=200, null=True, blank=True)
taker = models.ManyToManyField(User)
quiz = models.ManyToManyField(Subject)
quiz_taken = models.DateTimeField(auto_now_add=True)
score = models.IntegerField(default=0)
complete = models.BooleanField(default=False, null=True, blank=True)
def __str__(self) -> str:
return str('Exam Test')
Also, i want to show the result of the Quiz when the quiz is completed.Therefore i created var score, but no metter what i do i couldn't implement.
my views.py model:
from django.shortcuts import render, redirect
from .models import Subject, Quiz
from django.core.paginator import Paginator
from django.http import HttpResponse
from .forms import AnswerOptionsForm
from .models import QuizInstance
from django.contrib.auth.decorators import login_required
# Create your views here.
def homePage(request):
return render(request, 'home.html')
def quizCard(request):
subjects = Subject.objects.all()
context = {'subjects': subjects}
return render(request, 'quiz-card.html', context)
#login_required(login_url='sign-in')
def getQuestion(request, id):
subject = Subject.objects.get(id=id)
form = AnswerOptionsForm()
obj = subject.quiz_set.all()
p = Paginator(obj, 1)
submitted = False
try:
page = int(request.GET.get('page', '1'))
except:
page = 1
try:
questions = p.page(page)
except(EmptyPage, InvalidPage):
return redirect('result', int(subject.id))
page = p.num_pages
if request.method == 'POST':
submitted = True
currentQuestion = Quiz.objects.get(id=page)
currentQuestion.submitted = True
ans = request.POST.get('options')
print(ans)
if currentQuestion.answer == ans:
pass
# exam.score += 1
# exam.save()
# print(exam.score)
context = {'obj': obj, 'questions': questions, 'page':page, 'form': form, 'submitted': submitted, 'subject': subject}
return render(request, 'questions.html', context)
def result(request, id):
user = request.user.useraccount
subject = Subject.objects.get(id=id)
number_of_questions = len(subject.quiz_set.all())
user.completed_subject.add(subject)
user.save()
###This is Giving me an error###
exam = QuizInstance.objects.filter(
taker = request.user,
quiz = subject,
)
return HttpResponse(f'You have found out of {number_of_questions}')
def retakeQuiz(request, id):
subject = Subject.objects.get(id=id)
exam = QuizInstance.objects.filter(
taker = request.user,
quiz = subject,
score = 0,
complete = False,
)
exam.score = 0
return redirect('question', id)
user models.py
from django.db import models
from django.contrib.auth.models import User
from quiz.models import Quiz
from quiz.models import Subject
# Create your models here.
class UserAccount(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
username = models.CharField(max_length=150, blank=True, null=True)
programming_language = models.CharField(max_length=200, blank=True, null=True)
password = models.CharField(max_length=200, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
email = models.EmailField(max_length=300, blank=True, null=True)
completed_subject = models.ManyToManyField(Subject, default=Subject.objects.all)
def __str__(self) -> str:
return str(self.username)

Related

Connect the username when sending a report in django

I am beginner to django and I am trying to create a site to send reports after creating a profile, but when I send the report, the username of the author of the report is not saved, Just (None). I searched a lot about it and did not find it
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, verbose_name=("user"), null=True, on_delete=models.CASCADE)
identity_No = models.IntegerField( blank=True, null=True)
mobile_No = models.IntegerField( blank=True, null=True)
city = models.CharField( max_length=15,null=True)
class Meta:
verbose_name =("Profile")
verbose_name_plural =("Profile")
def __str__(self):
return '%s' %(self.user)
class Report(models.Model):
user = models.ForeignKey(User, verbose_name=("user"), on_delete=models.CASCADE)
Report_type =models.CharField( max_length=100, blank=True, null=True)
Region =models.CharField( max_length=30, blank=True, null=True)
city =models.CharField( max_length=30, blank=True, null=True)
sector =models.CharField( max_length=30, blank=True, null=True)
report =models.TextField( max_length=3000, blank=True, null=True)
files =models.FileField( blank=True, null=True)
class Meta:
verbose_name =("Report")
verbose_name_plural =("Report")
def __str__(self):
return '%s' %(self.user)
form.py
Shorten the time, attach only the report
class ReportForm(forms.ModelForm):
class Meta:
model = Report
fields = ['Report_type', 'Region', 'city','sector','report','files' ]
view.py
def report(requst):
if requst.method == 'POST':
report_form = ReportForm(requst.POST)
if report_form.is_valid() :
report_form.save()
return redirect ('accounts:home')
else:
report_form = ReportForm()
return render(requst, 'user/report.html', {
'report_form': report_form,
enter image description here })
You can link the new report wrapped in the ReportForm to the logged in user request.user with:
from django.contrib.auth.decorators import login_required
#login_required
def report(requst):
if requst.method == 'POST':
report_form = ReportForm(requst.POST)
if report_form.is_valid():
report_form.instance.user = request.user
report_form.save()
return redirect ('accounts:home')
else:
report_form = ReportForm()
return render(requst, 'user/report.html', { 'report_form': report_form })
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

TypeError: __str__ returned non-string (type NoneType). Not sure how to solve this

[![Nurse admin page[![][1]][1][models.py
from django.db import models
#Work Related aka Department and Work Shift
class Department(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.name
class WorkShift(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
start_datetime = models.DateTimeField(null=True, blank=True)
end_datetime = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.name
#Personel Related aka Employees and Patients
class Doctor(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
email = models.CharField(max_length=200, null=True)
phone = models.CharField(max_length=200, null=True)
department = models.ForeignKey(Department, default="", null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Nurse(models.Model):
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
phone = models.CharField(max_length=200, null=True)
department = models.ForeignKey(Department, default="", null=True, blank=True, on_delete=models.CASCADE)
reports_to = models.OneToOneField(Doctor, default="", blank=True, null=True, on_delete=models.CASCADE)
work_shift = models.OneToOneField(WorkShift, default="", blank=True, null=True, on_delete=models.CASCADE)
def __str__(self):
return str(name)
class Patient(models.Model):
STATUS = (
('Sick', 'Sick'),
('Healing', 'Healing'),
('Cured', 'Cured'),
('Deceased', 'Deceased'),
)
name = models.CharField(max_length=200, null=True, blank=True)
description = models.TextField(blank=True, null=True)
status = models.CharField(max_length=200, null=True, blank=True, choices=STATUS)
department = models.ForeignKey(Department, default="", null=True, blank=True, on_delete=models.CASCADE)
care = models.ForeignKey(Nurse, default="", blank=True, null=True, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True, blank=True, null=True)
def __str__(self):
return self.name
views.py
from django.shortcuts import render
# Create your views here.
from django.shortcuts import render
from .models import Doctor, Nurse, Patient
from django.http import HttpResponse
# Create your views here.
def index(request):
patient = Patient.objects.all()
nurse = Nurse.objects.all()
doctor = Doctor.objects.all()
total_patient = patient.count()
sick = patient.filter(status='Sick').count()
healing = patient.filter(status='Healing').count()
cured = patient.filter(status='Cured').count()
total_nurse = nurse.count()
# if request.method == 'POST':
# form =
context = {
'patient':patient, 'nurse':nurse,
'doctor':doctor, 'total_patient':total_patient,
'sick':sick, 'healing':healing, 'cured':cured,
'total_nurse':total_nurse
}
return render(request, 'lifesaver/index.html', context)
def patient(request):
patient = Patient.objects.all()
total_patient = patient.count()
context = {
'patient':patient,
'total_patient':total_patient
}
return render(request, 'lifesaver/patient.html', context)][1]
forms.py
from django import forms
from .models import Doctor, Nurse, Patient
from django.auth.contrib.forms import UserCreationForm
class DoctorForm(forms.ModelForm):
name = forms.CharField(widget = forms.TextInput(attrs =
{
'placeholder': 'Add a New Doctor',
'class': 'form-control'
}
))
department = forms.ModelChoiceField(queryset=department.objects.all)
class NurseForm(forms.ModelForm):
name = forms.CharField(widget = forms.TextInput(attrs =
{
'placeholder': 'Add a New Nurse',
'class': 'form-control'
}
))
class PatientForm(forms.ModelForm):
name = forms.CharField(widget = forms.TextInput(attrs =
{
'placeholder': 'Add a New Patient'
'class': 'form-control'
}))
HTML for patient
{% extends 'lifesaver/main.html' %}
{% block content %}
<h1>SUPERSTAR</h1>
{% for patient in patient %}
{{patient.name}}
{% endfor %}
{% endblock content %}
I get this error when I go to try to add another Nurse. The URL is http://127.0.0.1:8000/admin/lifesaver/nurse/add/. Everything else behaves as expected, except the adding the Nurse part.
If I try to remove the def __str___ part, the error still displays. I believe the error lies in the:
work_shift = models.OneToOneField(WorkShift, default="",
blank=True,
null=True,
on_delete=models.CASCADE)
part since when I included that code, the error spawned. Furthermore, the code is to add a work shift to certain employees and the goal is that the employees shift will display in their profile.
How do I fix this issue?
EDIT: When accessing the HTML template, the web page behaves as expected and has no issues.
In your Nurse model replace this:
def __str__(self):
return str(Nurse.name)
with this:
def __str__(self):
return self.name

How to add manytomany relation in other class . In my case in InfoCreateView class

I am making a CV page,
I want to link my Skill, Language etc class(table) to Main Person table/class,
But for that, I need to submit skill table first because my person table contains the foreign key for skills.
But as per CV form name & personal info comes first.
Also, I can put the whole form on one page but I want to go to the next page for each sub information, so is it possible to pass the request data from one class-based view to another class-based view.
models.py
from django.db import models
from django.core.validators import MinLengthValidator
from django.conf import settings
import datetime
class Workexperience(models.Model):
work = models.CharField(null=True, blank=True,
max_length=256,
help_text='eg: Juniorengineer: at L&T ')
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.work
class Education(models.Model):
school = models.CharField(max_length=200)
college = models.CharField(null=True, blank=True,max_length=200)
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.school
class Skills(models.Model):
skill = models.CharField(
max_length=256,
help_text='Add skills sperated by commas eg: programming, Matlab')
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.skill
class Languages(models.Model):
language = models.CharField(
max_length=256,
help_text='Add language sperated by commas eg: English, Gujarati')
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.language
class Person(models.Model):
name = models.CharField(
max_length=100,
help_text='Enter a name (e.g. Harry Virani)',
validators=[MinLengthValidator(2, "It must be greater than 1 character")]
)
picture = models.BinaryField(null=True, blank=True, editable=True)
content_type = models.CharField(max_length=256, null=True, blank=True,
help_text='The MIMEType of the file')
profession = models.CharField(
max_length=100,
validators=[MinLengthValidator(2, "It must be greater than 1 character")]
)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default='')
address = models.CharField(max_length=256)
email = models.EmailField(max_length = 254)
phone = models.CharField(
max_length=15,
help_text='Enter a phone number like this (e.g. +91000000000)',
validators=[MinLengthValidator(10, "It must be greater than 10 character")] )
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
facebook = models.URLField(null=True, blank=True, max_length=200,
help_text='enter your facebook URL' )
instagram = models.URLField(null=True, blank=True, max_length=200,
help_text='enter your instagram link URL' )
linkedin = models.URLField(null=True, blank=True, max_length=200,
help_text='enter your Linked link URL' )
skill = models.ManyToManyField(Skills, related_name='skills', default=1)
language = models.ManyToManyField(Languages, related_name='languages', default=1)
edu = models.ManyToManyField(Education, default=1,related_name='edu' )
work = models.ManyToManyField(Workexperience,default=1, blank=True, related_name='works')
# Shows up in the admin list
def __str__(self):
return self.name
views.py
I want to save it in another class which is for creating skill & other models.
class PersonCreateView(LoginRequiredMixin, View):
template_name = 'MYP/form.html'
success_url = 'MYP:myp_create_info'
def get(self, request, pk=None):
personform = PersonForm()
ctx = { 'personform': personform}
return render(request, self.template_name, ctx)
def post(self, request, pk=None) :
# if 'personform' in request.POST:
personform = PersonForm(request.POST, request.FILES or None)
if not personform.is_valid():
ctx = {'personform': personform}
return render(request, self.template_name, ctx)
pform = personform.save(commit=False)
#adding onwer
pform.owner = self.request.user
pform.save()
return redirect(self.success_url, pform.id)
class InfoCreateView(LoginRequiredMixin, View):
template_name = 'MYP/form2.html'
success_url = reverse_lazy('MYP:all')
def get(self, request, pk):
person = get_object_or_404(Person,id=pk)
skill= SkillsForm()
skill_list = Skills.objects.filter(person=person)
ctx = { 'skill':skill, 'skill_list':skill_list }
return render(request, self.template_name, ctx)
def post(self, request, pk):
if 'skill' in request.POST:
skill = SkillsForm(request.POST or None)
if not skill.is_valid() :
ctx = { 'skill':skill}
return render(request, self.template_name, ctx)
person = get_object_or_404(Person,id=pk)
print(person)
skill = Skills(skill=request.POST['skill'], person=person)
skill.save()
print(skill.person)
return redirect('MYP:myp_create_info', pk=pk)
forms.py
class PersonForm(forms.ModelForm):
max_upload_limit = 2 * 1024 * 1024
max_upload_limit_text = naturalsize(max_upload_limit)
# Call this 'picture' so it gets copied from the form to the in-memory model
# It will not be the "bytes", it will be the "InMemoryUploadedFile"
# because we need to pull out things like content_type
picture = forms.FileField(required=False, label='File to Upload <= '+max_upload_limit_text)
upload_field_name = 'picture'
# Hint: this will need to be changed for use in the ads application :)
class Meta:
model = Person
fields = ['name', 'profession', 'picture', 'address', 'email', 'phone','facebook','linkedin','instagram'] # Picture is manual
# Validate the size of the picture
def clean(self) :
cleaned_data = super().clean()
pic = cleaned_data.get('picture')
if pic is None : return
if len(pic) > self.max_upload_limit:
self.add_error('picture', "File must be < "+self.max_upload_limit_text+" bytes")
# Convert uploaded File object to a picture
def save(self, commit=True) :
instance = super(PersonForm, self).save(commit=False)
# We only need to adjust picture if it is a freshly uploaded file
f = instance.picture # Make a copy
if isinstance(f, InMemoryUploadedFile): # Extract data from the form to the model
bytearr = f.read();
instance.content_type = f.content_type
instance.picture = bytearr # Overwrite with the actual image data
if commit:
instance.save()
return instance
class WorkexperienceForm(forms.ModelForm):
class Meta:
model = Workexperience
fields = ['work']
class EducationForm(forms.ModelForm):
class Meta:
model = Education
fields = ['school','college']
class SkillsForm(forms.ModelForm):
class Meta:
model = Skills
fields = ['skill']
class LanguagesForm(forms.ModelForm):
class Meta:
model = Languages
fields = ['language']
Ignore the rest of the code it is just for image handling....
This is what I want to do but I know it is the wrong format
I want to just add id for everything later.
In my opinion, your models are messed up. Here is how I would have write them :
class WorkExperience(models.Model):
work = models.CharField(
blank=True,
max_length=256,
help_text='eg: Juniorengineer: at L&T'
)
def __str__(self):
return self.work
class Education(models.Model):
school = models.CharField(max_length=200)
college = models.CharField(blank=True, max_length=200)
def __str__(self):
return self.school
class Skill(models.Model):
name = models.CharField(
max_length=256,
help_text='Add a skill name (eg: Programming)'
)
def __str__(self):
return self.name
class Language(models.Model):
name = models.CharField(
max_length=256,
help_text='Add a language name (eg: Gujarati)'
)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(
max_length=100,
help_text='Enter a name (e.g. Harry Virani)',
validators=[MinLengthValidator(2, "It must be greater than 1 character")]
)
# [...Other fields...]
skills = models.ManyToManyField(Skill, related_name='persons', blank=True)
languages = models.ManyToManyField(Language, related_name='persons', blank=True)
educations = models.ManyToManyField(Education, related_name='persons', blank=True)
work_experiences = models.ManyToManyField(WorkExperience, related_name='persons', blank=True)
def __str__(self):
return self.name
Then I need to see your forms.py to better understand how you handle it in your view.

Multiple Django OneToOne ModelForm Validation in single Create View

I have three modelforms and I am trying to validate those forms in a single view. All forms are connected with OneToOne relation. I cannot validate subforms after main form ins same view. Tried few solutions and I guess I am doing something wrong and if someone can help I can redo it few times to understand it at my end. DoctorForm works fine but I couldn't find a suitable method to validate DoctorQualificationForm() and WorkExperienceForm(). Following is the code:
Models:
class User(AbstractUser):
ACC_TYPE = (
('', ''),
('Doctor', 'Doctor'),
('Patient', 'Patient')
)
account_type = models.CharField(max_length=20, choices=ACC_TYPE, null=True, blank=True)
cell_phone = models.IntegerField(null=True, blank=True)
landline = models.IntegerField(null=True, blank=True)
pic = models.ImageField(upload_to='profile/', null=True, blank=True)
secondary_email = models.EmailField(null=True, blank=True)
def __str__(self):
return str(self.username)
def get_absolute_url(self):
return reverse('user:detail', kwargs={'pk':self.user.pk})
class Role(models.Model):
LAB_ADMIN = 1
SALES_ADMIN = 2
SALES_EXCUTIVE = 3
LAB_TECH = 4
ROLE_CHOICES = (
(LAB_ADMIN, 'Lab Admin'),
(SALES_ADMIN, 'Sales Admin'),
(SALES_EXCUTIVE, 'Sales Executive'),
(LAB_TECH, 'Lab Tech'),
)
id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)
doctor = models.OneToOneField('Doctor', on_delete=models.CASCADE, related_name='roles')
def __str__(self):
return self.id
class Doctor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='doctor', null=True)
about = models.TextField()
#role = models.OneToOneField(Role, on_delete=models.CASCADE, related_name='currentrole',null=True, blank=True)
street = models.CharField(max_length=200)
city = models.CharField(max_length=200)
country = models.CharField(max_length=200)
cell_phone = models.CharField(max_length=200)
landline = models.CharField(max_length=200)
def __str__(self):
return str(self.user)
def get_absolute_url(self):
return reverse('doctor:detail', kwargs={'pk':self.pk})
class Qualitifaction(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE,
related_name='qualifications')
course_title = models.CharField(max_length=100)
institute_name = models.CharField(max_length=200)
location = models.CharField(max_length=200)
start_year = models.DateField(null=True)
end_year = models.DateField(null=True)
def __str__(self):
return self.course_title
def get_absolute_url(self):
return reverse('doctor:detail', kwargs={'pk':self.pk})
class WorkExperience(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE,
related_name='experience')
organization_name = models.CharField(max_length=100)
year_from = models.DateField(null=True)
year_to = models.DateField(null=True)
employement_role = models.CharField(max_length=200)
industry = models.CharField(max_length=200)
def __str__(self):
return self.organization_name
def get_absolute_url(self):
return reverse('doctor:detail', kwargs={'pk':self.pk})
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
if instance.account_type=='Employee':
profile = Employee.objects.get_or_create(user=instance)
elif instance.account_type=='Customer':
profile = Customer.objects.get_or_create(user=instance)
post_save.connect(update_user_profile, sender=User)
Forms:
class DoctorForm(forms.ModelForm):
model = Doctor
fields = ('about', 'street', 'city', 'country', 'cell_phone', 'landline',)
class DoctorQualificationForm(forms.ModelForm):
model = Qualitifaction
fields = ('course_title', 'institute_name', 'location', 'start_year', 'end_year')
class WorkExperienceForm(forms.ModelForm):
model = WorkExperience
fields = ('organization_name', 'year_from, 'year_to', 'employement_role', 'industry')
View:
def createDoctor(request):
if request.method == 'POST':
doctorform = DoctorForm(request.POST, instance=request.user.doctor)
qualifications_form = DoctorQualificationForm()# not sure how to ref instance here
workexperience_form = WorkExperienceForm()# not sure how to ref instance here
if doctorform.is_valid() and qualifications_form.is_valid() and workexperience_form.is_valid():
doctorform.save()
qualifications_form.save()
workexperience_form.save()
else:
doctorform = DoctorForm()
qualifications_form = DoctorQualificationForm()
workexperience_form = WorkExperienceForm()
return render(request, 'doctor/create.html', {'doctorform':doctorform, 'qualifications_form':qualifications_form, 'workexperience_form':workexperience_form})
def createDoctor(request):
if request.method == 'POST':
doctorform = DoctorForm(request.POST, instance=request.user.doctor)
qualifications_form = DoctorQualificationForm(request.POST)# not sure how to ref instance here
workexperience_form = WorkExperienceForm(request.POST)
if doctorform.is_valid() and qualifications_form.is_valid() and workexperience_form.is_valid():
doctor = doctorform.save()
qualification = qualifications_form.save(commit=False)
qualification.doctor = doctor
qualification.save()
work = workexperience_form.save(commit=False)
work.doctor = doctor
work.save()
else:
doctorform = DoctorForm()
qualifications_form = DoctorQualificationForm()
workexperience_form = WorkExperienceForm()
return render(request, 'doctor/create.html', {'doctorform':doctorform, 'qualifications_form':qualifications_form, 'workexperience_form':workexperience_form})
Although there are number of other ways to do it. But in case you have OneToOne rel in all models you just need to use validation of single or parent model. You can reference that validation in all the children as above.

How to filter a User model with a ForeignKey using custom URL format

Intended URL format:
api/v1/users?applicant={applicantId}
Current (working) URL format:
path('users/applicant/<int:pk>/')
How do I check if an applicant has already setup an account on the system as User using the applicantID (which has a foreignkey relationship with the Users table)?
models.py:
class Applicant(models.Model):
APPLICATION_STATUS = (
(1, 'Pending'),
(2, 'Accept'),
(3, 'Reject'),
)
first_name = models.CharField(max_length=200, blank=False,
null=False)
last_name = models.CharField(max_length=200, blank=False,
null=False)
email = models.EmailField(max_length=200, blank=False, null=False,
unique=True)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$',
message="Phone number must be entered in the format: '+999999999'.
Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex],
max_length=17, blank=True, null=False, unique=True) # validators
should be a list
linkedin_url = models.URLField(max_length=255, unique=True,
blank=True, null=True) #make sure diff users cant use two same
profile
twitter_url = models.URLField(max_length=255, unique=True) #make
sure diff users cant use two same profile
articles = ArrayField(models.URLField(), blank=False, null=False,
unique=True, size=3)
country = models.ForeignKey(Country, on_delete=models.CASCADE,
blank=False, related_name="applicant")
category = models.ForeignKey(Category, on_delete=models.CASCADE,
related_name="applicant", blank=False)
status = models.CharField(max_length=200,
choices=APPLICATION_STATUS, default=1)
def __str__(self):
return self.first_name
class User(AbstractUser):
USER_TYPE_CHOICES = (
(1, 'Journalist'),
(2, 'Admin'),
)
GENDER = (
(1, 'Male'),
(2, 'Female')
)
first_name = models.CharField(max_length=200, blank=False)
last_name = models.CharField(max_length=200, blank=False)
# is_active = models.BooleanField(default=True)
password = models.CharField(max_length=200)
email = models.EmailField(max_length=250, unique=True)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$',
message="Phone number must be entered in the format:
'+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex],
max_length=17, unique=True, blank=False) # validators should be a
list
user_type = models.CharField(max_length=200,
choices=USER_TYPE_CHOICES, default=1)
category = models.ForeignKey(Category, on_delete=models.CASCADE,
related_name="users")
# posts_url = ArrayField(models.URLField(), size=3)
country = models.ForeignKey(Country, on_delete=models.CASCADE,
blank=True, related_name="users")
gender = models.CharField(max_length=200, choices=GENDER)
image_url = models.URLField(max_length=255)
about = models.TextField()
applicant = models.ForeignKey(Applicant,
on_delete=models.CASCADE, blank=True, null=True,
related_name="users")
def __str__(self):
return self.username
class Meta:
ordering = ("-date_joined",)
views.py:
class IdentifyUserApplicantID(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = ApplicantSerializer
permission_classes = (IsAuthenticated,)
# def get_queryset(self, pk):
# return Applicant.objects.get(id=pk)
def get(self, request):
data = request.data.get('pk')
admin_user = User.objects.get(user_type=2)
if request.user == admin_user:
try:
queryset = User.objects.get(applicant=data)
serializer = UserSerializer(queryset)
return Response(jsend.success({'users':
serializer.data}))
except User.DoesNotExist:
return Response(jsend.success({'users': '[]'}))
else:
return Response((jsend.error("You are not authorized to
perform this action")),
status=status.HTTP_404_NOT_FOUND)
P.S: I checked out django-filter module but the docs isn't clearly written and a bit hard to understand. Would be glad if more clarification is made in that regard if django-filter is the recommended way of implementing the solution.
I don't know if I understand your question, but do you mean something like this:
if User.objects.filter(applicant__id=pk).exists():
path('api/v1/users', views.YOURVIEW.as_view())
and in the view
applicantId = request.GET.get('applicant', None)
The key was to filter against query parameter, which was done here: http://www.django-rest-framework.org/api-guide/filtering/#filtering-against-query-parameters
Using request.query_params.get() to get the users query via URL in your .get_queryset() method...and pass it as your queryset when creating a response object.
My updated views.py:
class IdentifyUserApplicantID(generics.ListAPIView):
serializer_class = UserSerializer
permission_classes = [IsAuthenticated,]
queryset = User.objects.all()
def get_queryset(self):
queryset = User.objects.all()
applicant = self.request.query_params.get("applicant", None)
if applicant is not None:
queryset = queryset.get(applicant=applicant)
return queryset
def get(self, request):
if request.user.user_type == "2":
try:
queryset = self.get_queryset()
serializer = UserSerializer(queryset)
return Response(jsend.success({'user': serializer.data}))
except User.DoesNotExist:
return Response(jsend.success({'user': '[]'}))
else:
return Response((jsend.error("You are not authorized to perform
this action")),status=status.HTTP_403_FORBIDDEN)
My updated urls.py
re_path(r'^users$', IdentifyUserApplicantID.as_view(), name="identify-
applicant"),
Example Query:
http://example.com/api/v1/users?applicant=2
Hope this helps. Thanks everyone for your answers.

Categories

Resources