Models.py
from django.db import models
# Create your models here.
class reviewData(models.Model):
building_name = models.CharField(max_length=50)
review_content = models.TextField()
star_num = models.FloatField()
class buildingData(models.Model):
building_name = models.CharField(max_length=50)
building_loc = models.CharField(max_length=50)
building_call = models.CharField(max_length=20)
views.py
# Create your views here.
from django.shortcuts import render
from rest_framework.response import Response
from .models import reviewData
from .models import buildingData
from rest_framework.views import APIView
from .serializers import ReviewSerializer
class BuildingInfoAPI(APIView):
def get(request):
queryset = buildingData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
class ReviewListAPI(APIView):
def get(request):
queryset = reviewData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
urls.py
from django.contrib import admin
from django.urls import path
from crawling_data.views import ReviewListAPI
from crawling_data.views import BuildingInfoAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('api/buildingdata/', BuildingInfoAPI.as_view()),
#path('api/buildingdata/(I want to put building name here)', ReviewListAPI.as_view())
]
I am making review api.
I want to use building name as url path to bring reviews for specific buildings
For example, there are a, b, c reviews
a, b reviews are for aaabuilding
c reviews are for xxxbuilding
api/buildingdata/aaabuilding (only shows aaabuilding review)
{
building_name = aaabuilding
review_content = a
star_num = 5
building_name = aaabuilding
review_content = b
star_num = 3
}
api/buildingdata/xxxbuilding (only shows xxxbuilding review)
{
building_name = xxxbuilding
review_content = c
star_num = 4
}
I've searched some dynamic URL posts, but they were not that I want.
Also, I've posted a question before but there was no answer I was looking for.
Is there any way to bring building name into URL from db?
Please refer to the documentation on path converters. And usage of django's slugify function.
In your situation you will want a slug - but there are limitations to using a slug:
slugs must translate to some unique string, in your case building name. Therefore you should make sure that building name and slug are unique in your model.
You should add a slug field to the model - and also change the review model so it foreign keys to the building model:
from django.utils.text import slugify
class buildingData(models.Model):
building_name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
building_loc = models.CharField(max_length=50)
building_call = models.CharField(max_length=20)
def save(self, *args, **kwargs):
self.slug = slugify(self.building_name)
return super().save(*args, **kwargs)
class reviewData(models.Model):
building = models.ForeignKey(buildingData, related_name='reviews', on_delete=models.CASCADE, null=False, blank=False)
review_content = models.TextField()
star_num = models.FloatField()
Then in your urls.py:
path('api/buildingdata/<slug:slug>/', ReviewListAPI.as_view())
Then in your Views.py:
class ReviewListAPI(APIView):
def get(self, request):
building = get_object_or_404(buildingData, slug=self.kwargs.get('slug')
queryset = building.reviews.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
Also review pep8 - your class names should really be BuildingData and ReviewData - and you problably dont need Data in the names either.
Related
I'm building an API using DRF, and as I am a beginner, I can't get my head across this.
I'm building an instagram clone using DRF and was able to attach comments and likes to each post object, but I can only attach likes and comments using the admin panel. I can see the total number of likes/comments and the user who added them as JSON Output though. Is there a way to add an add comment_form to the post_detail view?
Here's my models.py file
from __future__ import unicode_literals
import uuid
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
# Create your models here.
class Createpost(models.Model):
id = models.UUIDField(
primary_key = True,
default=uuid.uuid4,
editable= False,
)
author = models.ForeignKey(User , on_delete=models.CASCADE)
title = models.CharField(max_length=50)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
post_image = models.ImageField(upload_to='images/',blank=True)
#property
def total_likes(self):
return Like.objects.filter(post_id = self.id).count()
#property
def likes(self):
array = []
for like in Like.objects.filter(post_id = self.id):
array.append(like.author.username)
return array
#property
def total_comments(self):
return Answers.objects.filter(post_id = self.id).count()
#property
def comments(self):
array = []
for comment in Answers.objects.filter(post_id = self.id):
c = {}
c['body'] = comment.body
c['username'] = comment.author.username
c['created_at'] = comment.created_at
array.append(c)
return array
def __str__(self):
return self.title
class Answers(models.Model):
post = models.OneToOneField(
Createpost,
primary_key=True,
on_delete = models.CASCADE,
)
body = models.TextField()
author = models.ForeignKey(User,on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
Updated_At = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=False)
def __str__(self):
return 'Comment {} by {} '.format(self.body,self.author)
class Like(models.Model):
post = models.OneToOneField(
Createpost,
primary_key=True,
on_delete = models.CASCADE,
)
author = models.ForeignKey(User,on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ('post','author',)
Here's my Views.py file:
from django.shortcuts import render
from rest_framework import generics
from .models import Createpost
from .permissions import IsAuthorOrReadOnly
from .serializers import PostSerializer,PostDetailSerializer,CommentSerializer
# Create your views here.
class PostList(generics.ListCreateAPIView):
queryset = Createpost.objects.all()
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthorOrReadOnly,)
queryset = Createpost.objects.all()
serializer_class = PostDetailSerializer
Here's my serializers.py file:
from rest_framework import status
from rest_framework import serializers
from rest_framework.decorators import APIView
from .models import Createpost,Answers
from django.contrib.auth.models import User
class PostSerializer(serializers.ModelSerializer):
totallikes = serializers.ReadOnlyField(source = 'total_likes')
totalcomments = serializers.ReadOnlyField(source = 'total_comments')
class Meta:
fields = ('id','author','title','body','created_at','totallikes','totalcomments')
model = Createpost
class CommentSerializer(serializers.Serializer):
field1 = serializers.CharField()
class PostDetailSerializer(serializers.ModelSerializer):
li_kes = serializers.ReadOnlyField(source = 'likes')
com_ments = serializers.ReadOnlyField(source = 'comments')
class Meta:
fields = ('id','author','title','body','created_at','updated_at','post_image','li_kes','com_ments',)
model = Createpost
I don't see a comment model in your code, so it's hard to know exactly how you're going about this. But one pattern for adding comments to a post object would to create an endpoint that accepts the comment details in the request and saves them to the post. Something like:
from rest_framework import viewsets, status
class PostComment(viewsets.ModelViewSet):
""" API endpoint for adding comments to posts """
def create(self, request):
Data = request.data
payload = {'post': Data['post_id'], 'user': self.request.user.id, 'comment': Data['comment']]}
post = UserPost.objects.get(uniqueID=Data['post_id'])
payload['post'] = post.id
serializer = UserCommentReplyPOSTSerializer(data=payload)
if serializer.is_valid():
serializer.save()
return Response('Comment saved', status=status.HTTP_200_OK)
else:
print(serializer.errors)
return Response('There was a problem with your request', status=status.HTTP_400_BAD_REQUEST)
You would then register this endpoint in your urls.py and use it in your front-end comment POST routine.
Obviously you'd need a Comment model with a foreign key to to your Post model for this to work. I'm assuming you have that and didn't show it.
If I'll send get request like thisenter image description here, i need to have multiple pagination (LimitOffset and PageNumber).
models.py:
from django.db import models
class Products(models.Model):
title = models.CharField(max_length=255)
description = models.TextField(blank=True)
photo = models.ImageField(upload_to="photos/%Y/%m/%d/", null=True)
hashtag = models.CharField(max_length=255)
is_hit = models.BooleanField(default=False)
category = models.ForeignKey('Category', on_delete=models.PROTECT, null=True)
def __str__(self):
return self.title
class Category(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
views.py:
from rest_framework import generics
from rest_framework.pagination import PageNumberPagination
from .models import *
from .serializers import ProductsSerializer
class PaginationProducts(PageNumberPagination):
page_size = 2
page_size_query_param = 'page_size'
max_page_size = 2
class ProductsAPIList(generics.ListCreateAPIView):
queryset = Products.objects.all()
serializer_class = ProductsSerializer
pagination_class = PaginationProducts
serializers.py
from rest_framework import serializers
from .models import *
class ProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Products
fields = "__all__"
def get_photo_url(self, obj):
request = self.context.get('request')
photo_url = obj.fingerprint.url
return request.build_absolute_uri(photo_url)
I need something that can help API client choose number of page and quantity of posts on that page. Think that in this case i need NumberPagePagination and LimitOffsetPagination.
I think you don't need to create the custom pagination class.
from rest_framework.pagination import LimitOffsetPagination
class ProductsAPIList(generics.ListCreateAPIView):
queryset = Products.objects.all()
serializer_class = ProductsSerializer
pagination_class = LimitOffsetPagination
The offset value corresponds to the page * size in the original pagination and the limit value corresponds to the size.
I am making API with Django.
Crawled data is saved well in DB, but I have a problem with making API.
views.py
from django.shortcuts import render
from rest_framework.response import Response
from .models import ReviewData
from .models import BuildingData
from rest_framework.views import APIView
from .serializers import ReviewSerializer
from .serializers import BuildingSerializer
from django.shortcuts import render, get_object_or_404
class BuildingInfoAPI(APIView):
def get(request):
queryset = BuildingData.objects.all()
serializer = BuildingSerializer(queryset, many=True)
return Response(serializer.data)
class ReviewListAPI(APIView):
def get(request):
queryset = ReviewData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
urls.py
from django.contrib import admin
from django.urls import path
from crawling_data.views import ReviewListAPI
from crawling_data.views import BuildingInfoAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('api/buildingdata/', BuildingInfoAPI.as_view()),
path('api/buildingdata/<slug:slug>/', ReviewListAPI.as_view())
]
serializers.py
from rest_framework import serializers
from .models import ReviewData
from .models import BuildingData
class BuildingSerializer(serializers.ModelSerializer) :
class Meta :
model = BuildingData
fields = '__all__'
class ReviewSerializer(serializers.ModelSerializer) :
class Meta :
model = ReviewData
fields = '__all__'
models.py
from django.db import models
import uuid
# Create your models here.
from django.utils.text import slugify
def generate_unique_slug(klass, field):
origin_slug = slugify(field, allow_unicode=True)
unique_slug = origin_slug
numb = 1
while klass.objects.filter(slug=unique_slug).exists():
unique_slug = '%s-%d' % (origin_slug, numb)
numb += 1
return unique_slug
class BuildingData(models.Model):
building_name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True, allow_unicode=True, default=uuid.uuid1)
building_loc = models.CharField(max_length=50)
building_call = models.CharField(max_length=20)
building_time = models.CharField(max_length=50)
def save(self, *args, **kwargs):
if self.slug: # edit
if slugify(self.building_name, allow_unicode=True) != self.slug:
self.slug = generate_unique_slug(BuildingData, self.building_name)
else: # create
self.slug = generate_unique_slug(BuildingData, self.building_name)
super(BuildingData, self).save(*args, **kwargs)
'''
def save(self, *args, **kwargs):
self.slug = slugify(self.building_name, allow_unicode=True)
try:
return super().save(*args, **kwargs)
except:
print(f"the repeated slug is: `{self.slug}`")
raise
'''
class ReviewData(models.Model):
#building = models.ForeignKey(BuildingData, related_name='reviews', on_delete=models.CASCADE, null=False, blank=False)
building_name = models.CharField(max_length=50)
review_content = models.TextField()
star_num = models.FloatField()
I think there's no problem with models.
But I can't find which makes get() error.
And I think error from(api/buildingdata/) prevents making slug url(api/buildingdata//) pages. (It says page not found when I enter slug url)
Is there any problem with my code?
add self parameter to your get method like this:def get(self,request) or just use generic views more clear and DRY.
I am a beginner in Django. Right now, I am working with the APIs. I am facing a problem. I can't view one of the fields, called label, at http://127.0.0.1:8000/gameapi/. Here is the screenshot:
Here are my codes of serializers.py located inside gamreview folder.
from rest_framework import serializers
from .models import Game, Tags
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tags
fields = ['label']
class GameSerializer(serializers.ModelSerializer):
# label_tag = TagSerializer(many=True)
class Meta:
model = Game
fields = ['id', 'title', 'developer', 'platform']
fields = ['id', 'title', 'developer', 'platform','label_tag']
def create(self, validated_data):
label_tag_data = validated_data.pop('label_tag')
game = Game.objects.create(**validated_data)
for tags_data in label_tag_data:
Tags.objects.create(game=game, **tags_data)
return Game.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.title = validated_data.get('title', instance.title)
instance.developer = validated_data.get('developer', instance.developer)
instance.platform = validated_data.get('platform', instance.platform)
instance.tag = TagSerializer(read_only=True, many=True)
instance.save()
return instance
Here are my codes of models.py under gamreview folder:
from django.db import models
from django.template.defaultfilters import slugify
# Create your models here.
class Tags(models.Model):
label = models.CharField(max_length=20)
def __str__(self):
return self.label
class Game(models.Model):
title = models.CharField(max_length=100)
developer = models.CharField(max_length=100)
platform = models.CharField(max_length=50, default='null')
label_tag = models.ManyToManyField(Tags)
slug = models.SlugField(max_length=150, default='null')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)
class Review(models.Model):
game = models.ForeignKey(Game, on_delete=models.CASCADE)
review = models.CharField(max_length=1000)
date = models.DateField(auto_now=True)
slug = models.SlugField(max_length=150, default='null')
def __str__(self):
return self.game
Here are my codes of views.py under gamreview folder:
from django.views import generic
from .models import Game
from rest_framework import generics
from .serializers import GameSerializer
# Create your views here.
class GameListView(generic.ListView):
template_name = 'gamereview/gamelist.html'
context_object_name = 'all_games'
def get_queryset(self):
return Game.objects.all()
class ReviewView(generic.DetailView):
model = Game
template_name = 'gamereview/review.html'
# class GameApiView(generics.ListAPIView):
class GameApiView(generics.ListCreateAPIView):
queryset = Game.objects.all()
serializer_class = GameSerializer
class GameDetailApiView(generics.RetrieveUpdateDestroyAPIView):
queryset = Game.objects.all()
serializer_class = GameSerializer
Here are my codes of urls.py under gamreview folder:
from . import views
from django.urls import path
app_name = 'gamereview'
urlpatterns = [
path('gamereview/', views.GameListView.as_view(), name='gamelist'),
path('gamereview/<slug:slug>/', views.ReviewView.as_view(), name='review'),
path('gameapi/', views.GameApiView.as_view(), name='gamelistapi'),
path('gameapi/<int:pk>/', views.GameDetailApiView.as_view()),
]
I don't get any error while running the server. However, the label field is not showing up.
How can I fix the issue?
You have declared fields twice in GameSerializer- Meta class. Delete the first one.
class GameSerializer(serializers.ModelSerializer):
# label_tag = TagSerializer(many=True)
class Meta:
model = Game
fields = ['id', 'title', 'developer', 'platform'] --> delete this
fields = ['id', 'title', 'developer', 'platform','label_tag']
Django rest framework relies on related_name attribute to the resolve foreign key fields.
I think just changing your Game model so would do it
label_tag = models.ManyToManyField(Tags, related_name="label")
I am building an django rest api for saving/managing customer data for my project. I have two models. Customer for storing basic customer
details and CustomerDetails for storing a bunch of customer details. I want to write a single api to create/update data for both the models.
How can I do this?
models.py
class Customer(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=20)
address = models.CharField(max_length=50)
city = models.CharField(max_length=256)
"""some more fields to go"""
# Create your models here.
class CustomerDetails(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
customer = models.ForeignKey(Customer, db_index=True, on_delete=models.CASCADE,
related_name='customer_details',
default=0)
spouse_name = models.CharField(max_length=256)
interests = models.CharField(max_length=256)
"""many more fields to go"""
views.py
import pprint
from .models import Customer, CustomerDetails
from oauth2_provider.ext.rest_framework import TokenHasReadWriteScope, TokenHasScope
from rest_framework import permissions, viewsets
from .serializers import CustomerSerializer, CustomerDetailsSerializer
from django.contrib import admin
from rest_framework import generics
admin.autodiscover()
# Create your views here.
# ViewSets define the view behavior.
class CustomerViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, TokenHasReadWriteScope]
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class CustomerCreateAPIView(generics.CreateAPIView):
model = Customer
serializer_class = CustomerSerializer
serializers.py
from rest_framework import serializers
from models import Customer, CustomerDetails
class CustomerDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = CustomerDetails
fields = ('spouse_name',)
class CustomerSerializer(serializers.ModelSerializer):
customer_details = CustomerDetailsSerializer()
class Meta:
model = Customer
fields = ('name', 'city', 'customer_details')
urls.py
router = routers.SimpleRouter(trailing_slash=False)
router.register(r'customer', views.CustomerViewSet, 'customers')
urlpatterns = [
url(r'^', include(router.urls))
]
My suggestion
Views.py
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
class CustomerProfile(APIView):
parser_classes = (MultiPartParser, FormParser,) # File upload
def post(self, request, pk=None, format=None):
data = request.data
required_fields = ['name'] # required fields
for field in required_fields:
if field not in data.keys():
return JSONResponse({'status':"error", "field_name":field, "message":"{0} field required" .format(field) })
elif not data.get(field):
return JSONResponse({'status':"error", "field_name":field, "message":"{0} field not empty" .format(field) })
## Validate
if pk:
try:
customer = Customer.objects.get(id=pk)
except Customer.DoesNotExist:
pass # Return Error
else:
customer = Customer.objects.create(name=data['address'], city=data['city'], name=data['name'])
cd = CustomerDetails.objects.create(customer=customer,....)
return JSONResponse({'status':"success", "message":"Successfully updated profile",'full_name':artist.full_name, 'detial':detail_url})
urls.py
from apps.sample import views
url(r'^api/v1/customer/$', views.CustomerProfile.as_view()), ## For Save customer detail
url(r'^api/v1/customer/(?P<pk>[0-9]+)/$', views.CustomerProfile.as_view()), ## Edit Customer Detail
I don't really know why you need CustomerCreateAPIView in this. ModelViewSet should be more than enough to perform all actions you need as long as you provide correct customer_details in your POST data.