Saving json data to a Django model

14,776

Solution 1

If the answers you get from the consumption of Google's API contains different attributes in each query and you want to store them all, then you have to use a JSONField:

from django.db import models
from django.core.serializers.json import DjangoJSONEncoder
import json

class JSONField(models.TextField):
    """
    JSONField es un campo TextField que serializa/deserializa objetos JSON.
    Django snippet #1478

    Ejemplo:
        class Page(models.Model):
            data = JSONField(blank=True, null=True)

        page = Page.objects.get(pk=5)
        page.data = {'title': 'test', 'type': 3}
        page.save()
    """
    def to_python(self, value):
        if value == "":
            return None

        try:
            if isinstance(value, str):
                return json.loads(value)
        except ValueError:
            pass
        return value

    def from_db_value(self, value, *args):
        return self.to_python(value)

    def get_db_prep_save(self, value, *args, **kwargs):
        if value == "":
            return None
        if isinstance(value, dict):
            value = json.dumps(value, cls=DjangoJSONEncoder)
        return value

In your models.py:

class Book(Model.models):
    info = JSONField(null=True, blank=True)
    ...

In your views.py:

 ...
 book.info = json.loads(r.content)
 book.save()

But if you need to save always the same attributes, in your case title, description, author_name and genres:

Book.objects.create(title = r['items'][0-2]['volumeInfo']['title'], description = r['items'][2]['volumeInfo']['description'], ......)

Solution 2

Django uses ORM (Object-relational mapping). hence a models.Model instance will be translated to SQL by 'manage.py makemigrations' command.

so you can see if the database you work with has this field.

in Postgresql you can use JSON field. some other databases may have this field to.

for Postgresql you can visit: JSONField for PostgreSQL

and for MYSQL: JSONField for MySQL


your error: on: Books.objects.save(**book_info) first of all ** on a dictionary in python, turn it like this:

Books.objects.save(genere='genere', author='author name', ....)

what a text field does is saving text what is text? is a long limitless string how to turn dictionary to string? call json.dumps(dictionary)

take the returned value to save on your text field.

how to make dictionary again from string? call json.loads(string) and the result is the dictionary.

there are some limits too you will see like dumping datetime or numpy ndarray ...

Share:
14,776
Rafalpero
Author by

Rafalpero

Updated on June 10, 2022

Comments

  • Rafalpero
    Rafalpero about 2 years

    I'm trying to save json data to a model. I'm getting all the data i need, how do i save them to a model?

    views.py

    def book_api(request):
    if request.method == 'POST':
        search = request.POST['textfield']
        url = 'https://www.googleapis.com/books/v1/volumes?q=' + search
        print(url)
        r = requests.get(url).json()
        book_info = {
            'title': r['items'][0-2]['volumeInfo']['title'],
            'description': r['items'][2]['volumeInfo']['description'],
            'author_name': r['items'][0-2]['volumeInfo']['authors'],
            'genres': r['items'][0-2]['volumeInfo']['categories'],
    
        }
        print(book_info)
    
        return redirect('index')
    else:
        return render(request, 'api/book_api.html')
    

    models.py

    class Genres(models.Model):
        genres = models.CharField(max_length=200)
    
        def __str__(self):
            return self.genres
    
    
    class Authors(models.Model):
        author_name = models.CharField(max_length=200)
    
        def __str__(self):
            return self.author_name
    
    
    class Books(models.Model):
        title = models.CharField(max_length=300)
        description = models.TextField()
        authors = models.ForeignKey(Authors, on_delete=models.CASCADE)
        genres = models.ForeignKey(Genres, on_delete=models.CASCADE)
    
        def __str__(self):
          return self.title
    

    Was trying to do Books.objects.save(**book_info) but it raises a error

    'Manager' object has no attribute 'save'