Django JsonField Array data query - django

I have a jsonfield in Postgres db and data like below:
income_info = [
{
"id": "1",
"name": "A",
"min_income": 22000
},
{
"id": "2",
"name": "B",
"min_income": 40000
},
{
"id": "3",
"name": "C",
"min_income": 22000
}
]
Now want to use gte and lte over the django orm queryset. Already tried
Employee.objects.filter(income_info__min_income__lte = 4000000)
but did not work at all.
models.py:
class Employee(models.Model):
institute = models.ForeignKey(Institute, on_delete=models.DO_NOTHING)
income_info = JSONField(default=list)
others = models.TextField(null=True)

In django's documentation for querying JsonFields:
If the key is an integer, it will be interpreted as an index lookup in an array
As your json data is list of json datas, you need a query like this:
Employee.objects.filter(income_info__0__min_income__lte=4000000)

Related

Fetch and return category and all related objects

I have a Bookmark and a BookmarkCategory object. I'd like to be able to fetch JSON that looks like this:
GET -> localhost:8000/api/bookmarks
[
"python": {
"title": "Python",
"bookmarks": [
{
"title": "Python Documentation",
"url": "https://docs.python.org"
}
]
},
"javascript": {
"title": "Javascript",
"bookmarks": [
{
"title": "Python Documentation",
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript"
}
]
}
]
Here's my models:
class BookmarkCategory(models.Model):
title = models.CharField(max_length=255)
class Bookmark(models.Model):
title = models.CharField(max_length=255)
url = models.CharField(max_length=255)
category = models.ManyToManyField(BookmarkCategory)
Here's how I would query all the BookmarkCategory objects:
from .models import BookmarkCategory
bookmarks = BookmarkCategory.objects.all()
The JSON doesn't have to look exactly like this. I just need to get all my BookmarkCategory objects along with all the related Bookmark objects so I can iterate over them after I make a GET request to fetch them.
You'll have to use select_related on "bookmark_set", to fetch them along. If you are using DRF, you need to create a nested serializer configuration for bookmarks. Here is an example without DRF:
categories = BookmarkCategory.objects.select_related("bookmark_set")
items = []
for category in categories:
items.append(
{
"title": category.title,
"bookmarks": category.bookmark_set.values_list("title", "url"),
}
)

Import JSON records into database on Django and performing CRUD on JSON file

1) I have a JSON file (structure as seen below) and it has hundreds of records. How can I put these data into my Django model so that I am able to perform CRUD operations on the data?
I do not want to change the structure of the JSON file to match the output given by Django's model files as it can be tedious.
2) Please advise as I am also unsure where to put my JSON files in the project as well.
[
{
"name": "A",
"abbreviation": "a",
"count": 1
},
{
"name": "B",
"abbreviation": "b",
"count": 3
},
{
"name": "C",
"abbreviation": "c",
"count": 55
}
.
.
.
]
I am new and using Django 2.2 and I just finished "TheNewBoston" Django tutorial. I am using Django's model to makemigration and migrate to my database. I think I am using SQLite which is the default for Django.
Below is my code for my model.
class userDetail(models.Model):
name = models.IntegerField(max_length=20)
abbreviation = models.CharField(max_length=2)
count = models.IntegerField()
EDIT:
I created a data migration apart from the 0001_initial.py.
class Migration(migrations.Migration):
initial = True
def load_data(apps, schema_editor):
data1 = [{
"id": "A",
"abbreviation": "a",
"count": 1
}]
for data in data1:
c = userDetail(id=data['id'],abbreviation=data['abbreviation'], count=data['count'])
c.save()
dependencies = [
'userDetail', '0001_initial.py',
]
operations = [
migrations.RunPython(load_data),
]

How create django model with timestamptz field

I have responce data from API it's look like this
{
"api": {
"results": 1,
"fixtures": {
"65": {
"fixture_id": "65",
"event_timestamp": "1533927600",
"event_date": "2018-08-10T19:00:00+00:00",
"league_id": "2",
"round": "Premier League - 1",
"homeTeam_id": "33",
"awayTeam_id": "46",
"homeTeam": "Manchester United",
"awayTeam": "Leicester",
"status": "Match Finished",
"statusShort": "FT",
"goalsHomeTeam": "2",
"goalsAwayTeam": "1",
"halftime_score": "1 - 0",
"final_score": "2 - 1",
"penalty": null,
"elapsed": "95",
"firstHalfStart": "1533927660",
"secondHalfStart": "1533931380"
}
}
}
}
Now I am trying to build fixture model to store above data in PosgreSql database. I dont understand didnt find any example of builded model with timestamptz field. I need to store event_date key in timestamptz. Can anyone to show me how i should create this field
Django does not have a default timestamp field. However, you can add one by having the following model field:
event_date = models.DateTimeField(auto_now_add=True)
EDIT
Or alternatively, something a little more up to date:
from django.utils import timezone
....
event_date = models.DateTimeField(default=timezone.now)
Make sure its timezone.now and not timzone.now()

