how to save django object using dictionary? - django

is there a way that I can save the model by using dictionary
for e.g.
this is working fine,
p1 = Poll.objects.get(pk=1)
p1.name = 'poll2'
p1.descirption = 'poll2 description'
p1.save()
but what if I have dictionary like { 'name': 'poll2', 'description: 'poll2 description' }
is there a simple way to save the such dictionary direct to Poll

drmegahertz's solution works if you're creating a new object from scratch. In your example, though, you seem to want to update an existing object. You do this by accessing the __dict__ attribute that every Python object has:
p1.__dict__.update(mydatadict)
p1.save()

You could unwrap the dictionary, making its keys and values act like named arguments:
data_dict = {'name': 'foo', 'description': 'bar'}
# This becomes Poll(name='foo', description='bar')
p = Poll(**data_dict)
...
p.save()

I find only this variant worked for me clear.
Also in this case all Signals will be triggered properly
p1 = Poll.objects.get(pk=1)
values = { 'name': 'poll2', 'description': 'poll2 description' }
for field, value in values.items():
if hasattr(p1, field):
setattr(p1, field, value)
p1.save()

You could achieve this by using update on a filterset:
e.g.:
data = { 'name': 'poll2', 'description: 'poll2 description' }
p1 = Poll.objects.filter(pk=1)
p1.update(**data)
Notes:
be aware that .update does not trigger signals
You may want to put a check in there to make sure that only 1 result is returned before updating (just to be on the safe side). e.g.: if p1.count() == 1: ...
This may be a preferable option to using __ methods such as __dict__.

Related

Can I restrict post method in flask restApi from adding another data to the database?

Given with my current data in db, I want to restrict the post method from adding another data to the database. What I want is restrict the post method in adding another data, and just update the existing data within the db.
Code:
def get(self):
predict = PredictModel.query.all()
return {'Predict': list(x.json() for x in predict)}
def post(self):
data = request.get_json()
new_predict = PredictModel(data['timelag1'],data['timelag2'],data['timelag3'],data['timelag4'],data['timelag5'])
db.session.add(new_predict)
db.session.commit()
db.session.flush()
return new_predict.json(),201
Current data in db:
"Predict": [
{
"timelag1":1,
"timelag2": 1,
"timelag3": 1,
"timelag4": 1,
"timelag5": 1
}
]
}
Data in db after a user entered another data:
"Predict": [
{
"timelag1":2,
"timelag2": 2,
"timelag3": 2,
"timelag4": 2,
"timelag5": 2
}
]
}
I recommend reading this answer concerning how to do the database manipulation (especially the later ones):
Flask-SQLalchemy update a row's information
you will need some kind of primary key or unique identifier to specify the row that you want to change - something like "id"
here's some sample code which will probably work if you adapt it to your case:
instance = User.query.filter(User.id==id)
data=instance.update(dict(json_data))
db.session.commit()
or
num_rows_updated = User.query.filter_by(username='admin').update(dict(email='my_new_email#example.com')))
db.session.commit()

Django Rest Framework filtering a set of item to include only latest entry of each type

I have a list of object of this kind of structure returned in my api
SomeCustomModel => {
itemId: "id",
relatedItem: "id",
data: {},
created_at: "data string"
}
I want to return a list that contains only unique relatedItemIds, filtered by the one that was created most recently.
I have written this and it seems to work
id_tracker = {}
query_set = SomeCustomModel.objects.all()
for item in query_set:
if item.relatedItem.id not in id_tracker:
id_tracker[item.relatedItem.id] = 1
else:
query_set = query_set.exclude(id=item.id)
return query_set
This works by I am wondering if there is cleaner way of writing this using only django aggregations.
I am using Mysql so the distinct("relatedItem") aggregation is not supported.
You should try to do this within sql. You can use Subquery to accomplish this. Here's the example from the django docs.
from django.db.models import OuterRef, Subquery
newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))
Unfortunately, I haven't found anything that can replace distict() in a django-esque manner. However, you could do something along the lines of:
list(set(map(lambda x: x.['relatedItem_id'], query_set.order_by('created_at').values('relatedItem_id'))))
or
list(set(map(lambda x: x.relatedItem_id, query_set.order_by('created_at'))))
which are a bit more Pythonic.
However, you are saying that you want to return a list yet your function returns a queryset. Which is the valid one?

Django ORM call to obtain multiple fk values?

