Modeling django model statistics - django

I'm working on a questionnaire model for django that should be maintainable by someone with no programming experience, so I've spent a lot of time crafting my models to compensate for minor details.. Now I want to unlock the potential of SQL database queries to be able to generate statistics about the responses and feedback given.
One of my question types is a 5 star rating, so I would like to be able to gather statistics about the question like:
How many responses for question q were 5 star (, 4star, 3star, etc.)?
What was the average rating response?
Ideally I would like to record these statistic questions in a model, and create a view that shows all the statistics asked and keep the entire thing programmatic.
Should this be a carefully crafted model or set of models like feedback, or is there already some framework or module that handles these situations for me?
My questionnaire/models.py:
class QuestionType(models.Model):
name = models.CharField(max_length=256, blank=True, default="")
class Question(models.Model):
text = models.TextField()
type = models.ForeignKey(QuestionType)
class Response(models.Model):
question = models.ForeignKey(Question)
answer = models.TextField()
class Feedback(models.Model):
user = models.ForeignKey(User)
responses = models.ManyToManyField(Response)
response_time = models.DateTimeField(auto_now_add=True)

This would cover your requirements:
class QuestionType(models.Model):
name = models.CharField(max_length=256, blank=True, default="")
class Question(models.Model):
text = models.TextField()
type = models.ForeignKey(QuestionType)
def how_many_ratings_where_x_stars(self, stars):
return self.rating_set.filter(stars=stars).count()
def average_rating(self, stars):
return self.rating_set.aggregate(models.Avg('stars'))['stars__avg']
class Response(models.Model):
question = models.ForeignKey(Question)
answer = models.TextField()
user = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now_add=True)
class Rating(models.Model):
question = models.ForeignKey(Question)
stars = models.PositiveIntegerField(min_value=1, max_value=5)
user = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = [('question', 'user')]

Related

Many foreign keys in a model, better way to do models?

I'm kind of new to django. While writing the models for an app I'm doing, I felt like I was doing something wrong because of all the foreign keys I was using for a single model (ticket model to be specific)
My thinking at the beginning was that I wanted each Ticket to keep the information on it's creator, what team this ticket is assigned to and the comments made on the ticket. And other information that don't need foreign keys. Am I doing this right ? I dont know why, but I feel like there is a better way.
class Team(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=2000)
members = models.ManyToManyField(User, through='Team_members')
def __str__(self):
return self.name
class Ticket(models.Model):
name = models.CharField(max_length=200)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
comments = models.ForeignKey(Comment, on_delete=models.CASCADE)
#worker = models.ForeignKey(User, on_delete=models.CASCADE) *to be finished
description = models.CharField(max_length=500)
status = models.BooleanField(default=False)
date_opened = models.DateTimeField('date opened')
date_closed = models.DateTimeField('date closed',null=True, blank=True)
def __str__(self):
return self.name
class Team_member:
team = models.ForeignKey(Team)
user = models.ForeignKey(User)
date = models.DateTimeField('date joined')
class Comment:
text = models.CharField(max_length=2000)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.text
Your question actually has very little (like, nothing?) to do with Django.
Please read about database normalization, it should answer your questions.
Regarding your models, I could notice the following:
Your models look quite good. Don't be afraid of foreign keys, they are the main reason you use a relational database :)
I assume, User might be a member of a Team (service?) or somebody who opens a ticket. If so: when you will have worker foreign key, you most likely won't need team in the Ticket model. It will be redundant, as worker would have a relation to Team.
Nitpicking: Team_member is not pythonic, a PEP8 compliant version would be TeamMember

Creating a variable field in model Django

I want to ask the user how many questions they want to ask; based on their response, I want to populate a model with those many fields. The way I am currently thinking about doing that is as follows:
from __future__ import unicode_literals
from django.db import models
class Interview(models.Model):
title = models.TextField()
description = models.TextField()
number_questions = models.IntegerField()
question_one = models.ForeignKey('Question', related_name='question_one')
question_two = models.ForeignKey('Question', related_name='question_two')
question_three = models.ForeignKey('Question', related_name='question_three')
question_four = models.ForeignKey('Question', related_name='question_four')
question_five = models.ForeignKey('Question', related_name='question_five')
class Question(models.Model):
question_description = models.TextField()
prep_time = models.IntegerField()
response_time = models.IntegerField()
I realize that this solution is inefficient because a) the user is limited to a preset number of questions and b) if the user specifies less than 5 questions, there are unnecessary question entries created. What is a better way to go about storing multiple questions?
Do the foreign key relation the other way round. That's how you model a many-to-one relation:
class Interview(models.Model):
title = models.TextField()
description = models.TextField()
#property
def number_questions(self):
return self.questions.count()
class Question(models.Model):
interview = models.ForeignKey(Interview, related_name='questions')
question_description = models.TextField()
prep_time = models.IntegerField()
response_time = models.IntegerField()
Now you can access an interview's question via:
interview.questions.all()
An Interview can now have any number of Questions.
Btw, the related_name of all the ForeignKeys in your original Interview model should have been 'interview' to make any semantic sense.

Excluding objects from Django queryset based on recency

