Using Django Rest Framework with ForeignKey's - json

I am trying to use the django rest framework to create a Module model, but I can't get the JSON formatted correctly.
I create a lecture and a lab and then try to make a module with the lecture and lab. But I get an error (Cannot add "": instance is on database "default", value is on database "None")
Here is what I am trying for the JSON content.
{
"title": "First Module",
"labs": [
{
"title": "First Lab",
"duration": 10.0,
"description": "This is the first lab."
}
],
"lectures": [
{
"title": "First Lecture",
"duration": 0.0,
"description": "This is the first lecture."
}
]
}
class Lab(models.Model):
title = models.CharField(max_length=255)
duration = models.FloatField(help_text=_("Duration of Lab in Hours"), blank=True, null=True)
description = models.TextField(null=True, blank=True)
def __unicode__(self):
return self.title
class Lecture(models.Model):
title = models.CharField(max_length=255)
duration = models.FloatField(help_text=_("Duration of Lecture in Hours"), blank=True, null=True)
description = models.TextField(null=True, blank=True)
def __unicode__(self):
return self.title
class Module(models.Model):
title = models.CharField(max_length=255)
labs = models.ManyToManyField(Lab, related_name='modules', blank=True, null=True)
lectures = models.ManyToManyField(Lecture, related_name='modules', blank=True, null=True)
def __unicode__(self):
return self.title
class LabSerializer(serializers.ModelSerializer):
class Meta:
model = Lab
fields = ('title', 'duration', 'description')
class LectureSerializer(serializers.ModelSerializer):
class Meta:
model = Lecture
fields = ('title', 'duration', 'description')
class ModuleSerializer(serializers.ModelSerializer):
labs = LabSerializer(many=True, required=False)
lectures = LectureSerializer(many=True, required=False)
class Meta:
model = Module
fields = ('title', 'labs', 'lectures')
Traceback:
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/django/views/generic/base.py" in view
69. return self.dispatch(request, *args, **kwargs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
57. return view_func(*args, **kwargs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
400. response = self.handle_exception(exc)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
397. response = handler(request, *args, **kwargs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/rest_framework/generics.py" in post
468. return self.create(request, *args, **kwargs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/rest_framework/mixins.py" in create
54. self.object = serializer.save(force_insert=True)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/rest_framework/serializers.py" in save
596. self.save_object(self.object, **kwargs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/rest_framework/serializers.py" in save_object
995. setattr(obj, accessor_name, object_list)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/django/db/models/fields/related.py" in __set__
840. manager.add(*value)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/django/db/models/fields/related.py" in add
581. self._add_items(self.source_field_name, self.target_field_name, *objs)
File "/home/siecje/virtualenv/ccafe/local/lib/python2.7/site-packages/django/db/models/fields/related.py" in _add_items
640. (obj, self.instance._state.db, obj._state.db))
Exception Type: ValueError at /modules/
Exception Value: Cannot add "<Lab: First Lab>": instance is on database "default", value is on database "None"

Related

How may I convert a Many to Many field into JSON Format in Django

I am working with APIs based in REST Architecture. I know Django has a framework to work with this APIs but my homework is do it from scratch. I got an API of a movies site where users can go and search information about a bunch of movies and i am trying to get the data into JSON format from the model Movie which has a Many-to-Many relationship whith the Actor model. I am using Class-based views for this.
The code from my models.py and views.py files is nested below:
class Actor(models.Model):
full_name = models.CharField(max_length=125)
role = models.CharField(max_length=125)
def __str__(self):
return self.full_name
class Movie(models.Model):
ACTION = 'AC'
DRAMA = 'DR'
COMEDY = 'CM'
SCIENCE_FICTION = 'SF'
THRILLER = 'TR'
RELIGIOUS = 'RG'
GENRE_CHOICES = [
(ACTION, 'Accion'),
(DRAMA, 'Drama'),
(COMEDY, 'Comedy'),
(SCIENCE_FICTION, 'Ciencia Ficcion'),
(THRILLER, 'Triler'),
(RELIGIOUS, 'Religioso')
]
title = models.CharField(max_length=155, blank=False)
synopsis = models.TextField(max_length=1000, blank=True)
genre = models.CharField(max_length=100, choices=GENRE_CHOICES, default='', blank=False)
tag = models.JSONField(default=dict, blank=True)
actors = models.ManyToManyField(Actor, related_name='movies', blank=True)
def __str__(self):
views.py
from django.views import View
from django.http.response import JsonResponse
from .models import Movie
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
import json
class MovieView(View):
#method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request, pk=0):
"""
Return the list of all movies, or a single movie
:param pk:
:param request:
:return:
"""
if pk > 0:
movies = list(Movie.objects.filter(pk=pk).values())
if len(movies) > 0:
movie = movies[0]
data = {'message': "Success", 'movie': movie}
else:
data = {'message': "Movie not found... "}
return JsonResponse(data)
else:
movies = list(Movie.objects.values('title', 'synopsis', 'genre', 'actors__full_name').order_by('pk'))
if len(movies) > 0:
data = {'message': "Success", 'movies': movies}
else:
data = {'message': "Movies not found ..."}
return JsonResponse(data)
def post(self, request):
"""
Create a new movie
:param request:
:return:
"""
json_data = json.loads(request.body)
Movie.objects.create(title=json_data['title'], synopsis=json_data['synopsis'], genre=json_data['genre'],
tag=json_data['tag'], actors=json_data['actors'])
data = {'message': "Success"}
return JsonResponse(data)
def put(self, request, pk):
"""
Update a single movie
:param request:
:param pk:
:return:
"""
json_data = json.loads(request.body)
movies = list(Movie.objects.filter(pk=pk).values())
if len(movies) > 0:
movie = Movie.objects.get(pk=pk)
movie.title = json_data['title']
movie.synopsis = json_data['synopsis']
movie.genre = json_data['genre']
movie.tag = json_data['tag']
movie.save()
data = {'message': "Success"}
else:
data = {'message': "Movie not found ..."}
return JsonResponse(data)
def delete(self, request, pk):
movies = list(Movie.objects.filter(pk=pk).values())
if len(movies) > 0:
Movie.objects.filter(pk=pk).delete()
data = {'message': "Success"}
else:
data = {'message': "Movie not found ..."}
return JsonResponse(data)

`category` and `tag` shared by multiple wagtail page types

I have a Django+Wagtail website, and have category and tag created to be applied to blog posts.
from taggit.models import Tag as TaggitTag
from taggit.models import TaggedItemBase
class PostList(RoutablePageMixin, Page):
template = "Post_List.html"
intro = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel("intro")
]
subpage_types = [
"PostDetail",
]
parent_page_type = [
"HomePage",
]
# Each 'search / category / tag / author' will generate a separate 'PostList' page with its own 'context',
# hence for 'Pagination' for all 'PostList' pages, we only need to implement in 'get_context()'
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
# For Pagination
page_id = request.GET.get("page")
paginator = Paginator(self.posts, 3) # 'posts' is defined in 'def post_list()' and 'def get_posts()' as below.
try:
paginator_page = paginator.page(page_id)
except PageNotAnInteger:
paginator_page = paginator.page(1)
page_id = 1
except EmptyPage:
paginator_page = paginator.page(1)
page_id =1
context['paginator_page'] = paginator_page
context['total_num_pages'] = paginator.num_pages
# By default, Paginator.get_elided_page_range(number, *, on_each_side=3, on_ends=2)
context['elided_page_range'] = paginator.get_elided_page_range(page_id, on_each_side=5, on_ends=2)
return context
def get_posts(self):
return PostDetail.objects.descendant_of(self).live()
#route(r'^tag/(?P<tag>[-\w]+)/$')
def post_by_tag(self, request, tag, *args, **kwargs):
self.search_type = 'tag'
self.search_term = tag
self.posts = self.get_posts().filter(tags__name=tag)
return Page.serve(self, request, *args, **kwargs)
#route(r'^category/(?P<category>[-\w]+)/$')
def post_by_category(self, request, category, *args, **kwargs):
self.search_type = 'category'
self.search_term = category
self.posts = self.get_posts().filter(categories__category__name=category)
return Page.serve(self, request, *args, **kwargs)
#route(r'^user/(?P<user>[-\w]+)/$')
def post_by_user(self, request, user, *args, **kwargs):
self.search_type = 'user'
self.search_term = user
self.posts = self.get_posts().filter(owner__username=user)
return Page.serve(self, request, *args, **kwargs)
#route(r'^$')
def post_list(self, request, *args, **kwargs):
self.posts = self.get_posts()
return Page.serve(self, request, *args, **kwargs)
#route(r'^search/$')
def post_search(self, request, *args, **kwargs):
search_query = request.GET.get('q', None)
self.posts = self.get_posts()
if search_query:
self.posts = self.posts.filter(body__contains=search_query)
self.search_term = search_query
self.search_type = 'search'
return Page.serve(self, request, *args, **kwargs)
class PostDetail(Page):
template = "Post_Detail.html"
body = MarkdownField()
tags = ClusterTaggableManager(through="PostDetailTag", blank=True)
#register_snippet
class Category(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=100)
panels = [
FieldPanel("name"),
FieldPanel("slug"),
]
def __str__(self):
return self.name
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ["name"]
#register_snippet
class Tag(TaggitTag):
class Meta:
proxy = True
# Intermediate Models for ManyToMany Relationship
class PostDetailCategory(models.Model):
post = ParentalKey("PostDetail", on_delete=models.CASCADE, related_name="categories")
category = models.ForeignKey("Category", on_delete=models.CASCADE, related_name="post_details")
panels = [
SnippetChooserPanel("category"),
]
class Meta:
unique_together = ("post", "category")
class PostDetailTag(TaggedItemBase):
content_object = ParentalKey("PostDetail", on_delete=models.CASCADE)
Now, I am about to creating another wagtail page type "SurveyPoll", and want to have tag and category applied as well.
What is the best practice for this deployment, same tag and category applied to different wagtail page types via ManyToMany relationship ?
Which type of ManyToMany relationship deployment is better, tag or category ? Personally, I prefer the category way as it allows me to choose from a list of existing category in wagtail admin edit page.

How to serialize json to sql?

I have a list of words and I should send requests to an API and get the information about the words. I want to convert the API data which is in JSON format to SQL(my DB is PostgreSQL) format in Django. How can I do that? Do you know any good source to learn to serialize json to sql?
I have just started learning Django.
It is the API's JSON data:
[
{
"word": "hello",
"phonetics": [
{
"text": "/həˈloʊ/",
"audio": "https://lex-audio.useremarkable.com/mp3/hello_us_1_rr.mp3"
},
{
"text": "/hɛˈloʊ/",
"audio": "https://lex-audio.useremarkable.com/mp3/hello_us_2_rr.mp3"
}
],
"meanings": [
{
"partOfSpeech": "exclamation",
"definitions": [
{
"definition": "Used as a greeting or to begin a phone conversation.",
"example": "hello there, Katie!"
}
]
},
{
"partOfSpeech": "noun",
"definitions": [
{
"definition": "An utterance of “hello”; a greeting.",
"example": "she was getting polite nods and hellos from people",
"synonyms": [
"greeting",
"welcome",
"salutation",
"saluting",
"hailing",
"address",
"hello",
"hallo"
]
}
]
},
{
"partOfSpeech": "intransitive verb",
"definitions": [
{
"definition": "Say or shout “hello”; greet someone.",
"example": "I pressed the phone button and helloed"
}
]
}
]
}
]
this is my models.py:
class Words(models.Model):
word = models.CharField(max_length=50)
american_phonetic= models.CharField(max_length=50)
american_audio= models.URLField(max_length = 200)
british_phonetic= models.CharField(max_length=50)
british_audio= models.URLField(max_length = 200)
###########################################################################
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
birth_date = models.DateField('birth date')
field= models.CharField(max_length=50)
location = models.CharField(max_length=30, blank=True)
interest= models.IntegerField() # for example : 1 for science , 2 for art , 3 for sport etc.
education= models.IntegerField() # for example : 1 for highschool , 2 for bachelor , 3 for master and 4 for phd
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
class UserLearned(models.Model):
Profile_id = models.ForeignKey(Profile, on_delete=models.CASCADE)
word_id = models.ForeignKey(Words, models.SET_NULL, blank=True, null=True,)
def __str__(self):
return self.word_id
############################################################################
class Meanings(models.Model):
word_id = models.ForeignKey(Words, on_delete=models.CASCADE)
partOfSpeech = models.CharField(max_length=30)
class Definitions(models.Model):
word_id = models.ForeignKey(Words, on_delete=models.CASCADE)
Meaning_id = models.OneToOneField(Meanings, on_delete=models.CASCADE, primary_key=True)
definition = models.TextField()
def __str__(self):
return self.definition
class Examples(models.Model):
word_id = models.ForeignKey(Words, on_delete=models.CASCADE)
Meaning_id = models.OneToOneField(Meanings, on_delete=models.CASCADE, primary_key=True)
example = models.TextField()
def __str__(self):
return self.example
class Synonyms(models.Model):
word_id = models.ForeignKey(Words, on_delete=models.CASCADE)
Meaning_id = models.ForeignKey(Meanings, on_delete=models.CASCADE)
synonym = models.CharField(max_length=50)
def __str__(self):
return self.synonym
You can use the json library to serialise the json data and vice versa (use json.loads() & json.dumps() methods).
For Example:
import json
data = "{'name': 'Jack', 'age': 30}" #json data
python_dict = json.loads(data) #now it is a python dict
Now you can directly assign the values of the python dict to any model attributes in Django.
Following are some good sources to start learning the library:
https://www.w3schools.com/python/python_json.asp
https://docs.python.org/3/library/json.html

Return nested JSON from Models with relations in Django

models.py (simplified)
class Author(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
def get_books(self):
return Book.objects.filter(author=self.pk)
class Book(models.Model):
name = models.CharField(max_length=255)
pages = models.IntegerField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return f'{self.name} from {self.author}'
class Paragraph(models.Model):
name = models.CharField(max_length=255)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
def __str__(self):
return f'{self.name} from {self.book}'
I want to return all the instances in a json file with this structure:
[
{
"name": 'Dumas',
"books": {
"name": "The count of Montecristo",
"paragraphs": {
"name": "paragraph_name_1",
},
{
"name": "paragraph_name_2",
},
{
"name": "The three Musketeers",
"paragraphs": {
"name": "paragraph_name",
},
]
What I tried:
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
books = serializers.CharField(source='get_books', read_only=True)
class Meta:
model = Author
fields = ['name', 'books']
This add the books key but the value is the string representation of the istances of Book (of course), how I make the value being the serialized istances of Book? I have created a BookSerializer.
Notes:
I know that I can created a nested json by creating a serializer for Paragraph with depth = 2 but this will include fields I don't want (like pages in Book) and the json structure will be totally different.
You can create nested serializer as
class ParagraphSerializer(serializers.ModelSerializer):
class Meta:
model = Paragraph
fields = ("name",)
class BookSerializer(serializers.ModelSerializer):
paragraphs = ParagraphSerializer(source="paragraph_set", many=True, read_only=True)
class Meta:
model = Book
fields = ("name", "paragraphs")
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(source="book_set", read_only=True, many=True)
class Meta:
model = Author
fields = ['name', 'books']

django rest api json data category subcategory

I am trying to access subcategories according to parent id. When i am checking subcategories api it's showing all data with all parent id. I am unable to filter subcategories according to parent id. I am trying to get json data according to parent id.
If our parent id is 7 so i need all subcategories which one's has parent id 7. Please guide how i can do its.
models.py
class Category(models.Model):
name = models.CharField(max_length=254, unique=True)
status = models.BooleanField(default=True)
def __str__(self):
return self.name
class SubCategory(models.Model):
name = models.CharField(max_length=254, unique=True)
id_parent = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
price = models.IntegerField()
status = models.BooleanField(default=True)
def __str__(self):
return self.name
json
[
{
"id": 1,
"name": "IT Servic",
"price": 2000,
"status": true,
"id_parent": 7
},
{
"id": 2,
"name": "Web Development",
"price": 1000,
"status": true,
"id_parent": 8
},
{
"id": 3,
"name": "Digital Marketing",
"price": 3000,
"status": true,
"id_parent": 7
},
{
"id": 4,
"name": "RO Repair",
"price": 3444,
"status": true,
"id_parent": 9
}
]
serializers.py
class CategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Category
fields = '__all__'
class SubCategorySerializer(serializers.ModelSerializer):
class Meta:
model = SubCategory
fields = '__all__'
lookup_field = 'id_parent'
views.py*
class CategoryViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = CategorySerializer
def get_queryset(self):
user = self.request.user
if user.is_authenticated:
if user is not None:
if user.is_active and user.is_superuser:
return Category.objects.all()
raise PermissionDenied()
raise PermissionDenied()
raise PermissionDenied()
class SubCategoryViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
if user.is_authenticated:
if user is not None:
if user.is_active and user.is_superuser:
return SubCategory.objects.all()
raise PermissionDenied()
raise PermissionDenied()
raise PermissionDenied()
serializer_class = SubCategorySerializer
You should take a look at filtering.
Basically, you can either do your filtering "manually" in the get_queryset()
def get_queryset(self):
id_parent = self.request.query_params.get('id_parent')
queryset = super().get_queryset()
if id_parent:
queryset = queryset.filter(id_parent=id_parent)
return queryset
Or use a third-party library such as django-filter
you can add a custom action to your viewset like this, assuming you can set the appropriate urls/routes
#action(detail=False, methods=['GET'])
def get_sub_categories(self, request, *args, **kwargs):
category_id = self.request.query_params.get("category_id", None)
queryset = self.get_queryset()
filtered_sub_categories = queryset.filter(id_parent=category_id)
serializer = self.get_serializer(filtered_sub_categories, many=True)
return Response(serializer.data)