How to define rating sheet model for an interview? - django

Pardon the bad drawing.
Notations:
I - Interview
R1,R2,R3,R4 - Rounds
RT - Rating Sheet
A0, A1, A2, A4 - Aspect(Text Fields) under Rating sheet.
Models:
class Interview(models.Model):
date = ............
class Round(models.Model):
interview = models.ForeignKey(Interview)
class RatingSheet(models.Model):
name = ............
class Aspects(models.Model):
sheet= models.ForeignKey(RatingSheet)
I need a rating sheet to be filled for each interview. That sheet will hold ratings (1-10) for each aspect for each Round.
What have I tried:
I have thought of creating a form dynamically for an Interview with N rounds and accept ratings as drop down .
And I collect all via request.POST. And create a dictionary like:
rating_interview_1 = {'interview_pk':
{
'Round1': {'ASP1': 5, 'ASP2':10},
'Round2': {'ASP1': 5, 'ASP2':10},
'Round3': {'ASP1': 5, 'ASP2':9},
}
}
And then save it to database somehow. I think this can be difficult to edit or maintain. Can I get some suggestions on the correct way to design this ?

I solved it myself. Took 2 weeks of thinking. This is too complex to answer.
But one thing I learned is...there is always a way to organise you models to store data . Other wise retrieval of the same will be a real pain in the future.
Solution:
We need more models .
class InterviewRatingSheet(models.Model):
name = models.CharField(max_length=200, default='MySheet')
interview = models.ForeignKey(Interview, null=True)
round_name = models.OneToOneField(Round, null=True)
def __str__(self): # __unicode__ on Python 2
return self.name
class RatingAspect(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(null=True, default='', blank=True)
interview_rating_sheet = models.ForeignKey(InterviewRatingSheet)
points = models.PositiveIntegerField(default=0)
def __str__(self): # __unicode__ on Python 2
return self.name
So for a "Round", there will be only one "InterviewRatingSheet" and each sheet will have "RatingAspect"s same as "Aspects".
You can see the whole code in this link:
https://github.com/arindam31/django-interview-manager

Related

How to calculate and store scores in django betting game?

I'm working on my first django project which is a sport betting game.
My models are:
class Game(models.Model):
home_team = models.CharField(max_length=200)
away_team = models.CharField(max_length=200)
home_goals = models.IntegerField(default=None)
away_goals = models.IntegerField(default=None)
class Bet(models.Model):
gameid = models.ForeignKey(Game, on_delete=models.CASCADE)
userid = models.ForeignKey(User, on_delete=models.CASCADE)
home_goals = models.IntegerField()
away_goals = models.IntegerField()
score = models.IntegerField(default=None, null=True)
logic for calculating scores is:
WHEN polls_bet.home_goals = polls_game.home_goals AND polls_bet.away_goals = polls_game.away_goals THEN 2
WHEN polls_game.home_goals > polls_game.away_goals AND polls_game.home_goals > polls_game.away_goals THEN 1
WHEN polls_bet.home_goals < polls_bet.away_goals AND polls_game.home_goals < polls_game.away_goals THEN 1
ELSE 0
I was able to solve it easily using database view that combines all data in one table but it seems that it does not play well with django migrations..
So I was thinking about sql trigger after update of game goals, but then I don't know how to pass conditions like user's id.
2nd idea is to create additional 'scores' table with:
gameid,
userid,
betid,
score
But then again I don't know how to calculate scores.
Please advice how this should be done properly, without using sql view. I appreciate all answers!
You can define a 'score' property on the Bet model to solve this easily. Please refer to the documentation here.
Your property implementation will be something like:
#property
def score(self):
if (self.home_goals == self.game__home_goals and
self.away_goals == self.game__away_goals):
return 2
if (self.game__home_goals > self.game__away_goals):
return 1
if (self.home_goals < self.away_goals and
self.game__home_goals < self.home_goals):
return 1
return 0
On a side note, the normal naming convension for a foreignkey relation is the model name in lowercase. So it becomes 'game' and 'user' instead of 'gameid' and 'userid'. Also I believe you have some typos on the second condition.

How to get simple ForeignKey model working? (a list of class in another class)

I tried to figure this out on my own :( couldn't quite get there. Pls take pity. . .
I'm trying to represent exercise data (a start time an end time and many--an undetermined number of-- heart rates)
this is the model I have set up:
class HeartRate(models.Model):
timestamp = models.DateTimeField('Date and time recorded')
heartrate = models.PositiveIntegerField(default=0)
def __str__(self):
return prettyDate(self.timestamp)
class Exercise(models.Model):
start_timestamp = models.DateTimeField('Starting time')
finishing_timestamp = models.DateTimeField('Finishing time')
heartrate = models.ForeignKey(HeartRate)
I know from working with the admin that it seems only one HeartRate is selected for each Exercise so maybe my approach is all wrong. How do I correctly model this? And once modeled correctly how do I query all heart rates for each (all) Exercises. I know this is a noob move but I really tried for hours getting this to work and can't quite get a handle on the documentation. Thanks in advance.
You should reverse the foreign key relationship:
class HeartRate(models.Model):
timestamp = models.DateTimeField('Date and time recorded')
heartrate = models.PositiveIntegerField(default=0)
exercise = models.ForeignKey(Exercise, related_name='heartrates')
class Exercise(models.Model):
start_timestamp = models.DateTimeField('Starting time')
finishing_timestamp = models.DateTimeField('Finishing time')
To get all of the heartrates of an exercise:
heartrates = my_exercise.heartrates.all()

How to get number of items grouped by a property of an intermediate model

I would like to have something like this
Adventure (4) | Sci-fi (12)
which are the books, in a bookshop, linked by a local price.
Say, Hobbit is $5 at Amazon and $6 at Barnes. So if I was listing the books in Amazon I will have Adventure (1) as the count of the books with a specified price in amazon.
If I do like this I get the correct Genres:
for u in Bookshop.objects.get(pk=1).BookBookshopLink_set.all():
print u.book.genre
which would print, e.g.:
Sci-fi
Sci-fi
Adventure
Here are the models:
from parler.models import TranslatableModel, TranslatedFields
from parler.managers import TranslationManager
class Genre(TranslatableModel):
translations = TranslatedFields(
name=models.CharField(max_length=200),
slug=models.SlugField(),
description=models.TextField(blank=True),
meta={'unique_together': [('language_code', 'slug')]},
)
published = models.BooleanField(default=False)
class Book(TranslatableModel):
translations = TranslatedFields(
name=models.CharField(max_length=200),
slug=models.SlugField(),
description=models.TextField(blank=True),
meta={'unique_together': [('language_code', 'slug')]},
)
genre = models.ForeignKey(Genre, blank=True, null=True)
published = models.BooleanField(default=False)
class Bookshop(TranslatableModel):
translations = TranslatedFields(
name=models.CharField(max_length=200),
description=models.TextField(_('Description'), default='', blank=True),
slug=models.SlugField(),
meta={'unique_together': [('slug', 'language_code')]},
)
booklist = models.ManyToManyField(Book, blank=True, through='BookBookshopLink')
class BookBookshopLink(TranslatableModel):
bookshop = models.ForeignKey(Bookshop)
book = models.ForeignKey(Book)
price = models.IntegerField(blank=True, null=True)
To do what you're trying to achieve in one query, you need to use Count, annotate and values_list
I'll show you a code example and then I'll try to explain it:
from django.db.models import Count
from your_project.models import *
Genre.objects.all().values_list('name').annotate(num_books=Count('book'))
.values_list('name'): This return a list of all genres by name
.annotate(num_books=Count('book')): This count books for each Genre
I have a similar models structure in my projects and when I execute that code, I get this as answer:
[(u'GENRE_NAME', 13), (u'GENRE_NAME', 14), (u'GENRE_NAME', 0),...]
You can parse the output of this query to fit your expectations
I also recomend you to check oficial documentation Django Agreggation
This loops over all your genres and prints out how many of them there are.
Even if there are 0 in a genre.
for a_genre in Gendre.objects.all():
print Book.objects.filter(genre=a_genre).count()
and if you want it printed with the genre aswel
for a_genre in Gendre.objects.all():
print "%s (%d)" % (a_genre, Book.objects.filter(genre=a_genre).count())
Documentation for filters in django : https://docs.djangoproject.com/en/1.7/topics/db/queries/#retrieving-specific-objects-with-filters

How do I count number of occurences in Django?

Here are models in my project:
class Tournament(models.Model):
title = models.CharField(max_length=150)
start_date = models.DateTimeField(verbose_name="Start date")
end_date = models.DateTimeField(verbose_name="End date")
participants = models.ManyToManyField(Participant)
def __unicode__(self):
return u"%s" % self.title
class Game(models.Model):
tournament = models.ForeignKey(Tournament)
number_of_tour = models.PositiveSmallIntegerField()
opponent_white = models.ForeignKey(Participant, related_name='opponent_white', blank=True)
opponent_black = models.ForeignKey(Participant, related_name='opponent_black', blank=True)
winner = models.CharField(max_length=150, choices=(('White', 'White'), ('Black', 'Black'), ('Draw', 'Draw')), blank=True)
elo_gained_white = models.FloatField(default=0)
elo_gained_black = models.FloatField(default=0)
My problem is that i want to know number of tours in each tournament. I'm trying to do it like this:
num_of_tours = Game.objects.filter(tournament=tournament_id).annotate(Count('number_of_tour', distinct=True)).count()
But this still returns number of Game objects related to a tournament with tournament_id. Could you show me the way to do it right?
Thanks.
I think I have the solution:
What he is looking for is the distinct count of number_of_tours per tournament.
Each game has a tour value, but those values can be double. so number_of_tours work like some kind of id.
Nervosa you can get the distinct value like so:
num_of_tours = Game.objects.filter(tournament=tournament_id).values('number_of_tour').distinct().count()
This should give you just that: the distinct number_of_tours per tournament
So you want to Sum the number_of_tour column for all games in a specific tournament? I think you may need aggregate instead of annotate and Sum instead of Count:
num_of_tours = Game.objects.filter(tournament=tournament_id).aggregate(total_num=Sum('number_of_tour', distinct=True))['total_num']
EDIT: Daniel Roseman pointed out that number_of_tour is probably an index. That makes much more sense. My bad. You will need to do a distinct on the whole query, then count that query. Like this:
num_of_tours = Game.objects.filter(tournament=tournament_id).distinct('number_of_tour').count()
That should count the number of Game objects that have a different number_of_tour. I believe that is what you want. Sorry for the confusion.

Sorting products after dateinterval and weight

What I want is to be able to get this weeks/this months/this years etc. hotest products. So I have a model named ProductStatistics that will log each hit and each purchase on a day-to-day basis. This is the models I have got to work with:
class Product(models.Model):
name = models.CharField(_("Name"), max_length=200)
slug = models.SlugField()
description = models.TextField(_("Description"))
picture = models.ImageField(upload_to=product_upload_path, blank=True)
category = models.ForeignKey(ProductCategory)
prices = models.ManyToManyField(Store, through='Pricing')
objects = ProductManager()
class Meta:
ordering = ('name', )
def __unicode__(self):
return self.name
class ProductStatistic(models.Model):
# There is only 1 `date` each day. `date` is
# set by datetime.today().date()
date = models.DateTimeField(default=datetime.now)
hits = models.PositiveIntegerField(default=0)
purchases = models.PositiveIntegerField(default=0)
product = models.ForeignKey(Product)
class Meta:
ordering = ('product', 'date', 'purchases', 'hits', )
def __unicode__(self):
return u'%s: %s - %s hits, %s purchases' % (self.product.name, str(self.date).split(' ')[0], self.hits, self.purchases)
How would you go about sorting the Products after say (hits+(purchases*2)) the latest week?
This structure isn't set in stone either, so if you would structure the models in any other way, please tell!
first idea:
in the view you could query for today's ProductStatistic, than loop over the the queryset and add a variable ranking to every object and add that object to a list. Then just sort after ranking and pass the list to ur template.
second idea:
create a filed ranking (hidden for admin) and write the solution of ur formula each time the object is saved to the database by using a pre_save-signal. Now you can do ProductStatistic.objects.filter(date=today()).order_by('ranking')
Both ideas have pros&cons, but I like second idea more
edit as response to the comment
Use Idea 2
Write a view, where you filter like this: ProductStatistic.objects.filter(product= aProductObject, date__gte=startdate, date__lte=enddate)
loop over the queryset and do somthing like aProductObject.ranking+= qs_obj.ranking
pass a sorted list of the queryset to the template
Basically a combination of both ideas
edit to your own answer
Your solution isn't far away from what I suggested — but in sql-space.
But another solution:
Make a Hit-Model:
class Hit(models.Model):
date = models.DateTimeFiles(auto_now=True)
product = models.ForeignKey(Product)
purchased= models.BooleanField(default=False)
session = models.CharField(max_length=40)
in your view for displaying a product you check, if there is a Hit-object with the session, and object. if not, you save it
Hit(product=product,
date=datetime.datetime.now(),
session=request.session.session_key).save()
in your purchase view you get the Hit-object and set purchased=True
Now in your templates/DB-Tools you can do real statistics.
Of course it can generate a lot of DB-Objects over the time, so you should think about a good deletion-strategy (like sum the data after 3 month into another model MonthlyHitArchive)
If you think, that displaying this statistics would generate to much DB-Traffic, you should consider using some caching.
I solved this the way I didn't want to solve it. I added week_rank, month_rank and overall_rank to Product and then I just added the following to my ProductStatistic model.
def calculate_rank(self, days_ago=7, overall=False):
if overall:
return self._default_manager.all().extra(
select = {'rank': 'SUM(hits + (clicks * 2))'}
).values()[0]['rank']
else:
return self._default_manager.filter(
date__gte = datetime.today()-timedelta(days_ago),
date__lte = datetime.today()
).extra(
select = {'rank': 'SUM(hits + (clicks * 2))'}
).values()[0]['rank']
def save(self, *args, **kwargs):
super(ProductStatistic, self).save(*args, **kwargs)
t = Product.objects.get(pk=self.product.id)
t.week_rank = self.calculate_rank()
t.month_rank = self.calculate_rank(30)
t.overall_rank = self.calculate_rank(overall=True)
t.save()
I'll leave it unsolved if there is a better solution.