I have a reddit-like Django app where users can post interesting urls (links) and then publicly comment under them. The two data models to represent this are:
class Link(models.Model):
description = models.TextField(validators=[MaxLengthValidator(500)])
submitter = models.ForeignKey(User)
submitted_on = models.DateTimeField(auto_now_add=True)
class Publicreply(models.Model):
submitted_by = models.ForeignKey(User)
answer_to = models.ForeignKey(Link)
submitted_on = models.DateTimeField(auto_now_add=True)
description = models.TextField(validators=[MaxLengthValidator(250)])
How do I query for all Links which have at least 1 or more publicreply, and secondly where the latest publicreply is not by self.request.user? I sense something like the following:
Link.objects.filter(publicreply__isnull=False).exclude(**something here**)
Please advise! Performance is key too, hence the simpler the better!
For performance and simplicity you could cache both the number of replies and the latest reply:
class Link(models.Model):
...
number_of_replies = models.PositiveIntegerField(default=0)
latest_reply = models.ForeignKey('myapp.Publicreply', related_name='+', blank=True, null=True, on_delete=models.SET_NULL)
When a reply is entered, update the corresponding link.number_of_replies and link.latest_reply.
The query would then be:
Link.objects.filter(number_of_replies__gte=1)\
.exclude(latest_reply__user=request.user)

Tag system for Django

I am building a Quiz app where a user (Content Creator or Author) can create quizzes (choice based questions and their solutions) from a specific domain. These quiz can be attempted by other users (Consumers - not yet implemented).
To allow quiz consumers to be able to search questions based on specific domains of their interest (and to add granularity to the quiz content), I am implementing a tagging system attached to the questions.
Here are my models:
class question(models.Model):
ques_id = models.AutoField(primary_key=True)
ques_text = models.TextField(max_length=1024, blank=False)
ques_author = models.ForeignKey('author')
ques_created = models.DateField(auto_now_add=True)
ques_dscore = models.IntegerField()
ques_bloom = models.CharField(max_length=3)
ques_subject = models.CharField(max_length=3)
ques_type = models.CharField(max_length=1)
ques_flags = models.CharField(max_length=16)
ques_quiz = models.ManyToManyField('quiz')
def __unicode__(self):
return self.ques_text
class choice(models.Model):
choice_id = models.AutoField(primary_key=True)
choice_text = models.CharField(max_length=256, blank=False)
choice_ques = models.ForeignKey('question')
choice_ans = models.BooleanField(default=False)
choice_tags = models.CharField(max_length=32)
def __unicode__(self):
return self.choice_text
class answer(models.Model):
answer_id = models.AutoField(primary_key=True)
answer_text = models.TextField(max_length=1024)
answer_ques = models.ForeignKey('question')
answer_choice = models.ForeignKey('choice')
answer_tags = models.CharField(max_length=128)
class author(models.Model):
user = models.OneToOneField(User)
domain = models.CharField(max_length=16)
def __unicode__(self):
return self.user.username
# a table for storing all the tags
class tags(models.Model):
tags_id = models.AutoField(primary_key=True)
tags_text = models.CharField(max_length=16)
def __unicode__(self):
return self.tags_text
# table that connects tags with question attached to the tag
# from all the research on the web, it can be infered that
# 3NF tagging (Toxi Solution) is the best way to go
# good for inserts but slow on selects
class tagcon(models.Model):
tagcon_id = models.AutoField(primary_key=True)
tagcon_tags = models.ForeignKey('tags')
tagcon_ques = models.ForeignKey('question')
I have currently applied the 3NF tagging Toxi solution. The issue is that a denormalized system would help in faster selects and a 3NF would be faster inserts but slow searches.
I am confused if I should use ManyToMany field type for tags. Could someone enlighten if it would be better to use a ManyToMany field inbuilt in Django or implement the 3NF system as done?
This is already exactly the same as a ManyToManyField. The only difference is that adding the field would give you an explicit accessor from question to tag.
(Note, your models are very odd. There is absolutely no benefit in prefixing every field name with an abbreviated version of the model name; you can only ever access the field via the model anyway, so you would always be doing question.ques_text, which is redundant. And you shouldn't be defining your own PK fields unless you have a very good reason.)
In my opinion I suggest you try these 2 projects
django-tagging.
django-taggit.

Working with multiple forms on a single page in Django

I'm new to Django and I'm having a hard time wrapping my head around how to deal with "nested" forms in a template and how to process those forms accordingly. I'm creating a polling application similar to the tutorial, but more complex. I have multiple models (Poll, Question, Choice, Vote). A poll contains many questions, a question contains many choices.
I want to allow a user to view all the questions in a poll at once and vote on each question by selecting a choice from each question's choice set. After the user selects a choice for each question, they submit all their votes at once and process them to create the vote objects.
I'm really scratching my head at how to do this. Any help would be greatly appreciated.
Here are how my models are set up:
models.py
class Poll(models.Model):
name = models.CharField(max_length=255, default="Unnamed Poll")
key = models.CharField(max_length=16, blank=True, editable=False, unique=True, db_index=True, null=True)
instructor = models.ForeignKey(User)
course = models.ForeignKey(Course)
active = models.BooleanField(default=False)
anonymous = models.BooleanField(default=True, help_text="Allow votes to be anonymous?")
class Question(models.Model):
question_text = models.CharField(max_length=255, verbose_name='Poll Question')
poll = models.ForeignKey(Poll)
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=255, verbose_name='Response Choice')
class Vote(models.Model):
question = models.ForeignKey(Question)
choice = models.ForeignKey(Choice)
student = models.ForeignKey(User)
You should use django.forms.Formsets in your case.Read about formsets here
Please comment to ask for further clarifications.
cheers :-)