Odoo fields_view_get add dynamic groups - python-2.7

I want to override fields_view_get of odoo to add groups to fields dynamically based on a condition.
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
res = super(client_quote, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar,
submenu=submenu)
"""update this method to change the string of fields in different tab of client quote if it changes from vfx sheet """
if view_type == 'form' and ('vfx_shots_ids' in res['fields']):
for field in res['fields']['vfx_shots_ids']['views']['tree']['fields']:
if self._context.get('quote_id'):
vfx_quote_id = self.env['vfx.quote'].browse(self._context['quote_id'])
field_id = self.env['field.name'].search([('name', '=', field)])
if field_id:
line_id = self.env['mapping.template.line'].search([('template_id', '=', vfx_quote_id.template_id.id),
('field_id', '=', field_id.id),
('model_name', '=', 'vfx.shots')
])
if line_id:
string = line_id.heading_id.name
res['fields']['vfx_shots_ids']['views']['tree']['fields'][field]['string'] = _(string)
res['fields']['vfx_shots_ids']['views']['tree']['fields'][field]['groups'] = str('vfx_quote_template.group_empty_fields')
return res
This is my class and fields, i want to change vfx_quote_template.group_executive_producer group based of a condition.
Currently fields_view_get code seems to have no effect.
class vfx_shots(models.Model):
_name = 'vfx.shots'
item_number = fields.Char('Item',groups="vfx_quote_template.group_executive_producer")

You have to use lxml library to modify the XML architecture of the view in the fields_view_get() method.
You can also override the fields definition by overriding the fields_get() method.
You can get examples here : https://bazaar.launchpad.net/~unifield-team/unifield-server/trunk/view/head:/bin/addons/consumption_calculation/history_consumption.py#L457
I know it is in v6 version of the code, but the fields_view_get behavior didn't change a lot since this version.

Related

django dynamic content in query

I am trying to "DRY" my code and would like to create a function to make my query dynamic.
The code that I currently use is :
rightone = []
for item in taglist: #taglist is a list of model instances, not relevant here
content = content.filter(tags__title=item.title) #tags here is a M2M key : my problem, content is a query
rightone.append(content)
tagproofquery = rightone[-1]
and I would like to convert it to:
def uniquetogether(queryset,data, model):
rightone = []
for item in queryset:
content = data.filter(tags__title=item.title) # <--- problem is here with tags
rightone.append(content)
tagproofquery = rightone[-1]
return tagproofquery
I have no idea how to replace my M2M "tags" as in tags__title=item.title with the "model" parameter of my function. I tried f strings but it failed miserably (of course).
Is there a way to do this? Many thanks

Unexpected behavior of ndb Structured Property

