I've tried everything but I cannot figure out why my images for an Avatar won't save to the media folder in Django.
I am happy the front end is passing form data to the AvatarAPIView and I get the following when I print out the data being passed to the view.
<QueryDict: {'myFile': [<InMemoryUploadedFile: 1965.jpg (image/jpeg)>]}>
[07/Feb/2021 10:48:54] "PUT /api/profile/avatar/ HTTP/1.1" 200 31
view.py
from profiles.api.serializers import (UserDisplaySerializer,
SubscriptionSerializer,
AvatarSerializer)
from profiles.models import CustomUser
from rest_framework import status, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import UpdateAPIView, GenericAPIView
from rest_framework import mixins
from rest_framework.parsers import MultiPartParser, FileUploadParser, FormParser
from django.http import HttpResponse
class CurrentUserAPIView(APIView):
def get(self, request):
serializer = UserDisplaySerializer(request.user)
return Response(serializer.data)
def patch(self, request):
serializer = UserDisplaySerializer(request.user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserUpdateAPIView(UpdateAPIView):
queryset = CustomUser.objects.all()
serializer_class = UserDisplaySerializer
class AvatarAPIView(APIView):
parser_classes = (MultiPartParser, FormParser)
def get(self, request):
serializer = AvatarSerializer(request.user)
return Response(serializer.data)
def put(self, request, format=None):
serializer = AvatarSerializer(
request.user, data=request.data)
print(request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.py
from rest_framework import serializers
from profiles.models import CustomUser, Subscription
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
exclude = ('id', 'user', )
class UserDisplaySerializer(serializers.ModelSerializer):
subscription = SubscriptionSerializer(read_only=True, many=False)
class Meta:
model = CustomUser
exclude = ('password',)
class AvatarSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('avatar',)
urls.py
from django.urls import path
from django.conf.urls import include
from profiles.api.views import (CurrentUserAPIView,
UserUpdateAPIView,
AvatarAPIView,
)
from rest_framework import routers
urlpatterns = [
path("user/", CurrentUserAPIView.as_view(), name="current-user"),
path("user/update/<int:pk>", UserUpdateAPIView.as_view()),
path("avatar/", AvatarAPIView.as_view(), name='user-avatar'),
]
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
bio = models.CharField(max_length=240, blank=True)
city = models.CharField(max_length=30, blank=True)
avatar = models.ImageField(null=True, blank=True)
I can upload files from the Django admin no problems. It's just when running through the serializer I have issues. Particularly because the data passes is_valid() and a code 200 is issued.
I'm half a day deep and I've got nothing.
not sure if your user is logged in or not;
as your formdata shows:
<QueryDict: {'myFile': [<InMemoryUploadedFile: 1965.jpg (image/jpeg)>]}> [07/Feb/2021 10:48:54] "PUT /api/profile/avatar/ HTTP/1.1" 200 31
In your form data, the "input name" of image is "myFile" while the name of imagefield in your Model and Serializer is "avatar".
Related
I'm extending my current model to have some common properties from other base classes.
Before extending the model, everything was working fine. But after extending, I'm getting the assertion error while performing put and post Operation. I tried my best to resolve it by my own. But not getting where it is going wrong. Can anyone help me on this?
Please find my model and serializers below.
basemodel.py
from django.db import models
class BaseModel(models.Model):
created_at=models.DateTimeField(auto_now=True)
updated_at=models.DateTimeField(auto_now=True)
class Meta:
abstract = True
softdelete.py
from django.db import models
class SoftDeleteModel(models.Model):
is_deleted = models.BooleanField(default=False)
def delete(self):
self.is_deleted = True
self.save()
def restore(self):
self.is_deleted = False
self.save()
class Meta:
abstract = True
movies.py
from django.db import models
from cinimateApp.models.comman.softdelete import SoftDeleteModel
from cinimateApp.models.comman.basemodel import BaseModel
# Create your models here.
class Movies(SoftDeleteModel,BaseModel):
name=models.CharField(max_length=250)
description=models.CharField(max_length=250)
active=models.BooleanField(default=False)
def __str__(self):
return self.name
movieSerializer.py
#Model Serializer
from rest_framework import serializers
from cinimateApp.models.movies import Movies
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movies
fields = '__all__'
# fields=['id', 'name', 'description', 'active']
# exclude=['name']
# field Level Validation
def validate_name(self,value):
if(len(value)<3):
raise serializers.ValidationError('name is too short')
return value
#Objectlevel validation
def validate(self,data):
if(data['name']==data['description']):
raise serializers.ValidationError('name and description should be different')
return
#custome serializer field
name_length=serializers.SerializerMethodField()
def get_name_length(self,object):
return len(object.name)
views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from cinimateApp.serializers.movieSerializer import MovieSerializer
from cinimateApp.models.movies import Movies
# Create your views here.
class MovieList(APIView):
def get(self,request):
movies=Movies.objects.all()
serializer=MovieSerializer(movies,many=True)
return Response(serializer.data,status=status.HTTP_200_OK)
def post(self,request):
serialiser=MovieSerializer(data=request.data)
if(serialiser.is_valid()):
serialiser.save()
return Response(serialiser.data,status=status.HTTP_201_CREATED)
else:
return Response(serialiser.errors,status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class MovieDetailsAV(APIView):
def get(self,request,id):
try:
movie=Movies.objects.get(pk=id)
serializer=MovieSerializer(movie)
return Response(serializer.data,status=status.HTTP_200_OK)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
def put(self,request,id):
try:
movie=Movies.objects.get(pk=id)
serializer=MovieSerializer(movie,data=request.data)
if(serializer.is_valid()):
serializer.save()
return Response(serializer.data,status=status.HTTP_200_OK)
return Response(serializer.errors,status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
def delete(self,request,id):
try:
movie=Movies.objects.get(pk=id)
movie.delete()
return Response({'message' : 'Content deleted successfully'},status=status.HTTP_204_NO_CONTENT)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
def patch(self,request,id):
try:
movie=Movies.objects.get(pk=id)
serializer=MovieSerializer(movie,data=request.data,partial=True)
if(serializer.is_valid()):
serializer.save()
return Response(serializer.data,status=status.HTTP_200_OK)
return Response(serializer.errors,status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except Movies.DoesNotExist:
return Response({'Error':'Movie not found'},status=status.HTTP_404_NOT_FOUND)
I'm getting following errors for put and post requests.
assert value is not None, '.validate() should return the validated data'
AssertionError: .validate() should return the validated data
validate() function should return data so:
def validate(self,data):
if(data['name']==data['description']):
raise serializers.ValidationError('name and description should be different')
return data
I'm working on a project and get the following error: RelatedObjectDoesNotExist at /agents/create/
User has no userprofile.I created a form for the user to submit an Agent but when I create an Agent using the form it gives me the above mentioned error but when I try to submit an already created agent it says User with that name already exists.I have two apps Agents and Leads Here is my code:
agents/views.py
from django.shortcuts import reverse
from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin
from leads.models import Agent
from .forms import CreateAgentForm
class AgentListView(LoginRequiredMixin, generic.ListView):
template_name = 'agents/agent_list.html'
def get_queryset(self):
return Agent.objects.all()
class CreateAgentView(LoginRequiredMixin, generic.CreateView):
template_name = 'agents/agent_create.html'
form_class = CreateAgentForm
def get_success_url(self):
return reverse('agent-list')
def form_valid(self, form):
agent = form.save(commit=False)
agent.userprofile = self.request.user.userprofile
agent.save()
return super(CreateAgentView, self).form_valid(form)
leads/models.py
from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Lead(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
age = models.IntegerField(default=0)
agent = models.ForeignKey('Agent', on_delete=models.CASCADE)
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Agent(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
userprofile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
def __str__(self):
return self.user.first_name
def post_user_profile(instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(post_user_profile, sender=User)
agents/urls.py
from django.urls import path
from .views import AgentListView, CreateAgentView
urlpatterns = [
path('', AgentListView.as_view(), name='agent-list'),
path('create/', CreateAgentView.as_view(), name='agent-create'),
]
agents/forms.py
from django import forms
from leads.models import Agent
class CreateAgentForm(forms.ModelForm):
class Meta:
model = Agent
fields = ('user',)
I'm still learning so any help would be appreciated.
I think the admin user has no user profile created, so you need to manually create one for him in the admin panel since migrations have already been done.
Erase your db and redo a migration.
Create User with the admin panel
I'm working on a project from the book 'Django3 by example'. I want to add an image from the URL which the user provided. But when I try to save the page it gives me this error:
IntegrityError at /images/create/
NOT NULL constraint failed: images_image.users_like_id.
I have tried the solutions other posted but it didn't help.
Here is my code:
models.py
from django.db import models
from django.conf import settings
from django.utils.text import slugify
class Image(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,
related_name='images_created')
users_like = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,
related_name='images_liked')
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=200, blank=True)
url = models.URLField()
image = models.ImageField(upload_to='images/%Y/%m/%d/')
description = models.TextField()
created = models.DateField(auto_now_add=True, db_index=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .forms import ImageCreateForm
#login_required
def image_create(request):
if request.method == "POST":
form = ImageCreateForm(data=request.POST)
if form.is_valid():
cd = form.cleaned_data
new_item = form.save(commit=False)
new_item.user = request.user
new_item.save()
messages.success(request, 'Image added successfully')
return redirect(new_item.get_absolute_url())
else:
form = ImageCreateForm(data=request.GET)
context = {'section':'images', 'form':form}
return render(request, 'images/image/create.html', context)
forms.py
from django import forms
from urllib import request
from django.core.files.base import ContentFile
from django.utils.text import slugify
from .models import Image
class ImageCreateForm(forms.ModelForm):
class Meta:
model = Image
fields = ('title', 'url', 'description')
widgets = {
'url': forms.HiddenInput,
}
def clean_url(self):
url = self.cleaned_data['url']
valid_extension = ['jpg', 'jpeg']
extension = url.rsplit('.', 1)[1].lower()
if extension not in valid_extension:
raise forms.ValidationError('The given URL does not match valid image extension')
return url
def save(self, force_insert=False, force_update=False, commit=True):
image = super().save(commit=False)
image_url = self.cleaned_data['url']
name = slugify(image.title)
extension = image_url.rsplit('.', 1)[1].lower()
image_name = f'{image}.{extension}'
response = request.urlopen(image_url)
image.image.save(image_name, ContentFile(response.read()), save=False)
if commit:
image.save()
return image
I'm using a ForeignKey on users_like instead of ManyToManyField as a user might
like multiple images and each image can be liked by multiple users.
**views.py code**(views.py function id not call urls.py)
def SendMail(request,id):
post=get_object_or_404(Post,slug=slug,status='published')
form=EmailSendForm()
return render(request,'mail.html',{'form':form,'post':post})
**models.py**(models.py not accept the id number in views.py)
from django.contrib.auth.models import User
from django.db import models
from django.urls import reverse
from django.utils import timezone
class CustomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES=(('draft','Draft'),('published','Published'))
id=models.IntegerField(primary_key=True)
title=models.CharField(max_length=300)
slug=models.SlugField(max_length=300,unique_for_date='publish')
author=models.ForeignKey(User,related_name='post',on_delete=models.CASCADE)
body=models.TextField()
publish=models.DateTimeField(default=timezone.now)
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
status=models.CharField(max_length=10,choices=STATUS_CHOICES,default='draft')
objects=CustomManager()
class Meta:
ordering=('-publish', )
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post',args=[self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%d'),
self.slug])
urls.py(urls show page not found 404 error)
path('/(?P\d+)share/$',views.SendMail),
**views.py**
from django.core.mail import send_mail
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render,get_object_or_404
from app.models import Post
from app.forms import EmailSendForm
def post_list_view(request):
post_list=Post.objects.all()
paginator=Paginator(post_list,3)
page_number=request.GET.get('page')
try:
post_list=paginator.page(page_number)
except PageNotAnInteger:
post_list=paginator.page(1)
except EmptyPage:
post_list=paginator.page(paginator.num_pages)
return render(request, 'post_list.html', {'post_list':post_list})
def post_detail_view(request,year,month,day,slug):
post=get_object_or_404(Post,slug=slug,
status='published',
publish__year=year,
publish__month=month,
publish__day=day,
)
return render(request, 'post_detail.html', {'post':post})
def SendMail(request,post_id):
post = get_object_or_404(Post,id=post_id,status='published')
sent=False
if request.method=='POST':
form=EmailSendForm(request.POST)
if form.is_valid():
cd=form.cleaned_data
subject='{}({})Please read message"{}"'.format(cd['name'],cd['email'],post.title)
post_url=request.build_absolute_uri(post.get_absolute_url())
message="Read Post at:\n {}\n\n{}\'s Comments:\n{}".format(post_url,cd['name'],cd['comments'])
send_mail(subject,message,'vpnraut#gmail.com',[cd['to']])
sent=True
else:
form = EmailSendForm()
return render(request, 'mail.html', {'sent':sent,'form':form, 'post':post})
**models.py**
from django.contrib.auth.models import User
from django.db import models
from Django.urls import reverse
from Django.utils import timezone
class CustomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES=(('draft','Draft'),('published','Published'))
id=models.IntegerField(primary_key=True)
title=models.CharField(max_length=300)
slug=models.SlugField(max_length=300,unique_for_date='publish')
author=models.ForeignKey(User,related_name='post',on_delete=models.CASCADE)
body=models.TextField()
publish=models.DateTimeField(default=timezone.now)
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
status=models.CharField(max_length=10,choices=STATUS_CHOICES,default='draft')
objects=CustomManager()
class Meta:
ordering=('-publish', )
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post',args=[self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%d'),
self.slug])
class Comment(models.Model):
post=models.ForeignKey(Post,related_name='comments',on_delete=models.CASCADE)
name=models.CharField(max_length=30)
email=models.EmailField()
body=models.TextField()
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
active=models.BooleanField(default=True)
class Meta:
ordering=('-created', )
def __str__(self):
return 'Commnted by {} on {}'.format(self.name,self.post)
**urls.py**
urlpatterns = [
path('admin/', admin.site.urls),
path('',views.post_list_view),
path('<int:year>/<int:month>/<int:day>/<slug:slug>/',views.post_detail_view,name='post'),
path('(<int:post_id>\d+)/share/',views.SendMail, name='post_share'),]
I am having trouble creating a customizable swagger schema in the Django Rest Framework. I have read pages of documentation, but have not found a clear cut example on how to generate swagger annotations in python.
I am aware that swagger/schema documentation is readily generated when using ViewSets in Django. However, I am solely using APIViews and want to write a customized schema. I have tried creating a CoreAPI schema but am unaware of how to implement it. I am enclosing some of my sample code and some screenshots as well. The screen shots go from what I have to what I want.
Sample code:
urls.py
from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from Views import SampleView as sv
from rest_framework_swagger.views import get_swagger_view
from rest_framework.documentation import include_docs_urls
from rest_framework.renderers import CoreJSONRenderer
from rest_framework.schemas import get_schema_view
schema_view enter code here= get_swagger_view(
title='Sample API')
urlpatterns = [
url(r'^sample/$', pv.SampleList.as_view()),
url(r'^sample/(?P<id>[a-f\d]{24})/$', sv.SampleDetail.as_view()),
url('^schema/$', schema_view),
]
urlpatterns = format_suffix_patterns(urlpatterns)
views.py
from rest_framework.views import APIView
from Manager.SampleManager import SampleManager as sm
_sampleManager = sm()
class SampleList(APIView):
"""
get:
Return a list of all the existing samples.
post:
Create a new sample.
"""
def get(self, request, format=None):
return _sampleManager.getAll()
def post(self, request, format=None):
return _sampleManager.create( request)
class SampleDetail(APIView):
"""
get:
Get a sample.
put:
Update a sample.
delete:
Delete a sample.
"""
def get(self, request, id, format =None):
return _sampleManager.getById( id)
def put(self, request, id, format =None):
return _sampleManager.update( request, id)
def delete(self, request, id, format =None):
return _sampleManager.deleteById( id)
Serializers.py
from rest_framework_mongoengine.serializers import DocumentSerializer
from .modles import Sample, SampleInner
from Serializers.SampleInnerSerializer import SampleInnerSerializer
class SampleSerializer(DocumentSerializer):
other = SampleInnerSerializer(many=True)
class Meta:
model = Sample
fields = '__all__'
def create(self, validated_data):
samples = validated_data.pop('other')
created_instance = super(SampleSerializer, self).create(validated_data)
for sample_data in samples:
created_instance.other.append(SampleInner(**sample_data))
created_instance.save()
return created_instance
def update(self, instance, validated_data):
samples = validated_data.pop('other')
updated_instance = super(SampleSerializer, self).update(instance, validated_data)
for sample_data in samples:
updated_instance.other.append(SampleInner(**sample_data))
updated_instance.save()
return updated_instance
Schema.py
import coreapi
from rest_framework.decorators import api_view, renderer_classes
from rest_framework import renderers, response
schema = coreapi.Document(
title='Sample API',
content={
'sample': coreapi.Link(
url='/sample/',
action='post',
fields=[
coreapi.Field(
name='from',
required=True,
location='query',
description='City name or airport code.'
),
coreapi.Field(
name='to',
required=True,
location='query',
description='City name or airport code.'
),
coreapi.Field(
name='date',
required=True,
location='query',
description='Flight date in "YYYY-MM-DD" format.'
)
],
description='Create partner'
)
}
)
#api_view()
#renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request):
return response.Response(schema)
There is two solution for you in this senario, One "go with the GenricApiView" Two "Create Custom row Schema"
let's go with
-- >solution one.
urls.py
schema_view = get_swagger_view(title='Test All API')
urlpatterns = [
path('swagger2/', schema_view),
]
view.py
class LoginAPIView(generics.GenericAPIView):
serializer_class = LoginSerializer
permission_classes = [permissions.AllowAny]
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Result
--> Solution two:
urls.py
configuration is same as before
views.py
class BlacklistTokenAdding(APIView):
permission_classes = [permissions.AllowAny]
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="body",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="body",
schema=coreschema.String()
),
])
def post(self, request, format='json'):
try:
refresh_token = request.data["refresh_token"]
token = RefreshToken(refresh_token)
token.blacklist()
return Response(status=status.HTTP_200_OK)
except Exception as e:
return Response(status=status.HTTP_400_BAD_REQUEST)
//Note the first_field & second_field is to demonstration you can add here as much field as you want.
Result