Is there a way to simplify this working code?
This code gets for an object all the different vote types, there are like 20 possible, and counts each type.
I prefer not to write raw sql but use the orm. It is a little bit more tricky because I use generic foreign key in the model.
def get_object_votes(self, obj):
"""
Get a dictionary mapping vote to votecount
"""
ctype = ContentType.objects.get_for_model(obj)
cursor = connection.cursor()
cursor.execute("""
SELECT v.vote , COUNT(*)
FROM votes v
WHERE %d = v.object_id AND %d = v.content_type_id
GROUP BY 1
ORDER BY 1 """ % ( obj.id, ctype.id )
)
votes = {}
for row in cursor.fetchall():
votes[row[0]] = row[1]
return votes
The models im using
class Vote(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
payload = generic.GenericForeignKey('content_type', 'object_id')
vote = models.IntegerField(choices = possible_votes.items() )
class Issue(models.Model):
title = models.CharField( blank=True, max_length=200)
The code Below did the trick for me!
def get_object_votes(self, obj, all=False):
"""
Get a dictionary mapping vote to votecount
"""
object_id = obj._get_pk_val()
ctype = ContentType.objects.get_for_model(obj)
queryset = self.filter(content_type=ctype, object_id=object_id)
if not all:
queryset = queryset.filter(is_archived=False) # only pick active votes
queryset = queryset.values('vote')
queryset = queryset.annotate(vcount=Count("vote")).order_by()
votes = {}
for count in queryset:
votes[count['vote']] = count['vcount']
return votes
Yes, definitely use the ORM. What you should really be doing is this in your model:
class Obj(models.Model):
#whatever the object has
class Vote(models.Model):
obj = models.ForeignKey(Obj) #this ties a vote to its object
Then to get all of the votes from an object, have these Django calls be in one of your view functions:
obj = Obj.objects.get(id=#the id)
votes = obj.vote_set.all()
From there it's fairly easy to see how to count them (get the length of the list called votes).
I recommend reading about many-to-one relationships from the documentation, it's quite handy.
http://www.djangoproject.com/documentation/models/many_to_one/
Related
The goal of this project is to create an API that refreshes hourly with the most up to date betting odds for a list of games that I'll be scraping hourly from the internet. The goal structure for the JSON returned will be each game as the parent object and the nested children will be the top 1 record for each of linesmakers being scraped by updated date. My understanding is that the best way to accomplish this is to modify the to_representation function within the ListSerializer to return the appropriate queryset.
Because I need the game_id of the parent element to grab the children of the appropriate game, I've attempted to pull the game_id out of the data that gets passed. The issue is that this line looks to be populated correctly when I see what it contains through an exception, but when I let the full code run, I get a list index is out of range exception.
For ex.
class OddsMakerListSerializer(serializers.ListSerializer):
def to_representation(self, data):
game = data.all()[0].game_id
#if I put this here it evaluates to 1 which should run the raw sql below correctly
raise Exception(game)
data = OddsMaker.objects.filter(odds_id__in = RawSQL(''' SELECT o.odds_id
FROM gamesbackend_oddsmaker o
INNER JOIN (
SELECT game_id
, oddsmaker
, max(updated_datetime) as last_updated
FROM gamesbackend_oddsmaker
WHERE game_id = %s
GROUP BY game_id
, oddsmaker
) l on o.game_id = l.game_id
and o.oddsmaker = l.oddsmaker
and o.updated_datetime = l.last_updated
''', [game]))
#if I put this here the data appears to be populated correctly and contain the right data
raise Exception(data)
data = [game for game in data]
return data
Now, if I remove these raise Exceptions, I get the list index is out of range. My initial thought was that there's something else that depends on "data" being returned as a list, so I created the list comprehension snippet, but that doesn't resolve the issue.
So, my question is 1) Is there an easier way to accomplish what I'm going for? I'm not using a postgres backend so distinct on isn't available to me. and 2) If not, its not clear to me what instance is that's being passed in or what is expected to be returned. I've consulted the documentation and it looks as though it expects a dictionary and that might be part of the issue, but again the error message references a list. https://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior
I appreciate any help in understanding what is going on here in advance.
Edit:
The rest of the serializers:
class OddsMakerSerializer(serializers.ModelSerializer):
class Meta:
list_serializer_class = OddsMakerListSerializer
model = OddsMaker
fields = ('odds_id','game_id','oddsmaker','home_ml',
'away_ml','home_spread','home_spread_odds',
'away_spread_odds','total','total_over_odds',
'total_under_odds','updated_datetime')
class GameSerializer(serializers.ModelSerializer):
oddsmaker_set = OddsMakerSerializer(many=True, read_only=True)
class Meta:
model = Game
fields = ('game_id','date','sport', 'home_team',
'away_team','home_score', 'away_score',
'home_win','away_win', 'game_completed',
'oddsmaker_set')
models.py:
class Game(models.Model):
game_id = models.AutoField(primary_key=True)
date = models.DateTimeField(null=True)
sport=models.CharField(max_length=256, null=True)
home_team = models.CharField(max_length=256, null=True)
away_team = models.CharField(max_length=256, null=True)
home_score = models.IntegerField(default=0, null=True)
away_score = models.IntegerField(default=0, null=True)
home_win = models.BooleanField(default=0, null=True)
away_win = models.BooleanField(default=0, null=True)
game_completed = models.BooleanField(default=0, null=True)
class OddsMaker(models.Model):
odds_id = models.AutoField(primary_key=True)
game = models.ForeignKey('Game', on_delete = models.CASCADE)
oddsmaker = models.CharField(max_length=256)
home_ml = models.IntegerField(default=999999)
away_ml = models.IntegerField(default=999999)
home_spread = models.FloatField(default=999)
home_spread_odds = models.IntegerField(default=9999)
away_spread_odds = models.IntegerField(default=9999)
total = models.FloatField(default=999)
total_over_odds = models.IntegerField(default=999)
total_under_odds = models.IntegerField(default=999)
updated_datetime = models.DateTimeField(auto_now=True)
views.py:
class GameView(viewsets.ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameSerializer
Thanks
To answer the question in the title:
The instance being passed to the Serializer.to_representation() is the instance you pass when initializing the serializer
queryset = MyModel.objects.all()
Serializer(queryset, many=True)
instance = MyModel.objects.all().first()
Serializer(data)
Usually you don't have to inherit from ListSerializer per se. You can inherit from BaseSerializer and whenever you pass many=True during initialization, it will automatically 'becomeaListSerializer`. You can see this in action here
To answer your problem
from django.db.models import Max
class OddsMakerListSerializer(serializers.ListSerializer):
def to_representation(self, data): # data passed is a queryset of oddsmaker
# Do your filtering here
latest_date = data.aggregate(
latest_date=Max('updated_datetime')
).get('latest_date').date()
latest_records = data.filter(
updated_date_time__year=latest_date.year,
updated_date_time__month=latest_date.month,
updated_date_time__day=latest_date.day
)
return super().to_representation(latest_records)
I am new to programming, I have a doubt I formed the QuerySet with table data i want to know how to apply condition to the formed queryset and get the count.
Code :
final_set = TaskMaster.objects.filter(istaskactive=True)
I want something like
no_of_rebuild_task = final_set..objects.filter(tasktype.id=1).count
model.py
class TaskMaster(models.Model):
sid = models.CharField(max_length=3)
# Remember to change the default value in processor in production
processor = models.ForeignKey(User,null=True,on_delete=models.CASCADE,default=1)
tasktype = models.ForeignKey(TaskTypeTable, null=True,on_delete=models.CASCADE)
task_title = models.TextField(null=True)
task_description = models.TextField(null=True)
datacenter = models.ForeignKey(DatacenterTable,null=True,on_delete=models.CASCADE)
priority = models.ForeignKey(PriorityTable, null=True,on_delete=models.CASCADE)
status = models.ForeignKey(StatusTable, default=1,on_delete=models.CASCADE)
pid = models.IntegerField(null=True)
sourceincident = models.CharField(max_length=250,null=True)
errorincident = models.CharField(max_length=250,null=True)
processingteam =
models.ForeignKey(TeamTable,null=True,on_delete=models.CASCADE)
createddate = models.DateField(("Date"), default=datetime.date.today)
duedate = models.DateField(("Date"), default=datetime.date.today)
istaskactive = models.BooleanField(default=True)
In Django ORM you can use count() to count the number of records in the selected table.
So for your query it can be
no_of_rebuild_task = TaskMaster.objects.filter(istaskactive=True, tasktype_id=1).count()
See effective way of Django ORM
and count() here.
no_of_rebuild_task = final_set.filter(tasktype__id=1).count()
I'm currently trying to find a way to do something with Django's (v1.10) ORM that I feel should be possible but I'm struggling to understand how to apply the documented methods to solve my problem.
Edit: So here's the sql that I've hacked together to return the data that I'd like from the dbshell, with a postgresql database now, after I realised that my original sqlite3 backed sql query was incorrect:
select
voting_bill.*,vv.vote
from
voting_bill
left join
(select
voting_votes.vote,voting_votes.bill_id
from
voting_bill
left join
voting_votes
on
voting_bill.id=voting_votes.bill_id
where
voting_votes.voter_id = (select id from auth_user where username='richard' or username is Null)
)
as
vv
on
voting_bill.id=vv.bill_id;
Here's the 'models.py' for my voting app:
from django.db import models
from django.contrib.auth.models import User
class Bill(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
result = models.BooleanField()
status = models.BooleanField(default=False)
def __str__(self):
return self.name
class Votes(models.Model):
vote = models.NullBooleanField()
bill = models.ForeignKey(Bill, related_name='bill',
on_delete=models.CASCADE,)
voter = models.ForeignKey(User, on_delete=models.CASCADE,)
def __str__(self):
return '{0} {1}'.format(self.bill, self.voter)
I can see that my sql works as I expect with the vote tacked onto the end, or a null if the user hasn't voted yet.
I was working to have the queryset in this format so that I can iterate over it in the template to produce a table and if the result is null I can instead provide a link which takes the user to another view.
I've read about select_related and prefetch_related, but as I said, I'm struggling to work out how I translate this to how I can do this in SQL.
Hope I correctly understood your problem. Try this:
votes = Votes.objects.filter(voter__username='django').select_related('bill')
You can use this. But I think you do not need select_related in this case.
bills_for_user = Bill.objects.filter(votes__voter__username='django').select_related('votes').distinct()
Now you can iterate your bills_for_user
for bill in bills_for_user:
bill_name = bill.name
bill_description = bill.description
bill_result = bill.result
bill_status = bill.status
# and there are several variants what you can with votes
bill_votes = bill.votes_set.all() # will return you all votes for this bill
bill_first_vote1 = bill.votes_set.first() # will return first element in this query or None if its empty
bill_first_vote2 = bill.votes_set.all()[0] # will return first element in this query or Error if its empty
bill_last_vote = bill.votes_set.last()[0] # will return last element in this query or None if its empty
# you can also filter it for example by voting
bill_positive_votes = bill.votes_set.filter(vote=True) # will return you all votes for this bill with 'vote' = True
bill_negative_votes = bill.votes_set.filter(vote=False) # will return you all votes for this bill with 'vote' = False
bill_neutral_votes = bill.votes_set.filter(vote=None) # will return you all votes for this bill with 'vote' = None
I am trying to use Django's select_related to make query that will walk through two separate models.
The conditional looks like this (note, value is a rename - it's not a syntax thing relating to anything about value):
if valueResults.objects.select_related("value_id__item_id").filter(status_code="yes", item_id=item_id).exists():
return JSONResponse({'message':'Yes', 'status':status.HTTP_200_OK})
elif valueResults.objects.select_related("value_id__item_id").filter(status_code="no", item_id=item_id).exists():
return JSONResponse({'message':'No’, 'status':status.HTTP_200_OK})
else:
return JSONResponse({'message':'There are no items matching that item_id', 'status': status.HTTP_404_NOT_FOUND})
And the data model looks like this:
class valueResults(models.Model):
value_id = models.ForeignKey(value)
result_date = EncryptedDateTimeField()
status_code = EncryptedCharField(max_length=25)
value = EncryptedIntegerField()
test_started = EncryptedDateTimeField()
class value(models.Model):
value_id = EncryptedCharField(primary_key=True, unique=True, max_length=100)
valuetype_id = models.ForeignKey(valueType)
dateitemord = EncryptedDateTimeField()
status = EncryptedCharField(max_length=100)
item_id = models.ForeignKey(Items)
user_id = models.ForeignKey(User)
class Items(models.Model):
item_id = models.CharField(primary_key=True,max_length=100)
mailed_date = EncryptedDateTimeField()
received_date = EncryptedDateTimeField()
last_viewed = EncryptedDateTimeField()
dateitemsent = EncryptedDateTimeField()
itemidvalue = EncryptedCharField(max_length=100)
itemsent = EncryptedCharField(max_length=25)
itemret = EncryptedCharField(max_length=25)
dateitemret = EncryptedDateTimeField()
status = EncryptedCharField(max_length=25)
My ideal goal would be to filter based on the status_code of the valueResults model, and the item_id of the Items. Is this possible?
select_related is a performance tuning tool, and not one that has anything to do with existence tests. It doesn't change what kinds of queries are possible. Filtering on foreign key relationships is possible using __ notation - see the docs for examples. EG, chaining from your valueResults model through value to Items:
if valueResults.objects.filter(value_id__item_id__status="yes", value_id__item_id__item_id=item_id).exists():
# do something
Hello Guy I'm a newbie to Django. Im using Rest API with Django to interact with my android application. I have the data I need in variable quest. Since there are multiple questions I'm using filter instead of get.
This is my Views.py:
class MapertablesViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Mapertables.objects.all()
serializer_class = MapertablesSerializer
lookup_field = 'category_id'
def get_queryset(self):
#print self.kwargs['category_id']
maps = Mapertables.objects.filter(category_id=self.kwargs['category_id'])
#queryset = list(maps)
#queryset = serializers.serialize('json',maps)
#print "AAAA ",queryset
i = 0
#quest ={}
queryset = []
queslist = []
for question in maps:
quest = {}
quest['question'] = question.question_id
#print 'qqqq ',question.question_id
#queryset = serializers.serialize('json',[question,])
choices = Choice.objects.filter(question=question.question_id)
print choices
#aaa = chain(question,choices)
#print aaa
#queryset = serializers.serialize('json',[question,choices,])
j = 0
for option in choices:
quest[j] = option.choice_text
j += 1
print 'data Here ',quest
#data Here {0: u'Highbury', 1: u'Selhurst Park', 2: u'The Dell', 3: u'Old Trafford', 'question': <Question: At which ground did Eric Cantona commit his "Kung Fu" kick ?>}
serializer_class = CoustomeSerializer(queryset, many=True)
print serializer_class.data
#[]
json = JSONRenderer().render(serializer_class.data)
print 'JSON',json
#[]
i += 1
queryset = queslist
serializer_class = CoustomeSerializer(queryset,many=True)
return queryset
#print "questions",queslist
#print "Ser ",ser.data
This is my serializers.py:
class MapertablesSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Mapertables
fields = ('question_id','category_id')
class CoustomeSerializer(serializers.HyperlinkedModelSerializer):
#questions = MapertablesSerializer(source='question_id')
#choices = ChoiceSerializer(source='choice_text')
class Meta:
model = Question,Choice,Category
fields = ('choice_text','choice_text','choice_text','choice_text','question_id')
URL that is defined to show:
http://127.0.0.1:8000/mapers/
Exception Type: KeyError
Exception Value: 'category_id'
when I query for a specific category it returns:
http://127.0.0.1:8000/mapers/2/
{
"detail": "Not found."
}
Model.py file is as follows:
from django.db import models
# Create your models here.
class Category(models.Model):
category_name = models.CharField(max_length=200,default='1')
def __str__(self):
return self.category_name
class Question(models.Model):
question_text = models.CharField(max_length=200)
#category_name = models.ForeignKey(Category)
pub_date = models.DateTimeField('date published')
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
def __str__(self):
return self.question_text
class Mapertables(models.Model):
category_id = models.ForeignKey(Category)
question_id = models.ForeignKey(Question)
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
I want to get all questions related to category and there choices form the choices module that why all the stuff in get_queryset.
Please tell me how to get all the data required for me in MapertablesViewSet class
Thank You in advance if you want me to send the complete project just let me know and I will make zip and upload it to a drive or something.
#Kevin Brown is right you shouldn't worry about the serializers, or rendering anything on the get_queryset method, but a thing I noticed in your get_queryset method is that you don't append any item to the lists queryset, and querylist. I'm giving you an idea below:
def get_queryset(self):
#print self.kwargs['category_id']
maps = Mapertables.objects.filter(category_id=self.kwargs['category_id'])
i = 0
queryset = []
for question in maps:
quest = {}
quest['question'] = question.question_id
choices = Choice.objects.filter(question=question.question_id)
print choices
j = 0
for option in choices:
quest[j] = option.choice_text
j += 1
print 'data Here ',quest
# Adding items to queryset list
queryset.append(quest)
i += 1
# You should have values here on queryset list
print queryset
return queryset
As to the URL, be sure you are passing the category_id as a parameter on the URL pattern. Something like url(r'^mapers/(?P<category_id>\d+)/?', if you are not using routers for this. It would be good if you paste here your URLs definition. Well, I hope it helps you to have a better idea how to continue.
You are returning an empty list from your get_queryset method, so no objects are being returned in the list view and a specific object cannot be retrieved by the pk.
You appear to be doing a lot of unrelated things in your get_queryset method, and they are probably contributing to this issue. You shouldn't be doing any serialization there, DRF will handle that for you later. And you should be doing filtering in the filter_queryset method, or passing that off to DRF to do. You also can't return any responses from that method, only a queryset.