models.py (derived from existing db)
class IceCreamComponent(models.Model):
name = models.CharField
#can be 'flavor', 'nut', etc
class IceCream(models.Model):
name = models.CharField
component = models.ForeignKey(IceCreamComponent)
value = models.CharField #will correspond to the component
The context behind this database is that 'IceCream' reports will come in from someone who's only purpose is to report back on a certain component (i.e. my 'extras' reporter will report the name of the ice cream and the extra it contained). It is assumed that all needed reports are in the db when queried so that something like:
IceCreams = IceCream.objects.values('name', 'component__name', 'value')
will return something akin to:
[
{'name': 'Rocky road', 'component__name': 'ice cream flavor', 'value':'chocolate'},
{'name': 'Rocky road', 'component__name': 'nut', 'value':'almond'},
{'name': 'Rocky road', 'component__name': 'extra', 'value':'marshmallow'},
{'name': 'Vanilla Bean', 'component__name': 'ice cream flavor', 'value':'vanilla'},
{'name': 'Vanilla Bean', 'component__name': 'extra', 'value':'ground vanilla bean'},
]
However, as you can imagine something like:
[
{'name': 'Rocky Road', 'ice cream flavor': 'chocolate', 'nut': 'almond', 'extra':'marshmallow' },
{'name': 'Vanilla Bean', 'ice cream flavor': 'vanilla', 'extra':'ground vanilla bean'}
]
is much more usable (especially considering I'd like to use this in a ListView).
Is there a better way to query the data or will I need to loop through the ValuesQuerySet to achieve the desired output?
Can't you reconstruct the list from the original result?
results = []
for row in vqueryset:
converted_row = {}
converted_row[row['component__name']] = row['value']
converted_row['name'] = row['name']
results.append(converted_row)
Of course you would want to paginate the original result before evaluating it (turning it into a list).
oh, you asked if there's a better way. I'm doing it this way because I couldn't find a better way anyway.
Here is the solution I came up with.
processing = None
output = []
base_dict = {}
for item in IceCreams:
# Detect change current site code from ordered list
if item['name'] != processing:
processing = item['name']
# If base_dict is not empty add it to our output (only first one)
# TODO see if there's a better way to do first one
if base_dict:
output.append(base_dict)
base_dict = {}
base_dict['name'] = item['name']
base_dict[item['component__name']] = item['value']

django retrieve specific data from a dictionary database field

I have a table that contains values saved as a dictionary.
FIELD_NAME: extra_data
VALUE:
{"code": null, "user_id": "103713616419757182414", "access_token": "ya29.IwBloLKFALsddhsAAADlliOoDeE-PD_--yz1i_BZvujw8ixGPh4zH-teMNgkIA", "expires": 3599}
I need to retrieve the user_id value from the field "extra_data" only not the dictionnary like below.
event_list = Event.objects.filter(season_id=season_id, event_status_id=2).value('extra_data')
If you are storing a dictionary as text in the code you can easily convert it to a python dictionary using eval - although I don't know why you'd want to as it opens you to all sorts of potential malicious code injections.
event_list = eval(Event.objects.filter(season_id=season_id, event_status_id=2).value('extra_data'))
user_id = event_list['user_id']
print user_id
Would give:
"103713616419757182414"
Edit:
On deeper inspection , thats not a Python dictionary, you could import a JSON library to import this, or declare what null is like so:
null = None
event_list = eval(Event.objects.filter(season_id=season_id, event_status_id=2).value('extra_data'))
user_id = event_list['user_id']
Either way, the idea of storing any structured data in a django textfield is fraught with danger that will come back to bite you. The best solution is to rethink your data structures.
This method worked for me. However, this works with a json compliant string
import json
json_obj = json.loads(event_list)
dict1 = dict(json_obj)
print dict1['user_id']

Using knockout destroy() with django deserializer

In knockout.js there is a function called destroy() See bottom of this page
It says that it is useful for Rails developers as it adds a _destroy attribute to a object in an observerable array
Im using django and trying to use the same function to know which objects to delete from my database - and as far as i understand a django deserialized object only contains the and pk what is in the fields object
this is what the json looks like:
{"pk": 1,
"model": "eventmanager.datetimelocgroup",
"fields": {"event": 10},
"_destroy": "true"
}
As of now i have very ugly but working code - i was wondering if there is any shorter way to detect if a deserialized object had a destroy flag
my current code looks like this
ra = []
removejson = json.loads(eventslist)
for i,a in enumerate(removejson):
if '_destroy' in a:
ra.append(i)
for index,event in enumerate(serializers.deserialize("json", eventslist)):
if index in ra:
try:
e = Event.objects.get(id = event.object.pk)
e.delete()
except ObjectDoesNotExist:
pass
else:
event.save()
I was wondering if there is a better way than going through the json multiple time
This oneliner should work (please understand it before trying it out):
Event.objects.filter(
id__in = [
x['fields']['event'] for x in json.loads(eventslist) if '_destroy' in x
]
).delete()