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.
Related
I would like to upload multiple images using the Django model field(ImageField).
I created a model and was able to upload multiple images on the admin side like so https://imgur.com/BzVDPC5
I got the idea here (https://github.com/raszidzie/Multiple-Images-Django-Tutorial) in the Post(admin.py)
admin.py
from django.contrib import admin
from .models import School,SchoolImage
class SchoolImageAdmin(admin.StackedInline):
model = SchoolImage
#admin.register(School)
class SchoolAdmin(admin.ModelAdmin):
list_display=('school_name','school_type',"school_country")
search_fields=('school_name','school_type',"school_country")
list_filter=('school_name','school_type','school_gender')
inlines = [SchoolImageAdmin]
class Meta:
model =School
#admin.register(SchoolImage)
class SchoolImageAdmin(admin.ModelAdmin):
pass
I created the SchoolImage Model to handle multiple images in admin.py
models.py
from django.db import models
from django_countries.fields import CountryField
from partial_date import PartialDateField
class School(models.Model):
school_name = models.CharField(max_length = 30)
school_country = CountryField()
school_city = models.CharField(max_length= 30,default= None)
school_population = models.IntegerField()
school_description = models.TextField(max_length = 300)
year_build = PartialDateField()
total_branches = models.IntegerField()
school_fees = models.IntegerField()
school_images = models.FileField()
def __str__(self):
return self.school_name
class SchoolImage(models.Model):
schoolImages = models.ImageField()
school = models.ForeignKey(School, on_delete=models.CASCADE)
def __str__(self):
return self.school.school_name
not sure how to make it work in the veiws
here is my views code
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from .models import School
from .serializers import *
#api_view(['GET','POST'])
def school_list(request):
if request.method == 'GET':
data = School.objects.all()
serializer = SchoolSerializer(data, context={'request': request},many = True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = SchoolSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response( status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_404_NOT_FOUND)
How do I make it work in my views??
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.
I am new on this field and i am currently learning django and i come up with this problem. I am working on a project which is a social clone project and this project you can only post when you are in a group and i've encountered this problem when i post. The first post is working fine but the second post i get this error message called IntegrityError i've tried to delete my migrations and database and migrate and makemigrations again but does not fix the problem and now i am stuck and i hope someone will help me. This is the actual error
Posts Models
##########################
## POSTS MODELS.PY FILE ##
##########################
from django.contrib.auth import get_user_model
from django.db import models
from groups.models import Group
from misaka import html
from django.urls import reverse
from django.conf import settings
User = get_user_model()
class Post(models.Model):
user = models.ForeignKey(User, related_name='posts', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
message = models.TextField()
message_html = models.TextField(editable=False)
group = models.ForeignKey(Group, related_name='posts', null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return self.message
def save(self, *args, **kwargs):
self.message_html = html(self.message)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse(
'posts:single',
kwargs={
'username': self.user.username,
'pk': self.pk
}
)
class Meta:
ordering = ['-created_at']
unique_together = ['user', 'group']
Posts Views.py
#########################
## POSTS VIEWS.PY FILE ##
#########################
from django.contrib.auth import get_user_model
from braces.views import SelectRelatedMixin
from django.views import generic
from posts import models, forms
from django.http import Http404
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.contrib import messages
User = get_user_model()
class PostList(SelectRelatedMixin, generic.ListView):
model = models.Post
select_related = ('user', 'group')
class UserPost(generic.ListView):
model = models.Post
template_name = 'posts/user_post_list.html'
def get_queryset(self):
try:
self.post_user = User.objects.prefetch_related('posts').get(
username__iexact=self.kwargs.get('username')
)
except User.DoesNotExist:
raise Http404
else:
return self.post_user.posts.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['post_user'] = self.post_user
return context
class PostDetail(SelectRelatedMixin, generic.DetailView):
model = models.Post
select_related = ('user', 'group')
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(
user__username__iexact=self.kwargs.get('username')
)
class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
model = models.Post
fields = ('message', 'group')
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
class DeletePost(LoginRequiredMixin, SelectRelatedMixin, generic.DeleteView):
model = models.Post
select_related = ('user', 'group')
success_url = reverse_lazy('posts:all')
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
def delete(self, *args, **kwargs):
messages.success(self.request, ('Post Delete'))
return super().delete(*args, **kwargs)
Groups Models.py
##########################
## GROUPS VIEWS.PY FILE ##
##########################
from django.contrib.auth import get_user_model
from django import template
from django.db import models
from django.utils.text import slugify
from misaka import html
from django.urls import reverse
from django.conf import settings
User = get_user_model()
register = template.Library()
class Group(models.Model):
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True)
description = models.TextField(blank=True, default='')
description_html = models.TextField(editable=False, blank=True, default='')
members = models.ManyToManyField(User, through='GroupMember')
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.description_html = html(self.description)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('groups:single', kwargs={'slug': self.slug})
class Meta:
ordering = ['name']
class GroupMember(models.Model):
group = models.ForeignKey(Group, related_name='memberships', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='user_groups', on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Meta:
unique_together = ('group', 'user')
Groups Views.py
[![##########################
## GROUPS VIEWS.PY FILE ##
##########################
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from groups.models import Group, GroupMember
from django.urls import reverse
from django.shortcuts import get_object_or_404
from django.db import IntegrityError
from django.contrib import messages
from groups import models
class CreateGroup(LoginRequiredMixin, generic.CreateView):
model = Group
fields = ('name', 'description')
class SingleGroup(generic.DetailView):
model = Group
class ListGroups(generic.ListView):
model = Group
class JoinGroup(LoginRequiredMixin, generic.RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse('groups:single', kwargs={'slug': self.kwargs.get('slug')})
def get(self, request, *args, **kwargs):
group = get_object_or_404(Group, slug=self.kwargs.get('slug'))
try:
GroupMember.objects.create(user=self.request.user, group=group)
except IntegrityError:
messages.warning(self.request, (f'Warning, Already A Member Of {group.name}.'))
else:
messages.success(self.request, (f'You Are Now A Member Of {group.name} Group.'))
return super().get(request, *args, **kwargs)
class LeaveGroup(LoginRequiredMixin, generic.RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse('groups:single', kwargs={'slug': self.kwargs.get('slug')})
def get(self, request, *args, **kwargs):
try:
membership = models.GroupMember.objects.filter(
user=self.request.user,
group__slug=self.kwargs.get('slug')
).get()
except models.GroupMember.DoesNotExist:
messages.warning(self.request, ("You Can't Leave This Group Because You Aren't In It."))
else:
membership.delete()
messages.success(self.request, ('You Have Successfully Left This Group.'))
return super().get(request, *args, **kwargs)
Remove unique_together from your Post model. It means that only one Post object can have that particular user and model combination, that is why you are getting the integrity error.
The error which you are getting is all about the unique constraint.
unique_together = ['user', 'group']
Since you have defined in your model the unique_together attribute, you need to have unique rows of the combination for user and group. One user can post only once in a group and you are trying to post in the same group by the same user, that's why you are getting a unique constraint failed error.
I'm creating a blog post right now and I'm new at Django. I have an avatar picture in another app(registration) and I'm trying to import and associate correctly to another app (pages). In other words, I need to recover, in the HTML, the exact avatar picture from the user who creates a post. Thanks!
models.py (registration)
from django.db import models
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
def custom_upload_to(instance, filename):
old_instance = Profile.objects.get(pk=instance.pk)
old_instance.avatar.delete()
return 'profiles/' + filename
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to=custom_upload_to, null=True, blank=True)
bio = models.TextField(null=True, blank=True)
link = models.URLField(max_length=200, null=True, blank=True)
class Meta:
ordering = ['user__username']
#receiver(post_save, sender=User)
def ensure_profile_exists(sender, instance, **kwargs):
if kwargs.get('created', False):
Profile.objects.get_or_create(user=instance)
models.py (pages)
from django.db import models
from ckeditor.fields import RichTextField
from django.contrib.auth.models import User
from registration.models import Profile
class Page(models.Model):
title = models.CharField(verbose_name="Título", max_length=200) # Titulo
author = models.ForeignKey('auth.User', verbose_name="autor", on_delete=models.CASCADE, null = True)
content = RichTextField(verbose_name="Contenido") # Contenido
order = models.SmallIntegerField(verbose_name="Orden", default=0) # Orden de publicacion
created = models.DateTimeField(auto_now_add=True, verbose_name="Fecha de creación") # Fecha de creacion
updated = models.DateTimeField(auto_now=True, verbose_name="Fecha de edición") # Fecha de actualizacion
class Meta:
verbose_name = "página"
verbose_name_plural = "páginas"
ordering = ['order', 'title']
def __str__(self):
return self.title
views.py (pages)
from .models import Page
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView
from django.views.generic.edit import UpdateView
from django.views.generic.edit import DeleteView
from django.urls import reverse, reverse_lazy
from .forms import PageForm
from django.shortcuts import redirect
from django.contrib.admin.views.decorators import staff_member_required
from registration.models import Profile
#Decoradores
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
# Create your views here.
class StaffRequiredMixin(object):
#method_decorator(staff_member_required)
def dispatch(self, request, *args, **kwargs):
return super(StaffRequiredMixin, self).dispatch(request, *args, **kwargs)
#method_decorator(login_required, name="dispatch")
class PageListView(ListView):
model = Page
#method_decorator(login_required, name="dispatch")
class PageDetailView(DetailView):
model = Page
# CRUD:
#method_decorator(staff_member_required, name='dispatch')
class PageCreate(CreateView):
model = Page
form_class = PageForm
success_url = reverse_lazy('pages:pages')
def form_valid(self, form):
self.post = form.save(commit=False)
self.post.author = self.request.user
self.post.save()
return super(PageCreate, self).form_valid(form)
#method_decorator(staff_member_required, name='dispatch')
class PageUpdate(UpdateView):
model = Page
form_class = PageForm
template_name_suffix = '_update_form'
def get_success_url(self):
return reverse_lazy('pages:update', args=[self.object.id]) + '?ok'
#method_decorator(staff_member_required, name='dispatch')
class PageDelete(DeleteView):
model = Page
success_url = reverse_lazy('pages:pages')
You will probably want to provide the data using get_context_data() in the PageListView or PageDetailView. Something like:
class PageDetailView(DetailView):
model = Page
def get_context_data(**kwargs):
context = super().get_context_data(**kwargs)
# Profile image has a url property, so in the template {{ profile_image.url }}
profile_image = self.object.author.user.profile.avatar
context['profile_image'] = profile_image
return context
Take care: An error can be raised if author.user.profile does not exist. You can test for the relationship with hasattr(author.user, "profile").
here is my models.py
from __future__ import unicode_literals
from django.db import models
class User(models.Model):
name = models.CharField(max_length=200)
company_name = models.ForeignKey('Company',on_delete=models.CASCADE,related_name='user')
def __str__(self):
return self.name
class Company(models.Model):
name = models.CharField(max_length=200)
phone_number = models.IntegerField(null=True,blank=True)
def __str__(self):
return self.name
class Catalog(models.Model):
name = models.CharField(max_length=200)
no_of_pcs = models.IntegerField(null=True,blank=True)
per_piece_price = models.DecimalField(null=True,blank=True,max_digits=10,decimal_places=2)
company_name = models.ForeignKey(Company,on_delete=models.CASCADE,related_name='catalog')
def __str__(self):
return self.name
Here is my serializers.py
from rest_framework import serializers
from .models import *
from django.db.models import Sum,Count
class CatalogSerializerPost(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(required=False, allow_blank=True, max_length=100)
no_of_pcs = serializers.IntegerField()
per_piece_price = serializers.IntegerField()
def create(self, validated_data):
return Catalog.objects.create(**validated_data)
class CatalogSerializer(serializers.ModelSerializer):
total_pieces = serializers.SerializerMethodField()
total_price = serializers.SerializerMethodField()
class Meta:
model = Catalog
fields = ('name','no_of_pcs','per_piece_price','company_name','total_pieces','total_price')
depth = 1
def get_total_pieces(self, obj):
totalpieces = Catalog.objects.aggregate(total_pieces=Count('no_of_pcs'))
return totalpieces["total_pieces"]
def get_total_price(self, obj):
totalprice = Catalog.objects.aggregate(total_price=Sum('per_piece_price'))
return totalprice["total_price"]
here is my views.py
from __future__ import unicode_literals
from django.http import HttpResponse
from .models import *
import json
from django.http import JsonResponse, HttpResponse
from .serializers import *
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework import viewsets, generics
from rest_framework.decorators import api_view
#api_view(['GET', 'POST'])
def CatalogView(request):
if request.method == 'GET':
catalogs = Catalog.objects.select_related('company_name')
serializer = CatalogSerializer(catalogs, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = CatalogSerializerPost(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Here is my urls.py
from django.conf.urls import url, include
from django.contrib import admin
from api.views import CatalogView
from api import views
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework import routers
router = routers.DefaultRouter()
# router.register('catalogs',views.CatalogView,'catalog')
router.register('companies',views.CompanyView)
router.register('users',views.UserView)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include(router.urls)),
url(r'catalog/', CatalogView),
]
Here i am not able to post data THRIUGH JSON DATA..
Please refer the screenshot for the error..
Thanks..
here is the screen shot for error
please check this issue.
Here i am not able to post data THROUGH JSON DATA..
showing id field is required.
there are few problems with your Serializer and View both, and also the data that you are passing, Change your serializer to this
class CatalogSerializerPost(serializers.Serializer):
name = serializers.CharField(required=False, allow_blank=True, max_length=100)
no_of_pcs = serializers.IntegerField()
per_piece_price = serializers.IntegerField()
company_name_id = serializers.IntegerField() # add this field as you have a company field in the Catalog Model. and you are passing company id in the JSON.
def create(self, validated_data):
return Catalog.objects.create(**validated_data)
and pass
"company_name_id" :3 in your json
You need to mark id field as read only:
class CatalogSerializerPost(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
Also it could be more simple to use ModelSerializer.