Understanding Full Join in Django - sql

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

Related

odoo calculate 2 fields with compute

I have this 2 fields which is I want to calculate using compute
_columns = {
'feb_target':fields.float('Februari Target'),
'apr_target':fields.float('April Target'),
'ytd':fields.float('YTD', compute='_computeytd'),
}
#api.depends('feb_target', 'apr_target')
def _computeytd(self):
for record in self:
record.ytd = record.feb_target + record.apr_target
But the result is 0.
What should I do? Thank you
Wow that took me back to my beginnings.
Old API fields defined in _columns should use fields.function for computed fields. But i prefer to use the "new" API when possible. And your code looks like fully done by yourself, so it is possible.
from odoo import api, fields, models
class YourClass(models.Model):
feb_target = fields.Float('Februari Target')
apr_target = fields.Float('April Target')
ytd = fields.Float('YTD', compute='_compute_ytd')
#api.multi
#api.depends('feb_target', 'apr_target')
def _compute_ytd(self):
for record in self:
record.ytd = record.feb_target + record.apr_target

Loading a dropdown content dynamically

I'm new in the Odoo world and now I'm stuck. I have this (Odoo v11.0):
Model: class Dog()
dog_name = fields.Char()
gps = fields.Many2One(Model Gps)
Model: class Gps()
serial = fields.Char()
I have a Gps list that is show in the Dog's form as a dropdown list, each time a Dog record is created only one Gps can be assigned to it, so the next time I create a Dog those assigned Gps must not appear in the dropdown list.
How to accomplish it?
Thanx in advance
Please add below method in class Gps.
#api.multi
def name_get(self):
if self._context.get('filter_gps'):
gps_records = self.env['Dog'].search([('gps','!=',False)]).mapped('gps')
new_self = self - gps_records
return super(Gps,new_self).name_get()
return super(Gps,self).name_get()
Add this method to Dog class:
#api.one
#api.onchange('gps')
def onchange_gps(self):
If not self.gps:
Res = {}
Ids = []
Dogs = self.env['dog'].search([])
Ids = [d.gps for d in dogs]
Res['Domain'] = {'gps' : [('id', 'not in', ids)]}
Return res

Odoo 10 selection fields value

How can i get selection fields value in odoo 10?
def compute_default_value(self):
return self.get_value("field")
I tried this,
def compute_default_value(self):
return dict(self._fields['field'].selection).get(self.type)
Also tried this,but it is not working.
Please help me, i could not find the solution.
Thank you.
You can do this in a following manner:
self._fields['your_field']._desription_selection(self.env)
This will return the selection list of pairs (value, label).
If you just need possible values, you can use get_values method.
self._fields['your_field'].get_values(self.env)
But it's not a common way. Most of the time people define selections differently and then use those definitions. For example, I commonly use classes for those.
class BaseSelectionType(object):
""" Base abstract class """
values = None
#classmethod
def get_selection(cls):
return [(x, cls.values[x]) for x in sorted(cls.values)]
#classmethod
def get_value(cls, _id):
return cls.values.get(_id, False)
class StateType(BaseSelectionType):
""" Your selection """
NEW = 1
IN_PROGRESS = 2
FINISHED = 3
values = {
NEW: 'New',
IN_PROGRESS: 'In Progress',
FINISHED: 'Finished'
}
You can use this class wherever you want, just import it.
state = fields.Selection(StateType.get_selection(), 'State')
And it's really handy to use those in the code. For example, if you want to do something on a specific state:
if self.state == StateType.NEW:
# do your code ...
I don't get the question fully, but let me try to answer. Why not just define the selection as method and use it for both situations:
from datetime import datetime
from odoo import models, fields
class MyModel(models.Model):
_name = 'my.model'
def month_selection(self):
return [(1, 'Month1'), (2, 'Month2')]
def compute_default_value(self):
selection = self.month_selection()
# do whatever you want here
month = fields.Selection(
selection=month_selection, string='Month',
default=datetime.now().month, required=True)

Increment integer fileds Odoo

I have added this fields under account.invoice in order to get an autoincrement number but it doesn't work.
Help me please to figure out my error
Example Code
class invoice(osv.osv):
_inherit = 'account.invoice'
def _get_increment(self, cr, uid, ids, fields, arg, context=None):
if context is None: context = {}
res = {}
if type == 'out_invoice':
ids = self.search(cr,uid,[('id','!=',False),('type','in',('out_invoice','out_refund'))])
if ids:
last_id = ids and max(ids)
print 'last_id',last_id
for invoice in self.browse(cr, uid, last_id, context):
print 'invoice', invoice
if invoice.name1:
res[invoice.id] = invoice.name1
else :
res[invoice.id] = invoice.name1 + 1
return res
_columns={
'name1':fields.function(_get_increment, type='integer', string='Name1'),
}
First of all. Your function never returns a value since type is never set.
Which means the if condition is never triggered.
At second. I'd suggest that you'd use the new Odoo API.
function fields are replaced by the compute attribute on fields and the declaration no longer takes place in the _columns dictionary.
New API
instead of importing from openerp.osv you should import the following:
from openerp import fields, models, api
The code would look like this:
from openerp import fields, models, api
class invoice(models.Model):
_inherit = 'account.invoice'
name1 = fields.Integer('Name1', compute='_get_increment')
#api.one
def _get_increment(self):
self.name1 = 1 + 1 #This value should be the value that you've calculated
the only thing you need to do in the method _get_increment is set self.name1.
In the new API self is a record. So self.id would get you the id of the record and so on.

Creating a user actions stream in rails

I'm trying to create a stream of actions in my rails App. Here are the helper methods I use to generate a list of likes a user received, and a list of stories a user's friend wrote.
Later, I simply combine these into one array to display in a view. But, I want to sort my final array, by date, but when I use .map in the earlier methods, I can't figure out how to get a date object in there that I can sort by.
def get_stream(current_user)
stories = get_friends_stories(current_user)
likes = get_likes(current_user)
stream = [stories, likes]
stream.flatten
end
def get_likes(user)
stories = get_stories(user)
likes = Like.find_all_by_story_id(stories)
hash = likes.map {|like| "#{like.user.display_name} liked your story #{like.story.title}" }
end
def get_friends_stories(user)
friends = get_friends(user)
friend_ids = friends.map {|f| f.friend_id }
stories = Story.find_all_by_user_id(friend_ids)
hash = stories.map {|story| "#{story.user.display_name} wrote a story called #{story.title}" }
end
Just a simple change seems to work:
def get_stream(current_user)
stories = get_friends_stories(current_user)
likes = get_likes(current_user).sort_by {|l| l.created_at }
streams = stories + likes
streams.sort_by(&:created_at)
end