So I have these models Question, Answer, and UserAnswer that make up a quiz. The problem I'm facing is making a form that validates with these models. I have an idea of how to do it but it's not working.
class QAForm(forms.Form):
answers = forms.ChoiceField(label='Question is this', choices=[('Answer1','Answer1'),('Answer2','Answer2')], widget=forms.RadioSelect())
This works for 1 form, not for thousands. How would I modify this code so that users sees all of the user-generated questions & answers as form and can provide their own answer to it.
I have this (it works but I know it's not a good practice):
def questions(request):
queryset = Questions.objects.all()
if request.method =='POST':
a = request.POST['answer']
answer = Answer.objects.get(answer=a)
importance = request.POST['importance']
q = request.POST['question']
question = Questions.objects.get(id=q)
try:
user_answer = UserAnswers.objects.get(owner=request.user, question=question)
user_answer.answer = answer
user_answer.importance = importance
user_answer.save()
except:
user_answer = UserAnswers(owner=request.user, question=question, answer=answer, importance=importance)
user_answer.save()
else:
try:
current = UserAnswers.objects.all().filter(owner=request.user)
except:
current = ''
return render_to_response("questions/base.html", locals(), context_instance=RequestContext(request))
My models:
class Answer(models.Model):
answer = models.CharField(max_length=120)
question = models.ForeignKey('Questions', null=True, blank=True)
def __unicode__(self):
return self.answer
IMPORTANCE = (
('Irrelevant', 'Irrelevant'),
('A Little Important', 'A Little Important'),
('Somewhat Important', 'Somewhat Important'),
('Very Important', 'Very Important'),
('Mandatory', 'Mandatory'),
)
class Questions(models.Model):
owner = models.ForeignKey(User)
question = models.CharField(max_length=300)
importance = models.CharField(max_length=120, choices=IMPORTANCE, null=True, blank=True)
updated = models.DateTimeField(auto_now=False, auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.question
class Meta:
verbose_name ='Question'
verbose_name_plural ='Questions'
class UserAnswers(models.Model):
owner = models.ForeignKey(User)
question = models.ForeignKey(Questions)
answer = models.ForeignKey(Answer)
importance = models.CharField(max_length=120, choices=IMPORTANCE)
def __unicode__(self):
return str(self.owner) + " " + str(self.answer) + " " + str(self.importance)
How about this? (Haven't actually tested it, but it should work)
class QuestionForm(forms.ModelForm):
answer = forms.ChoiceField(required=True, widget=forms.RadioSelect())
def __init__(self, question=None, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
self.fields['answer'].choices = [(a.text, a.value) for a in Answer.objects.filter(question=question)]
class Meta:
model = Question
fields = ('text')
Then initiating it like -
q = Question.objects.get(pk=1)
qform = QuestionForm(instance=q)
This can be done when you want just one form. You can use a FormSet if you want thousands of it.
PS: I'm assuming the Answer model has a foreignkey to the Question model and they have already been filled up.
Latest code for your demand. You can try this code :
class QuestionForm(forms.ModelForm):
answer = forms.ChoiceField(required=True, widget=forms.RadioSelect())
def __init__(self, question=None, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
self.fields['answer'].choices = [(a.text, a.value) for a in Answer.objects.filter(question=question)]
class Meta:
model = Question
fields = ('text')
general knowledge
Related
So I have been following this tutorial related to dependent dropdowns which can be found here and I seem to have gotten stuck at the last part the else if statement and am unable to implement the same in my project
postlog models.py:
from django.db import models
# Create your models here.
class FlightNum(models.Model):
fl_no =models.CharField(max_length=5,primary_key=True)
def __str__(self):
return self.fl_no
class Destination(models.Model):
fl_no= models.OneToOneField(FlightNum,on_delete=models.CASCADE,related_name='fl1')
dest= models.CharField(max_length=15,blank=True)
def __str__(self):
return self.dest
class Parking(models.Model):
fl_no= models.OneToOneField(FlightNum,on_delete=models.CASCADE,related_name='fl2')
park_bay= models.CharField(max_length=3)
def __str__(self):
return self.park_bay
class DepartureTime(models.Model):
fl_no= models.OneToOneField(FlightNum,on_delete=models.CASCADE,related_name='fl3')
dep_time= models.CharField(max_length=9)
def __str__(self):
return self.dep_time
class Flight(models.Model):
fl_no= models.OneToOneField(FlightNum,on_delete=models.CASCADE, primary_key=True, related_name='fl4')
park_bay= models.ForeignKey(Parking, on_delete=models.CASCADE)
dest= models.ForeignKey(Destination, on_delete=models.CASCADE)
dep_time= models.ForeignKey(DepartureTime, on_delete=models.CASCADE)
inbound= models.CharField(max_length=15,blank=True)
airline= models.CharField(max_length=15)
arr_time= models.TimeField()
status models.py:
from django.db import models
from postlog.models import FlightNum,Destination,Parking,DepartureTime
# Create your models here.
class FlightStatus(models.Model):
CLEANING_CHOICES = (
('Yes', 'Yes'),
('No','No'),
)
fl_no= models.OneToOneField(FlightNum,on_delete=models.CASCADE,related_name='fli_no',primary_key=True)
park_bay= models.ForeignKey(Parking,on_delete=models.CASCADE,related_name='parki_bay')
catering= models.CharField(max_length=9)
fuel= models.IntegerField()
pas_cnt= models.IntegerField()
dest= models.ForeignKey(Destination,on_delete=models.CASCADE,related_name='desti',null=True)
dep_time=models.ForeignKey(DepartureTime,on_delete=models.CASCADE,related_name='dept_time')
Cleaning = models.CharField( max_length=3, choices=CLEANING_CHOICES)
status forms.py:
from django.forms import ModelForm
from status.models import FlightStatus
from postlog.models import FlightNum,Destination,Parking,DepartureTime
class StatusForm(ModelForm):
class Meta:
model = FlightStatus
fields = ('fl_no', 'park_bay', 'catering', 'fuel', 'pas_cnt', 'dest','dep_time', 'Cleaning')
labels = {
'fl_no': ('Flight Number'),
'park_bay': ('Parking Bay'),
'catering': ('Catering'),
'fuel': ('Fuel'),
'pas_cnt': ('Passenger Count'),
'dest': ('Destination'),
'dep_time': ('Departure Time'),
'Cleaning': ('Cleaning'),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['park_bay'].queryset = Parking.objects.none()
self.fields['dest'].queryset = Destination.objects.none()
self.fields['dep_time'].queryset = DepartureTime.objects.none()
if 'fl_no' in self.data:
try:
flightid = int(self.data.get('fl_no'))
self.fields['park_bay'].queryset = Parking.objects.filter(fl_no=flightid).order_by('park_bay')
self.fields['dest'].queryset = Destination.objects.filter(fl_no=flightid).order_by('dest')
self.fields['dep_time'].queryset = DepartureTime.objects.filter(fl_no=flightid).order_by('dep_time')
except (ValueError, TypeError):
pass
elif self.instance.pk:
self.fields['park_bay'].querysets = self.instance.fl_no.park_bay_set.order_by('park_bay')
self.fields['dest'].querysets = self.instance.fl_no.dest_set.order_by('dest')
self.fields['dep_time'].querysets = self.instance.fl_no.park_bay_set.order_by('dep_time')
so if anyone could help me fix this part:
elif self.instance.pk:
self.fields['park_bay'].querysets = self.instance.fl_no.park_bay_set.order_by('park_bay')
self.fields['dest'].querysets = self.instance.fl_no.dest_set.order_by('dest')
self.fields['dep_time'].querysets = self.instance.fl_no.dep_time_set.order_by('dep_time')
I would really appreciate it
The error says there's no park_bay_set attribute for FlightNum, because you specified related_name='fl4' for your fl_no field inside your Flight model. Also, up to this point you are in a Flight instance, so you need one more relation to reach the park bays. Your status forms.py should be like this:
elif self.instance.pk:
self.fields['park_bay'].querysets = self.instance.fl_no.fl4.park_bay.all().order_by('park_bay')
self.fields['dest'].querysets = self.instance.fl_no.dest_set.order_by('dest')
self.fields['dep_time'].querysets = self.instance.fl_no.fl4.park_bay.all().order_by('dep_time')
Here's a diagram of how your models are currently related, not sure if this is exactly what you want, you might want to take a look and see if a normalization is needed.
I'm working on a django based backend.
I have a Submentor model. This model is going to have a list of names associated with it. So, I made a model called List. they both have a manytoMany relationship. Now, I made another model called names. This has a ManytoMany relationship with List. The list will have many names. Each Submentor will have one List each.
After coding when I try to add a value in The list from admin console I get core.Name.none instead of the name in my Submentors list.
What am I doing wrong?
code of models :-
class Names(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,blank=True,null=True)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class SAccepted_list(models.Model):
saccepted_name = models.ManyToManyField(Names,blank =True, related_name='saccepted_name')
def __str__(self):
return str(self.saccepted_name)
class SPending_list(models.Model):
spending_name = models.ManyToManyField(Names,blank =True, related_name='spending_name')
def __str__(self):
return str(self.spending_name)
class SRejected_list(models.Model):
srejected_name = models.ManyToManyField(Names,blank =True, related_name='srejected_name')
def __str__(self):
return str(self.srejected_name)
class SubMentor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
mentee_pref_count = models.IntegerField(default=3, verbose_name='Preferred mentee count')
rating = GenericRelation(Rating, related_query_name='Submentor')
skills = models.ManyToManyField(Skill, blank=True, related_name='subskills')
courses = models.ManyToManyField(Course, blank=True, related_name='subcourses')
projects = models.ManyToManyField(Project, blank=True, related_name='subprojects')
saccepted_list = models.ManyToManyField(SAccepted_list,blank=True,related_name='saccepted_list')
spending_list = models.ManyToManyField(SPending_list, blank=True,related_name='spending_list')
srejected_list = models.ManyToManyField(SRejected_list, blank=True,related_name='srejected_list')
def __str__(self):
return self.user.get_full_name()
def get_mentee_count(self, *args, **kwargs):
if self.trainees.exists():
return self.trainees.count()
else:
return 0
class Accepted_list(models.Model):
accepted_name = models.ManyToManyField(Names,blank =True, related_name='accepted_name')
# saccepted_name = models.ManyToManyField(Names,blank =True, related_name='saccepted_name')
def __str__(self):
return str(self.accepted_name)
class Pending_list(models.Model):
pending_name = models.ManyToManyField(Names,blank =True, related_name='pending_name')
# spending_name = models.ManyToManyField(Names,blank =True, related_name='spending_name')
def __str__(self):
return str(self.pending_name)
class Rejected_list(models.Model):
rejected_name = models.ManyToManyField(Names,blank =True, related_name='rejected_name')
# srejected_name = models.ManyToManyField(Names,blank =True, related_name='srejected_name')
def __str__(self):
return str(self.rejected_name)
class Mentor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
score = models.FloatField(default=0, blank=True, null=True)
mentee_pref_count = models.IntegerField(default=5, verbose_name='Preferred menteee count')
rating = GenericRelation(Rating, related_query_name='mentor')
skills = models.ManyToManyField(Skill, blank=True, related_name='skills')
accepted_list = models.ManyToManyField(Accepted_list,blank=True,related_name='accepted_list')
pending_list = models.ManyToManyField(Pending_list, blank=True,related_name='pending_list')
rejected_list = models.ManyToManyField(Rejected_list, blank=True,related_name='rejected_list')
def __str__(self):
return self.user.get_full_name()
def get_mentee_count(self, *args, **kwargs):
if self.trainees.exists():
return self.trainees.count()
else:
return 0
picture of me adding names direct through admin console:-
Thank you.
Ok, I solved my problem. It was wrong of me in the first place to use m2m and then another to make a list.
Instead I used only 1 m2m relationship with Lists and then made a property of them to be charfield. Now it's working properly.
Thanks :)
I'm pretty new to Django and I'm unsure of whether I'm going in the right direction with this.
What I'm trying to do is, when the user is creating a Character in the Admin menu, if the user chooses faction Alliance, to bring up the Alliance_Races, and if not, the Horde_Races.
models.py
Factions = (
('Choose', 'Choose...'),
('Alliance','Alliance'),
('Horde', 'Horde'),
)
Alliance_Races = (
('Human','Human'),
('Dwarf', 'Dwarf'),
('Night Elf', 'Night Elf'),
('Gnome', 'Gnome'),
('Draenei', 'Draenei'),
('Worgen', 'Worgen'),
('Pandaren', 'Pandaren'),
)
Horde_Races = (
('Orc','Orc'),
('Undead', 'Undead'),
('Tauren', 'Tauren'),
('Troll', 'Troll'),
('Blood Elf', 'Blood Elf'),
('Goblin', 'Goblin'),
('Pandaren', 'Pandaren'),
)
class Character(models.Model):
character_name = models.CharField(max_length=100, default="")
faction = models.CharField(max_length=8, choices=Factions, default='none')
race = ""
def __str__(self):
return self.character_name
def race_options(self):
if self.allied_with == "Alliance":
self.race = models.CharField(max_length=8, choices=Alliance_Races, default='none')
elif self.allied_with == "Horde":
self.race = models.CharField(max_length=8, choices=Horde_Races, default='none')
I'd appreciate any help. Thanks in advance!
Try using model inheritance:
class Character(models.Model):
character_name = models.CharField(max_length=100, default="")
def __str__(self):
return self.character_name
class Meta:
abstract = True
class AllianceCharacter(Character)
race = models.CharField(choices=Alliance_Races)
class HordeCharacter(Character)
race = models.CharField(choices=Horde_Races)
I am completely new to django and was a php coder previously, so please bear with me if i am being dumb.
I have three models defined in my app, Comprehension, Question, Answer. Each comprehension has multiple questions and answers defined as 'inline' in the Comprehension model. Questions are input directly by the admin, but answers would added automatically from the comprehension.
What I want to achieve is, to split the comprehension in to sentences and add each sentence as an answer object with foreignkey of the current comprehension.
I am trying to override the save method in Comprehension model. But when I click save, it gives an instance error
Cannot assign "23L": "Answer.ComprehensionAnswer" must be a "Comprehension" instance.
How do I assign/create and instance here ? or am I following a wrong approach. If so, kindly guide me to the right approach.
Following are the contents of models.py
class Question(models.Model):
QuestionText = models.CharField(max_length=500, verbose_name='Question Text')
QuestionTypeID = models.ManyToManyField(QuestionType, verbose_name='Question Type')
ComprehensionQuestion = models.ForeignKey(Comprehension, verbose_name='comprehension')
QuestionRemarks = models.CharField(max_length=500, verbose_name='remarks', null=True, blank=True)
LastUpdate = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.QuestionText
def was_published_recently(self):
return self.LastUpdate >= timezone.now() - datetime.timedelta(1)
class Answer(models.Model):
AnswerText = models.CharField(max_length=500, verbose_name='Answer Text')
AnswerTypeID = models.ManyToManyField(AnswerType, verbose_name='Answer Type')
ComprehensionAnswer = models.ForeignKey(Comprehension, verbose_name='Comprehension', null=True, blank=True)
AnswerRemarks = models.CharField(max_length=500, verbose_name='Remarks')
LastUpdate = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.AnswerText
class Comprehension(models.Model):
ComprehensionTitle = models.CharField(max_length=100, verbose_name='Comprehension Title')
ComprehensionsText = models.TextField(verbose_name='Text')
ComprehensionsRemarks = models.CharField(max_length=400, verbose_name='Remarks for this Comprehension', null=True, blank=True)
LastUpdate = models.DateTimeField("Last Updated", auto_now=True)
def __unicode__(self):
return self.ComprehensionTitle
def was_published_recently(self):
return self.LastUpdate >= timezone.now() - datetime.timedelta(1)
def save(self, *args, **kwargs):
#overrides the default save function to split the comprehension paragraph into sentences and adds them as probable answers
AnswerList = self.ComprehensionsText.split("u'\u0964'")
for sentence in AnswerList:
p = Answer.objects.create(AnswerText = sentence, ComprehensionAnswer = self.pk)
super(Comprehension, self).save(*args, **kwargs)
Content inside admin.py
class ComprehensionAdmin(admin.ModelAdmin):
form = ComprehensionForm
fieldsets = [
('Main', {'fields': ['ComprehensionTitle','ComprehensionsText']}),
('Additional Info', {'fields': ['ComprehensionsRemarks'], 'classes': ['collapse']}),
]
inlines = [QuestionInline, AnswerInline]
list_display = ('ComprehensionTitle', 'LastUpdate')
list_per_page = 10
class QuestionInline(admin.TabularInline):
model = Question
extra = 2
class AnswerInline(admin.TabularInline):
model = Answer
extra = 2
admin.site.register(Question)
admin.site.register(Answer)
admin.site.register(Comprehension, ComprehensionAdmin)
I have also followed the approach mentioned on this page. But, blank about how to create the objects in commit condition using the foreignkey of Comprehension model.
You should use self instead of self.pk and note that self refers the current object.
p = Answer.objects.create(AnswerText = sentence, ComprehensionAnswer = self)
From the traceback, it clearly shows that, ComprehensionAnswer attribute of Answer model expects Comprehension model's object. But you're passing the id of that object.
I want refactor some of my code in models because it's a little mess. I have couple models.
class Part(models.Model):
class Category(models.Model):
class Labor(models.Model):
And so on, seven in total. I am generating for them ID. For Part it is:
def save(self, *args, **kwargs):
if not Part.objects.count():
latest = 'XXX00000'
else:
latest = Part.objects.all().order_by('-par_id')[0].par_id
self.par_id = "PAR" + str(int(latest[3:]) + 1).zfill(5)
super(Part, self).save(*args, **kwargs)
And it's pretty similar for rest of classes. Only name of class is changing, three letters identification and paramtere in order_by. I was wondering how can I do it DRY. Because it's 7 lines of code on each class that should be somehow shortened.
I was wondering maybe create BaseModel class inherited from it and somehow change only mentioned things. I would like to get some directions how can I do it better.
Edit:
class Part(models.Model):
par_id = models.CharField(primary_key=True, unique=True, max_length=9, blank=False)
par_name = models.CharField(max_length=50)
def save(self, *args, **kwargs):
if not Part.objects.count():
latest = 'XXX00000'
else:
latest = Part.objects.all().order_by('-par_id')[0].par_id
self.par_id = "PAR" + str(int(latest[3:]) + 1).zfill(5)
super(Part, self).save(*args, **kwargs)
class Category(models.Model):
cat_id = models.CharField(primary_key=True, unique=True, max_length=9)
cat_name = models.CharField(max_length=50)
def save(self, *args, **kwargs):
if not Category.objects.count():
latest = 'XXX00000'
else:
latest = Category.objects.all().order_by('-cat_id')[0].cat_id
self.cat_id = "CAT" + str(int(latest[3:]) + 1).zfill(5)
super(Category, self).save(*args, **kwargs)
That are two o my classes.
Inheriting is definitely a good idea.
You're not giving much information about the models. So there are 2 main options for inheriting models:
A) To use an AbstractModel which would hold the common fields and some common methods. And then use child models to extend the fields and methods as you need. Here is an example from the django docs:
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
B) If you're only interested in inheriting or extending the behavioural parts of your models (like the different methods for generating the id's), a proxy model would be a better option. Take a look at the docs: https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models
Here is an example taken from the django docs:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
create class BaseModel(models.Model): and copypaste your save method there, but replace Part with self.__class__ , for example
class BaseModel(models.Model):
# some fields here
class Meta:
abstract = True
def save(self, *args, **kwargs):
first_declared_field = self.__class__._meta.fields[1].name
if self.__class__.objects.count():
latest = getattr(self.__class__.objects.order_by('-' + first_declared_field)[0], first_declared_field)
else:
latest = 'XXX00000'
field_value = first_declared_field.name.split('_')[0].upper() + str(int(latest[3:]) + 1).zfill(5)
setattr(self, first_declared_field, field_value)
super(BaseModel, self).save(*args, **kwargs)
class SomeChildModel(BaseModel):
pass