How can I make raw sql ManyToMany and Annotation in django? - sql

class Post(models.Model):
user = models.ForeignKey(FBUser, related_name='posts')
group = models.ForeignKey(Group, related_name='posts')
class Comment(models.Model):
user = models.ForeignKey(FBUser, related_name='comments')
post = models.ForeignKey(Post, related_name='comments')
group = models.ForeignKey(Group, related_name='comments')
class Group(models.Model):
name = models.CharField(max_length=100)
I made this code, but this code is really slow to get result over 10 seconds.
_group.user_set.filter(posts__group=_group, comments__group=_group) \
.annotate(p_count=Count('posts', distinct=True), c_count=Count('comments', distinct=True))
How can I make this code to raw sql?

Related

Understanding Full Join in Django

I have two models in my app:
# Create your models here.
class Melody(models.Model):
notes = models.JSONField()
bpm = models.IntegerField()
aimodel = models.CharField(max_length=200)
score = models.IntegerField(default=0)
person = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="melodies")
date_created = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.id)
class Vote(models.Model):
user_score = models.IntegerField(validators=[MaxValueValidator(1), MinValueValidator(-1)])
melody = models.ForeignKey(Melody, on_delete=models.CASCADE, related_name="scores")
person = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="voters")
def __str__(self):
return f"{self.person} - {self.melody} - {self.score}"
And I get the melodies of the current user by
# Get melodies of current user
melodies = Melody.objects.all().filter(person=person).order_by('-score')[start:end+1].values()
I would like to add to this results the vote of the user to each melody, if there is one, otherwise just null so I can loop over the melodies and retrieve the values:
melody.notes = ...
melody.bpm = ...
melody.user_score = This is the values I do not know still how to get, Null if user has not voted
I was reading about select_related but when I use it it always says
"Invalid field name(s) given in select_related: 'xxxx'. Choices are: (none)"
What am I missing?
EDIT
I solved it based on the answer of #Fnechz by making two queries and then looping over the elements so I can add the user_score to the melody:
# Get melodies of current user
melodies = Melody.objects.all().filter(person=person).order_by('-score')[start:end+1].values()
# Get votes of the user
votes = Vote.objects.all().filter(person=person)
for i, m_melody in enumerate(melodies):
for m_vote in votes:
if (m_vote.melody.id == m_melody['id']):
melodies[i]['user_score'] = m_vote.user_score
return JsonResponse({"melodies": list(melodies)})
Not sure if this is the best way to achieved it
I do not know if there is a direct method to accomplish what you want with a single query. But I guess concatenating the queryset results might work.
from itertools import chain
melodies = Melody.objects.all().filter(person=person).order_by('-score')[start:end+1].values()
votes = #query your vote model here to get the user_score
result_list = list(chain(melodies,votes))
If I have understood your question that might work

Django - id null - foreign key error

