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??
Related
I am working on an e-commerce project, and I want to add products from the front end. The files in my product app in Django is as follows
models.py:
from django.db import models
from django.forms import CharField
from PIL import Image
from io import BytesIO
from django.core.files import File
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField()
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
def get_absolute_url(self):
return f'/{self.slug}/'
class Product(models.Model):
category = models.ForeignKey(Category, related_name='product', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
slug = models.SlugField()
description = models.TextField(blank=True, null=True)
price = models.DecimalField(decimal_places=6, max_digits=6)
image = models.ImageField(upload_to='uploads/', blank=True, null=True)
thumbnail = models.ImageField(upload_to='uploads/', blank=True, null=True)
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-date_added',)
def __str__(self):
return self.name
def create_thumbnail(self, image, size = (300,200)):
img = Image.open(image)
img.convert('RGB')
img.thumbnail(size)
thumb_io = BytesIO()
img.save(thumb_io, 'JPEG')
thumbnail = File(thumb_io, name=image.name)
return thumbnail
def get_image(self):
if self.image:
return f'http://localhost:8000' + self.image.url
else:
return ''
def get_thumbnail(self):
if self.thumbnail:
return f'http://localhost:8000' + self.thumbnail.url
else:
if self.image:
self.thumbnail = self.create_thumbnail(self.image)
self.save()
return f'http://localhost:8000' + self.thumbnail.url
else:
return ''
def get_absolute_url(self):
return f'/{self.slug}/'
views.py:
from sys import excepthook
from unicodedata import category
from django.http import Http404
from django.shortcuts import render
from .serializers import ProductSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Product
from rest_framework import status
# Create your views here.
class LastestProduct(APIView):
def get(self, request, format=None):
products = Product.objects.all()[0:4]
serializer = ProductSerializer(products, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class Productclass LastestProduct(APIView):
def get(self, request, format=None):
products = Product.objects.all()[0:4]
serializer = ProductSerializer(products, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class ProductDetail(APIView):
def get_object(self, category_slug, product_slug):
try:
return Product.objects.filter(category__slug = category_slug).get(slug=product_slug)
except Product.DoesNotExits:
raise Http404
def get(self, request, category_slug, product_slug, format=None):
product = self.get_object(category_slug, product_slug)
serializer = ProductSerializer(product)
return Response(serializer.data, status=status.HTTP_200_OK)(APIView):
def get_object(self, category_slug, product_slug):
try:
return Product.objects.filter(category__slug = category_slug).get(slug=product_slug)
except Product.DoesNotExits:
raise Http404
def get(self, request, category_slug, product_slug, format=None):
product = self.get_object(category_slug, product_slug)
serializer = ProductSerializer(product)
return Response(serializer.data, status=status.HTTP_200_OK)
serializers.py:
from dataclasses import fields
from pyexpat import model
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = [
'id',
'name',
'category',
'get_absolute_url',
'description',
'price',
'get_image',
'get_thumbnail',
]
It works fine when it comes to fetching data (products I created in the Django admin) but how to send a JSON request that also contains the images as well as the text data like name, description etc. Currently, I can create a product by sending a POST request but the cannot send an image to the endpoint
Actually, you don't. If you want to send a file, you'd better send it as a multipart/formdata not json.
In DRF, this requires you change the default parser of your view.
See: https://www.django-rest-framework.org/api-guide/parsers/#multipartparser
But, if you really need to use a json format, I guess you could transform your file into a str representation (in the front - check base64 encoding) then send it in a json and finally transform the str representation into a file in the back. However, I would not advise you to do this as it makes the process more cumbersome
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.
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.
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.
I have the following model, included with their respective modelform (I am following the ModelForm guide on https://docs.djangoproject.com/en/1.5/topics/forms/modelforms/ ):
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
class Person(models.Model):
user = models.OneToOneField(User)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
address = models.CharField(max_length=100)
email = models.CharField(max_length=50)
class Meta:
abstract = True
class Trainer(Person):
team_name = models.CharField(max_length=50)
class Trainee(Person):
weight = models.DecimalField(max_digits=5, decimal_places=2)
height = models.DecimalField(max_digits=3, decimal_places=2)
class TrainerForm(ModelForm):
class Meta:
model = Trainer
class TraineeForm(ModelForm):
class Meta:
model = Trainee
Now I am trying to get the form on the view to work. Once again, I took the example from https://docs.djangoproject.com/en/1.5/topics/forms/modelforms/
# Create your views here.
from django.http import HttpResponse
from django.forms.models import modelformset_factory
def index(request):
return HttpResponse("Hello, world. You're at the users index.")
def trainer_signup(request):
TrainerFormSet = modelformset_factory(Trainer)
if request.method == 'POST':
formset = TrainerFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
# do something.
else:
formset = TrainerFormSet()
return render_to_response("forms.html", {
"formset": formset,
})
The error I get is:
global name 'Trainer' is not defined
Thanks!
The problem is with this line of code:
TrainerFormSet = modelformset_factory(Trainer)
Because he doesn't know what Trainer is. You have to import your models into the views. Add this to the top of the views.py file, and everything will work:
from models import *