I am using ndb Structured property in my app. The models look like this:
Resource External Integration:
class ResourceExternalIntegration(ndb.Model):
integration_type = ndb.StringProperty()
external_resource_type = ndb.StringProperty()
external_resource_id = ndb.IntegerProperty()
external_group_id = ndb.IntegerProperty()
external_resource_name = ndb.StringProperty()
Resouce Model:
class Resource(ndb.Model):
owner = ndb.IntegerProperty()
name = ndb.StringProperty()
type = ndb.StringProperty()
external_integrations = ndb.StructuredProperty(ResourceExternalIntegration, repeated=True)
Note that i have structured property as repeated=True
Issue:
I have a function in Resource class which formats/serializes the data extracted from DB. It looks like this:
def serialize(self):
external_integrations_list = []
if self.external_integrations:
for external_integration in self.external_integrations:
external_integration_dict = dict()
external_integration_dict['integration_type'] = external_integration.integration_type,
external_integration_dict['external_resource_type'] = external_integration.external_resource_type,
external_integration_dict['external_resource_id'] = external_integration.external_resource_id
external_integration_dict['external_group_id'] = external_integration.external_group_id
external_integration_dict['external_resource_name'] = external_integration.external_resource_name
external_integrations_list.append(external_integration_dict)
resource_data.update(dict(
owner=self.owner,
name=self.name,
type=self.type,
external_integrations=external_integrations_list
))
return resource_data
Now, in the resource_data the attribute external_integrations should be an array and every element in it should also be an array i.e. external_resource_id, external_resource_type etc should also be an array. It is because of the fact that structured property was set as repeated=True. But, the resource_data does not contain this expected result. It looks like:
{'name': u'Scissors lift', 'type': u'Scissors', 'external_integrations': [{'external_resource_type': (u'FLEET',), 'integration_type': (u'ABC',), 'external_resource_id': 212017856321402L, 'external_resource_name': u"Test 1", 'external_group_id': 5000}],'owner': 5629490125014563L}
And, on browser it looks like this:
external_group_id: 5000
external_resource_id: 212017856321402
external_resource_name: "Test 1"
external_resource_type: ["FLEET"]
integration_type: ["ABC"]
i.e. the external_group_id, external_resource_id, external_resource_name does not appear as array, but they were expected as arrays.
I also have another model in which the structured property does not exists as repeated=True. It looks like:
External Integration
class ExternalIntegration(ndb.Model):
access_token = ndb.StringProperty()
group_ids = ndb.IntegerProperty(repeated=True)
Profile
class profile(ndb.Model):
name = ndb.StringProperty()
integration_info = ndb.StructuredProperty(ExternalIntegration)
Here, the serialize function of profile model show result as:
{'integration_info': {'group_ids': ([5000],), 'access_token': (u'blahblahblahblah',)}, ''name: 'Test'}
And, on browser the result looks like:
access_token: ["blahblahblahblah"]
group_ids: [[5000]]
I am unable to understand why access_token appears as an array and why groups_ids is an array of array.
Can anyone please help me understand such behavior of ndb structured property? Specifically the cases i explained above.
There are two questions here:
Regarding the profile model:
integration_info contains two elements defined in ExternalIntegration class. It is saved as a dictionary containing two elements: access_token and group_ids. group_ids is defined with repeated=True, which takes a list of values of the underlying type, which creates a list. To summarize:
access_token appears as a string.
group_ids appears as a list, because repeated is set to True.
Regarding the resource model:
external_integrations appear as a list, because you defined repeated=True.
There is only one element on the list because the whole dictionary was appended in a single operation, instead of element per element.
external_group_id, external_resource_id and external_resource_name don't appear as an array because they were not defined with repeated=True. The definition is applied one level above, to external_integrations, not to each of its contained strings.
Try to redefine the elements which should be repeated and the ones that shouldn't.

Django get_or_create with icontains

I'm getting an unexpected result using icontains in my get_or_create call.
Take the following example:
>>>team_name = "Bears"
>>>Team.objects.get(name__icontains=team_name) # returns DoesNotExist as expected
>>>team, created = Team.objects.get_or_create(name__icontains=team_name)
>>>print(created) # Prints True as expected
>>>print(team.name) # Prints an empty string!
Why does this create a team with a blank name rather than "Bears"? The reason I'm using get_or_create here is that if a subsequent user posts something like "BearS" I want to get the correct team, not create a duplicate team with incorrect capitalization.
I think here you should split the get() and create() functionalities instead of using get_or_create(), because the __icontains lookup works for get() only.
Try doing something like this:
>>> team_name = 'Bears'
>>> teams = Team.objects.filter(name__icontains=team_name)
# This will filter the teams with this name
>>> team = teams.first() if teams.exists() else Team.objects.create(name=team_name)
# Now your team is the first element of your previous query (it returns a QuerySet with single element) if it exists
# Otherwise, you create a new Team.
Another option besides wencakisa's answer is to include the defaults parameter in get_or_create, because Django strips lookups containing the __ separator. See answers to this question.
The code would be:
Team.objects.get_or_create(
name__icontains=team_name,
defaults = {
"name": team_name
}
)
The right way to do it is using Django's function get_or_create(). But instead of "icontains", you should use "iexact" (), unless you want an exact match, in wich case you should use just "exact":
Team.objects.get_or_create(
name__iexact=team_name,
defaults = {
"name": team_name
}
)
Outside "defaults" you should put your search terms. If the objects doesn't exist, you should write your creation terms inside 'defaults'

Odoo error: return self.models[model_name] KeyError: 'res_groups_users_rel'