Error:
app_a.desc_id may not be NULL
I believe my problem is I'm not passing the id from formB to formA when I save. please please lead me to a solution for this problem.
Here's my view:
def form(request):
if request.method == 'GET':
formB = BForm()
formA = AForm()
return render(request,r'app/form.html',{'formA':formA,'formB':formB})
elif request.method == 'POST':
formA = AForm(request.POST)
formB = BForm(request.POST)
formB.save()
formA.save()
return HttpResponseRedirect('/log')
Here are my models:
# Descprition
class B(models.Model):
id = models.AutoField(primary_key=True)
description = models.CharField(max_length=50)
# Title
class A(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField('Name',max_length=20)
desc = models.ForeignKey(B)
and here is my form:
class BForm(forms.ModelForm):
class Meta:
model = B
fields = ['description']
class AForm(forms.ModelForm):
class Meta:
model = A
fields = ['name']
Your program has multiple errors but the main problem for this is because desc is a foreign key in class A that points to class B, and you don't have null=True on it, meaning you never want that field to be empty. In other words, each instance of A should have a foreign key desc.
If you just save() both forms, formA tries to save an instance of A, without having a value for desc field, hence the error. You should assign the instance that formB creates to the instance that formA creates:
new_b = formB.save()
new_a = formA.save(commit=False)
new_a.desc = new_b
new_a.save()
Other problems in your program including never called form.is_valid(), having redundant id fields(django would create one for you). I suggest you read django tutorial first before jumping into coding. It would save a lot of time like figuring out errors like this.

How to pass ActiveRecord model class to Resque

Let's say I have the following Resque job:
class Archive
#queue = :file_serve
def self.perform(repo_id, branch = 'master')
repo = Repository.find(repo_id)
repo.create_archive(branch)
end
end
What if I wanted to make this more generic by passing an object id and the object's class so that I can do something like this:
class Archive
#queue = :file_serve
def self.perform(object_class, object_id, branch = 'master')
object = object_class.find(object_id)
object.create_archive(branch)
end
end
This doesn't work, obviously, and I don't have a sense for what I should be doing, so if anyone can give some guidance, that would be really appreciated!
I would pass the name of the class to the job, rather than the class itself. Then you could call constantize on the name to get the class back, and call find on it. eg.
def self.perform(class_name, object_id, branch = 'master')
object = class_name.constantize.find(object_id)
object.create_archive(branch)
end

How to create object of one Model after creating another Model's object using serialization and modelViewSet

These are MODELS:
class Event (models.Model):
status = models.CharField(max_length = 30, blank = True)
time = models.DateTimeField()
point = models.ForeignKey(Point)
person = models.ForeignKey(Person)
device = models.ForeignKey(Device)
organization = models.ForeignKey(Organization)
class Presence(models.Model):
point = models.ForeignKey(Point)
person = models.ForeignKey(Person)
date_from = models.DateTimeField()
date_to = models.DateTimeField()
This is SERIALIZERS:
class EventSerializer(serializers.ModelSerializer):
person = serializers.SlugRelatedField(queryset=Person.objects.all(), slug_field='card_tag')
class Meta:
model = Event
fields = ['id','time','point','person','device','organization']
this is API:
class EventAPI(viewsets.ModelViewSet):
serializer_class = cs.EventSerializer
This is URL:
url(r'^event/', api.EventAPI.as_view({'post':'create'}), name='event_create'),
so I want these:
after every creation of Event object, check it by %2 (getting number of objects by card_tag, which is in body of request), if it's number
of events %2 == 0 => create object of Presence, how can I do it ?
Thanks and sorry
You should be able to use the perform_create method, which by default looks something like:
def perform_create(self, serializer):
serializer.save()
Now you can override it and do pretty much anything you want.
def perform_create(self, serializer):
serializer.save()
if ..something.. % 2:
Presence.objects.create(...)

Performing PostgreSQL LEFT OUTER JOINS and CASEs in Django

So I have a fairly involved sql query here.
SELECT links_link.id, links_link.created, links_link.url, links_link.title, links_category.title, SUM(links_vote.karma_delta) AS karma, SUM(CASE WHEN links_vote.user_id = 1 THEN links_vote.karma_delta ELSE 0 END) AS user_vote
FROM links_link
LEFT OUTER JOIN auth_user ON (links_link.user_id = auth_user.id)
LEFT OUTER JOIN links_category ON (links_link.category_id = links_category.id)
LEFT OUTER JOIN links_vote ON (links_vote.link_id = links_link.id)
WHERE (links_link.id = links_vote.link_id)
GROUP BY links_link.id, links_link.created, links_link.url, links_link.title, links_category.title
ORDER BY links_link.created DESC
LIMIT 20
All my relations are good (I think) and this query works perfectly when I run it in my navicat for postgresql but turning it into something Django can use has been quite the challenge. I am using the pre-alpha 1.2 development verison (from the subversion repositories) so I have full range of tools from the docs.
Here are my models for grins:
class Category (models.Model):
created = models.DateTimeField(auto_now_add = True)
modified = models.DateTimeField(auto_now = True)
title = models.CharField(max_length = 128)
def __unicode__(self):
return self.title
class Link (models.Model):
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add = True)
modified = models.DateTimeField(auto_now = True)
fame = models.PositiveIntegerField(default = 1)
url = models.URLField(max_length = 2048)
title = models.CharField(max_length = 256)
active = models.BooleanField(default = True)
def __unicode__(self):
return self.title
class Vote (models.Model):
link = models.ForeignKey(Link)
user = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add = True)
modified = models.DateTimeField(auto_now = True)
karma_delta = models.SmallIntegerField(default = 1)
def __unicode__(self):
return str(self.karma_delta)
How I am able to turn
def latest(request):
links = Link.objects.all().order_by('-created')[:20]
return render_to_response('links/list.html', {'links': links})
Into the above query?
I've only been able to make some progress using things like Aggregation but how to tackle my use of CASE is beyond me. Any help would be much appreciated. I always prefer to work in a framework's built in ORM but if raw SQL is necessary...
I don't have time at the moment to attempt a full translation of that query, but if the CASE is your main stumbling block, I can tell you right now it isn't supported natively, you'll need to use a call to .extra() with some raw SQL for that. Something like:
.extra(select={'user_vote': 'SUM(CASE WHEN links_vote.user_id = 1 THEN links_vote.karma_delta ELSE 0 END')})
But if this query works well as-is, why bother translating it into the ORM? Just grab a cursor and run it as a SQL query. Django's ORM is intentionally not a 100% solution, there's a reason it exposes the raw cursor API.
Update: And since Django 1.2, there's also Manager.raw() to let you make raw SQL queries and get model objects back (thanks Van Gale).