Django-REST-Framework "GroupBy" ModelSerializer

I have the following situation
class MyModel(models.Model):
key = models.CharField(max_length=255)
value = models.TextField(max_length=255)
category = models.CharField(max_length=4)
mode = models.CharField(max_length=4)
the fields key, category and mode are unique together. I have the following objects:
m1 = MyModel(key='MODEL_KEY', value='1', category='CAT_1' mode='MODE_1')
m2 = MyModel(key='MODEL_KEY', value='2', category='CAT_1' mode='MODE_2')
m3 = MyModel(key='MODEL_KEY', value='1', category='CAT_2' mode='MODE_1')
m4 = MyModel(key='MODEL_KEY', value='2', category='CAT_2' mode='MODE_2')
I want to expose an API that will group by key and category so the serialized data will look something like this:
{
"key": "MODEL_KEY",
"category": "CAT_1"
"MODE_1": { "id": 1, "value": "1" }
"MODE_2": { "id": 2, "value": "2" }
},
{
"key": "MODEL_KEY",
"category": "CAT_2"
"MODE_1": { "id": 3, "value": "1" }
"MODE_2": { "id": 4, "value": "2" }
}
Is there any way of doing this in django rest framework with ModelSerializer.
There is module that allows you to group Django models and still work with a QuerySet in the result: https://github.com/kako-nawao/django-group-by
Using the above to form your queryset:
# Postgres specific!
from django.contrib.postgres.aggregates.general import ArrayAgg
qs = MyModel.objects.group_by('key', 'category').annotate(
mode_list=ArrayAgg('mode')).order_by(
'key', 'category').distinct()
You can then access the properties key, category and mode_list on the resulting QuerySet items as attributes like qs[0].mode_list. Therefore, in your serializer you can simply name them as fields.
The model_list field might require a SerializerMethodField with some custom code to transform the list.
Note that you need an aggregation if you don't want to group by mode, as well.

Django fixtures primary key error, need natural keys solution

So I have a Film model that holds a list of Actors model in a many to many field:
class Person(models.Model):
full = models.TextField()
short = models.TextField()
num = models.CharField(max_length=5)
class Film(models.Model):
name = models.TextField()
year = models.SmallIntegerField(blank=True)
actors = models.ManyToManyField('Person')
I'm trying to load some initial data from json fixtures, however the problem I have is loading the many to many actors field.
For example I get the error:
DeserializationError: [u"'Anna-Varney' value must be an integer."]
with these fixtures:
{
"pk": 1,
"model": "data.Film",
"fields": {
"actors": [
"Anna-Varney"
],
"name": "Like a Corpse Standing in Desperation (2005) (V)",
"year": "2005"
}
while my actors fixture looks like this:
{
"pk": 1,
"model": "data.Person",
"fields": {
"full": "Anna-Varney",
"num": "I",
"short": "Anna-Varney"
}
}
So the many to many fields must use the pk integer, but the problem is that the data isn't sorted and for a long list of actors I don't think its practical to manually look up the pk of each one. I've been looking for solutions and it seems I have to use natural keys, but I'm not exactly sure how to apply those for my models.
EDIT: I've changed my models to be:
class PersonManager(models.Manager):
def get_by_natural_key(self, full):
return self.get(full=full)
class Person(models.Model):
objects = PersonManager()
full = models.TextField()
short = models.TextField()
num = models.CharField(max_length=5)
def natural_key(self):
return self.full
But I'm still getting the same error
There's a problem with both the input and the natural_key method.
Documentation: Serializing Django objects - natural keys states:
A natural key is a tuple of values that can be used to uniquely
identify an object instance without using the primary key value.
The Person natural_key method should return a tuple
def natural_key(self):
return (self.full,)
The serialised input should also contain tuples/lists for the natural keys.
{
"pk": 1,
"model": "data.film",
"fields": {
"actors": [
[
"Matt Damon"
],
[
"Jodie Foster"
]
],
"name": "Elysium",
"year": 2013
}
}