I need to make UI many2one dopdown list where I can identify users which depend to Manager group role.
Now I have dropdown field:
test = fields.Many2one('res.groups', 'Purchase request type', default=_get_users, track_visibility='onchange')
And I tried to write a function which can identify all users which depend to manager group role.
def _get_users(self):
pickings = self.env['res_groups_users_rel'].search([('gid','=',61)])
pickings_available = []
for picking in pickings:
pickings_available.append(picking)
return pickings_available
And I got an error:
return self.models[model_name]
KeyError: 'res_groups_users_rel'
I don't know how can I change this function and get value from amy2many relation.
I changed my function to:
def _get_users(self):
pickings = self.env['res.groups'].browse(61).users
pickings_available = []
for picking in pickings:
pickings_available.append(picking)
return pickings_available
and field:
test = fields.Many2one('res.users', 'Some text', default=_get_users, track_visibility='onchange')
I logged function _get_users and get values: [res.users(9,), res.users(65,)]
But I still can't get these values on my test field dropdown. What I am doing wrong?
If you are trying to get all users that belong to a group, why not do the following:
self.env['res_groups'].browse(61).users
On a side note, you might get an error, trying to assign a list as default value to a Many2one field.
Also you seem to be assigning users belonging to a group to a field that is specified to store reference to groups.
If you need to have a field to select a user that belongs to group with id 61, you can do the following:
test = fields.Many2one('res.users', 'Some description', domain="[('groups_id', 'in', [61])]")

Django: How to use django.forms.ModelChoiceField with a Raw SQL query?

I'm trying to render a form with a combo that shows related entities. Therefore I'm using a ModelChoiceField.
This approach works well, until I needed to limit which entities to show. If I use a simple query expression it also works well, but things break if I use a raw SQL query.
So my code that works, sets the queryset to a filter expression.
class ReservationForm(forms.Form):
location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time")
def __init__(self,*args,**kwargs):
city_id = kwargs.pop("city_id") # client is the parameter passed from views.py
super(ReservationForm, self).__init__(*args,**kwargs)
# TODO: move this to a manager
self.fields['location_time_slot'].queryset = LocationTimeSlot.objects.filter(city__id = city_id )
BUT, if I change that to a raw query I start having problems. Code that does not work:
class ReservationForm(forms.Form):
location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time")
def __init__(self,*args,**kwargs):
city_id = kwargs.pop("city_id") # client is the parameter passed from views.py
super(ReservationForm, self).__init__(*args,**kwargs)
# TODO: move this to a manager
query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order'
FROM reservations_locationtimeslot AS ts
INNER JOIN reservations_location AS l ON l.id = ts.location_id
WHERE l.city_id = %s
AND ts.available_reserves > 0
AND ts.datetime_from > datetime() """
time_slots = LocationTimeSlot.objects.raw(query, [city_id])
self.fields['location_time_slot'].queryset = time_slots
The first error I get when trying to render the widget is: 'RawQuerySet' object has no attribute 'all'
I could solve that one thanks to one of the commets in enter link description here, by doing:
time_slots.all = time_slots.__iter__ # Dummy fix to allow default form rendering with raw SQL
But now I'm getting something similar when posting the form:
'RawQuerySet' object has no attribute 'get'
Is there a proper way to prepare a RawQuerySet to be used by ModelChoiceField?
Thanks!
Are you sure you actually need a raw query there? Just looking at that query, I can't see any reason you can't just do it with filter(location__city=city_id, available_reserves__gte=0, datetime_from__gt=datetime.datetime.now()).
Raw query sets are missing a number of methods that are defined on conventional query sets, so just dropping them in place isn't likely to work without writing your own definitions for all those methods.
I temporarily fixed the problem adding the missing methods.
The way I'm currently using the ModelChoiceField I only needed to add the all() and get() methods, but in different scenarios you might need to add some other methods as well. Also this is not a perfect solution because:
1) Defining the get method this way migth produce incorrect results. I think the get() method is used to validate that the selected option is within the options returned by all(). The way I temporarily implemented it only validates that the id exists in the table.
2) I guess the get method is less performant specified this way.
If anyone can think of a better solution, please let me know.
So my temporary solution:
class LocationTimeSlotManager(models.Manager):
def availableSlots(self, city_id):
query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order'
FROM reservations_locationtimeslot AS ts
.....
.....
MORE SQL """
time_slots = LocationTimeSlot.objects.raw(query, [city_id])
# Dummy fix to allow default form rendering with raw SQL
time_slots.all = time_slots.__iter__
time_slots.get = LocationTimeSlot.objects.get
return time_slots