Equivalent replacement for ListProperty(db.Key) in djangoappengine - django

I and trying to use djangoappengine, but I am unsure how can I write model to incorporate standard
ListProperty(db.Key)
I know that djangotoolbox provides this field types but I am unable to figure out the exact syntax.

db.ListProperty(db.Key) stores a list of any entity's keys.
models:
class Profile(db.Model):
data_list=db.ListProperty(db.Key)
class Data(db.Model):
name=db.StringProperty()
views:
prof=Profile()
data=Data.all()
for data in data:
prof.data_list.append(data)
/// Here data_list stores the keys of Data entity
Data.get(prof.data_list) will get all the Data entities whose key are in the data_list attribute

Related

How can I use Django's update_or_create function for a model with multiple fields?

I have a model with many fields. In order to update my model, I make a query for my DB and using the dictfetchall() from Django I get a list of dicts containing the results from the query (each key in each dict is the column name for 1 object).
class Enterprise(models.Model):
--- primary key here ---
...
--- many other fields here ---
I want to use the Django's function update_or_create() for updating the existing rows with new information or creating new rows if the object already not exists (based on its pk).
But I don't know how to implement this, due to the large number of fields. Furthermore, the dict keys are not equal to the name of the field in my model.
How can I do this?
Than you!
If I simplify the question a little, you have a list of many objects as dicts you and to add to your database. Some are new, and some already exist. You want to update the existing and create the new ones.
You can use django-bulk-update-or-create to do that.
For the example, I'll use inputs as the list of dictionaries containing your new information.
Enterprise.objects.bulk_update_or_create([
Enterprise(**fields)
for fields in input
], ["all_your_fields_here"], match_field="pk")

Return object when aggregating grouped fields in Django

Assuming the following example model:
# models.py
class event(models.Model):
location = models.CharField(max_length=10)
type = models.CharField(max_length=10)
date = models.DateTimeField()
attendance = models.IntegerField()
I want to get the attendance number for the latest date of each event location and type combination, using Django ORM. According to the Django Aggregation documentation, we can achieve something close to this, using values preceding the annotation.
... the original results are grouped according to the unique combinations of the fields specified in the values() clause. An annotation is then provided for each unique group; the annotation is computed over all members of the group.
So using the example model, we can write:
event.objects.values('location', 'type').annotate(latest_date=Max('date'))
which does indeed group events by location and type, but does not return the attendance field, which is the desired behavior.
Another approach I tried was to use distinct i.e.:
event.objects.distinct('location', 'type').annotate(latest_date=Max('date'))
but I get an error
NotImplementedError: annotate() + distinct(fields) is not implemented.
I found some answers which rely on database specific features of Django, but I would like to find a solution which is agnostic to the underlying relational database.
Alright, I think this one might actually work for you. It is based upon an assumption, which I think is correct.
When you create your model object, they should all be unique. It seems highly unlikely that that you would have two events on the same date, in the same location of the same type. So with that assumption, let's begin: (as a formatting note, class Names tend to start with capital letters to differentiate between classes and variables or instances.)
# First you get your desired events with your criteria.
results = Event.objects.values('location', 'type').annotate(latest_date=Max('date'))
# Make an empty 'list' to store the values you want.
results_list = []
# Then iterate through your 'results' looking up objects
# you want and populating the list.
for r in results:
result = Event.objects.get(location=r['location'], type=r['type'], date=r['latest_date'])
results_list.append(result)
# Now you have a list of objects that you can do whatever you want with.
You might have to look up the exact output of the Max(Date), but this should get you on the right path.

Extract nested value from a Django jsonfield

Is there a way to query an object, 'extract' a nested piece of data from a JSONField field and then make it available as a custom, temporary field on each instance of the Queryset?
In my use case, I'm storing overflow metadata from Twitter's API in a data field for later use. I'd like to be able to access the nested field followers_count within TwitterPost.data.
I've read the docs about how to filter based on nested values but not how to extract it as a temporary field when generating a queryset.
Similarly, I've read the annotate docs for ways to create a custom temporary field but the examples all use aggregation functions on simple fields, so not JSONFields.
Thanks in advance for any suggestions.
Example model:
from django.contrib.postgres.fields import JSONField
class TwitterPost(models.Model):
id = models.IntegerField()
data = JSONField()
Example JSON value for the data field:
{
'followers_count': 7172,
"default_profile_image": false,
"profile_text_color": "000000"
}
Pseudocode for what I'd like to be able to do:
TwitterPost.objects.annotate(followers_count=instance.data.followers_count)
This is probably a late answer, but there is a way to do it
from django.contrib.postgres.fields.jsonb import KeyTransform
TwitterPost.objects.annotate(followers_count=KeyTransform('followers_count', 'data'))
OR KeyTextTransform could be used instead of KeyTransform (for converting to string)
If you want to access the data inside a JSONField, you've to use __. In your example it will be something like this
TwitterPost.objects.annotate(followers_count=instance.data__followers_count)
Take a look to the documentation here

Where are django's annotated fields stored on the model instance?

I am doing this:
p = MyModel.objects.filter(user__username="me").annotate(friend_count=Count(friends))
when I look at:
p[0]._meta.get_all_field_names()
It returns everything defined on the model but not the annotated field 'friend_count'
Is there a function I can use to see all the annotated fields of a particular model instance?
Use this:
p.query.annotations.keys()
It will give the list of all annotated fields.
annotations are just stored as plain instance attributes (just like the values for the ORM fields FWIW). You can use dir(my_model_instance) to see all the attributes (class and instance ones) names, or my_model_instance.__dict__.keys() for the plain instance attributes only.

Django append to JSON after serializers.serialze has been run on a queryset

I am returning a JSON serialized queryset using the following queryset:
genome_parents = Genome.objects.filter(genes=cus_id)
where cus_id is the FK pointing to a companies table so I am retrieving all Genome objects related to the current working company. I return this data after a form has been posted via:
genome_parents = serializers.serialize('json', genome_parents, use_natural_keys=True)
However, I need the natural key for one of my foreign keys, but the id for another (both on the same model). So one field is displayed nicely, but the other isn't. So this does what I need except for one little thing, I need the plain id number so that I can pre-populate my FK form field.
One thought I had was to just append something like
genome_parents.append({'id':gene.id})
but that obviously doesn't work. Is there anyway I can augment the JSON so that I can include one more little piece of data (or change how I format the JSON)?
Greg
Just switch the order of the operations. And put the entire gene object into the list so it is properly serialized.
genome_parents = list( Genome.objects.filter(genes=cus_id) )
genome_parents.append(gene)
json_genome_parents = serializers.serialize('json', genome_parents, use_natural_keys=True)