I have a one2many computed field which i also want users to be able to add new line of records into. i added an inverse field to it, but the only thing it does is to allow already existing records to be modified
#api.one
def accumulate_files(self):
documents = self.env['document.customer']
document_gotten = documents.search([('name','=', self.name)])
for docs in document_gotten:
self.res_line_ids |= docs.customer_line_ids
#api.one
def edit_accumulate_files(self):
documents = self.env['document.customer']
for lines in documents.customer_line_ids:
lines.write(self.res_line_ids)
I did a workaround, not sure how can I get values of one2many field in inverse method, in new api, like it was in old api. however it works for me
#api.multi
def _save_telefone(self):
for partner in self:
for phone in partner.phone_number_ids:
try:
# write on exisiting record
int(phone.id)
# write all possible values
phone.write({'partner_id': partner.id})
except:
# create new record with all possible values
phone.create({
'partner_id': partner.id,
'type_id': phone.type_id.id,
'status_id': phone.status_id.id,
'sequence': phone.sequence,
'graph_value': phone.graph_value,
'name': phone.name,
})
return True
Basically, create a record if it doesn't exist otherwise write on it.
how to know if record exists in DB? if the ID is integer it already
exists, otherwise it will have ID something like "odoo.model.NewID"
that means ID hasn't been assigned yet record is in memory yet.
Related
It is my first question here, after reading the similar questions I did not find what I need, thanks for your help.
I am creating a fairly simple API but I want to use best practices at the security level.
Requirement: There is a table in SQL Server with +5 million records that I should ONLY allow READ (all fields) and UPDATE (one field). This is so that a data scientist consumes data from this table and through a predictive model (I think) can assign a value to each record.
For this I mainly need 2 things:
That only one field is updated despite sending all the fields of the table in the Json (I think I have achieved it with my serializer).
And, where I have problems, is in disabling the creation of new records when updating one that does not exist.
I am using an UpdateAPIView to allow trying to allow a bulk update using a json like this (subrrogate_key is in my table and I use lookup_field to:
[
{
"subrrogate_key": "A1",
"class": "A"
},
{
"subrrogate_key": "A2",
"class": "B"
},
{
"subrrogate_key": "A3",
"class": "C"
},
]
When using the partial_update methods use update and this perform_update and this finally calls save and the default operation is to insert a new record if the primary key (or the one specified in lookup_field) is not found.
If I overwrite them, how can I make a new record not be inserted, and only update the field if it exists?
I tried:
Model.objects.filter (subrrogate_key = ['subrrogate_key']). Update (class = ['class])
Model.objects.update_or_create (...)
They work fine if all the keys in the Json exist, because if a new one comes they will insert (I don't want this).
P.S. I use a translator, sorry.
perform_update will create a new record if you passed a serializer that doesn't have an instance. Depending on how you wrote your view, you can simply check if there is an instance in the serializer before calling save in perform_update to prevent creating a new record:
def perform_update(self, serializer):
if not serializer.instance:
return
serializer.save()
Django implements that feature through the use of either force_update or update_fields during save().
https://docs.djangoproject.com/en/3.2/ref/models/instances/#forcing-an-insert-or-update
https://docs.djangoproject.com/en/3.2/ref/models/instances/#specifying-which-fields-to-save
https://docs.djangoproject.com/en/3.2/ref/models/instances/#saving-objects
In some rare circumstances, it’s necessary to be able to force the
save() method to perform an SQL INSERT and not fall back to doing an
UPDATE. Or vice-versa: update, if possible, but not insert a new row.
In these cases you can pass the force_insert=True or force_update=True
parameters to the save() method.
model_obj.save(force_update=True)
or
model_obj.save(update_fields=['field1', 'field2'])
I have created a model in Django and for which I get the data from an API. I am trying to use the update_or_create method for getting the data from the API and into my database. However, I may be confused on how it works.
When I run it for the first time it adds the data into the database as expected, however if I were to update one of the fields for a record - the data from the API has changed for the respective record - and then run it again, it is creating a new record rather than updating the existing record.
So in the scenario below, I run it and the count for record Commander Legends is 718, which I then update manually in the database to be 100. When I run it again, it creates a new record with count of 718
With my understanding of it, it should of updated the record rather than create a new record.
views.py
def set_update(request):
try:
discover_api = requests.get('https://api.scryfall.com/sets').json()
set_data = discover_api['data']
while discover_api['has_more']:
discover_api = requests.get(discover_api['next_page']).json()
set_data.extend(discover_api['data'])
except HTTPError as http_err:
print(f'HTTP error occurred: {http_err}')
except Exception as err:
print(f'Other error occurred: {err}')
sorted_data = sorted(set_data, key=lambda k: k['releaseDate'], reverse=False)
for i in sorted_data:
Set.objects.update_or_create(
scry_id=i.get('id'),
code=i.get('code'),
name=i.get('name'),
type=i.get('set_type').replace("_", " ").title(),
release_date=i.get('released_at'),
card_count=i.get('card_count'),
is_digital_only=i.get('digital', False),
is_non_foil_only=i.get('nonfoil_only', False),
is_foil_only=i.get('foil_only', False),
block_name=i.get('block'),
block_code=i.get('block_code'),
parent_set_code=i.get('parent_set_code'),
tcgplayer_id=i.get('tcgplayer_id'),
last_modified=date.today(),
defaults={
'scry_id': i.get('id'),
'code': i.get('code'),
'name': i.get('name'),
'type': i.get('set_type').replace("_", " ").title(),
'release_date': i.get('released_at'),
'card_count': i.get('card_count'),
'is_digital_only': i.get('digital', False),
'is_non_foil_only': i.get('nonfoil_only', False),
'is_foil_only': i.get('foil_only', False),
'block_name': i.get('block'),
'block_code': i.get('block_code'),
'parent_set_code': i.get('parent_set_code'),
'tcgplayer_id': i.get('tcgplayer_id'),
'last_modified': date.today(),
}
)
return redirect('dashboard:sets')
Screenshot
In a update_or_create(…) [Django-doc], you have basically two parts:
the named parameters which do the filtering, only if they can find a record that matches all the filters, it will update that record; and
the defaults=… parameter, which is a dictionary of values that will be used to update or create that record.
If you thus want to update only the card_count and last_modified, it looks like:
Set.objects.update_or_create(
scry_id=i.get('id'),
code=i.get('code'),
name=i.get('name'),
type=i.get('set_type').replace('_', ' ').title(),
release_date=i.get('released_at'),
is_digital_only=i.get('digital', False),
is_non_foil_only=i.get('nonfoil_only', False),
is_foil_only=i.get('foil_only', False),
block_name=i.get('block'),
block_code=i.get('block_code'),
parent_set_code=i.get('parent_set_code'),
tcgplayer_id=i.get('tcgplayer_id'),
defaults={
'card_count': i.get('card_count'),
'last_modified': date.today()
}
)
If you thus add card_count at the kwargs, it will only update the record if the card_count matches completely, so if both defaults and the kwargs contain the same values, you basically will either do nothing in case a record exists with all the values in place, or create a new one if no such record is present.
I'm trying to submit a form with a file field. There are instances when the file is not yet available so the user will have to submit the form without the file first.
My field now looks like this
file_attachment_pdf = models.FileField(blank= True,null = True, unique=True)
I'm able to save 1 record with blank fields. When adding the 2nd record with blank file upload, it doesn't work anymore since there is an existing record with the file value.
Upon checking, it's an empty string.
So I tried to override the clean function in models.py
def clean(self):
if not self.file_attachment_doc:
print('doc is blank, will tag as Null')
self.file_attachment_doc = None
But for some reason, when I check in the DB it still stores as an empty string. (I'm using DB Browser for SQLite, it says the field of data is Text with 0 chars)
When I try to submit, here is the error that is returned to me
File with this File attachment pdf already exists.
If this question was already asked and answered before, please do let me know.
FileField store the file path as a CharField. For CharField, the null=True settings, equals to store empty string. That why you see empty string in your db. Your error come from the unique=True parameter. That means that you can store only one empty file for your model.
Plus the model clean method is called only if you user model form to save you instance. In all way, if the method is call or not, it don't make difference, the value stored would be always empty string
https://docs.djangoproject.com/en/2.1/ref/models/fields/#null
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])]")
How can I resolve a resource_uri during a Tastypie hydrate call?
I am passing the following data object to a Tastypie resource:
{
'date': u'2013-10-31 15:06',
'visitor': u'/visitorlog/api/v1/person/33/',
'purpose': u'Testing'
}
I would like to take the visitor and pull the entire record in a hydrate function, which populates a field with some extra information.
I am currently doing this by splitting out the id and performing a search:
def hydrate_meta(self, bundle):
'''
This will populate the `meta` field with a snapshot of the employee record, if the `empid` is set. This is done so if the employee record changes we retain certain information at the time of the visit.
'''
split_id = bundle.data['visitor'].split('/')
# the id of `visitor` is in `split_id[-2]
# get the record of this visitor from the Django model
person_record = Person.objects.get(pk = split_id[-2])
# ... snipped ... create the `meta_value` object
bundle.data['meta'] = meta_values
return bundle
This is working, but calling split on the resource_uri does not seem the most elegant way to do this.
Is there more effective way to pull a record given a resource_uri?
Resource.get_via_uri(url) (doc) might come in handy.