Django Tastypie: maximum recursion depth exceeded - django

I am following the tutorial from django-tastypie, after Hooking Up The Resource(s), I went to http://localhost:8000/api/entry/?format=json, I got this error in JSON:
{"error_message": "maximum recursion depth exceeded", "traceback": "Traceback (most recent call last):\n\n File \"C:\\Python27\\lib\\site-packages\\django_tastypie-0.9.14-py2.7.egg\\tastypie\\resources.py\", line 202, in wrapper\n response = callback(request, *args, **kwargs)\n\n\
models.py:
from tastypie.utils.timezone import now
from django.contrib.auth.models import User
from django.db import models
from django.template.defaultfilters import slugify
class Entry(models.Model):
user = models.ForeignKey(User)
pub_date = models.DateTimeField(default=now)
title = models.CharField(max_length=200)
slug = models.SlugField()
body = models.TextField()
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
# For automatic slug generation.
if not self.slug:
self.slug = slugify(self.title)[:50]
return super(Entry, self).save(*args, **kwargs)
api.py:
from tastypie.resources import ModelResource
from myapp.models import Entry
class EntryResource(ModelResource):
class Meta:
queryset = Entry.objects.all()
resource_name = 'entry'

try uncomment "(r'^blog/', include('myapp.urls')" which you put under urlpatterns and then run your application again.

Just comment out the "(r'^blog/', include('myapp.urls')" which can be found under urlpatterns in your urls.py and then rerun your application.

Related

File Upload using Django Rest Framework getting error "No file was submitted."

While trying to upload the file using Postman with Content-Type - multipart/form-data in the headers. I am passing both the fields, but I get the following error:
Error:{"upload_to": ["This field is required."],"file_object": ["No
file was submitted."]}
urls.py
from django.conf.urls import include, url
from rest_framework_nested import routers
from utils.views import TemporaryImageView
from . import views
router = routers.SimpleRouter(trailing_slash=False)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^upload-temp-image/$', TemporaryImageView.as_view())
]
views.py
from rest_framework import viewsets, filters
import django_filters.rest_framework
from rest_framework.generics import CreateAPIView
from rest_framework.parsers import FileUploadParser, MultiPartParser, FormParser
from utils.serializers.temporary_image import TemporaryImageSerializer
class TemporaryImageView(CreateAPIView):
parser_classes = (MultiPartParser,)
serializer_class = TemporaryImageSerializer
serializers.py
from rest_framework import serializers
from utils.models.tempfile import TemporaryFile
class TemporaryImageSerializer(serializers.ModelSerializer):
choices = (('Company Logo','/company/logos/'),
)
upload_to = serializers.ChoiceField(choices=choices)
file_object = serializers.ImageField()
class Meta:
model = TemporaryFile
fields = ('upload_to', 'file_object')
models.py
from django.db import models
class TemporaryFile(models.Model):
"""
a temporary file to backend
"""
file_object = models.FileField(blank=False, null=False)
timestamp = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return str(self.id)
Please help...I don't know what is wrong.
I have changed my models.py file in the way below and it works as expected..
models.py
from django.db import models
def get_image_path(instance, filename):
if instance.upload_to == "company_logo":
path = 'company/logo/'
return path
class TemporaryFile(models.Model):
"""
a temporary file to backend
"""
file_object = models.FileField(blank=False, null=False, upload_to=get_image_path)
timestamp = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return str(self.id)
def __init__(self, *args, **kwargs):
self.upload_to = kwargs.pop("upload_to")
super(TemporaryFile, self).__init__(*args, **kwargs)

How to call a function when POST button is pressed on Django Rest Api

I have a Django rest api which you can upload a file and an id:
Screenshot
I want to call a function when post button is pressed in order to do some stuff with the uploaded file. How can I do this in django rest platform?
models.py
from django.db import models
from .validators import validate_file_extension
class Uplist(models.Model):
report_id = models.CharField(max_length=200, primary_key= True)
application = models.FileField(blank=False, null=False, validators=[validate_file_extension])
serializers.py
from rest_framework import serializers
from api import models
class UplistSerializer(serializers.ModelSerializer):
class Meta:
model = models.Uplist
fields = ('application', 'report_id',)
urls.py
from django.urls import path
from django.conf.urls import url
from . import views
urlpatterns = [
path('', views.ListUps.as_view()),
url(r'^$', views.ListUps.as_view()),
url(r'^(?P<pk>[0-9]+)/$', views.ListDetails.as_view()),
]
views.py
from rest_framework import generics
from rest_framework.parsers import MultiPartParser, FormParser
from api import models
from . import serializers
class ListUps(generics.ListCreateAPIView):
parser_classes = (MultiPartParser, FormParser)
queryset = models.Uplist.objects.all()
serializer_class = serializers.UplistSerializer
class ListDetails(generics.RetrieveUpdateDestroyAPIView):
queryset = models.Uplist.objects.all()
serializer_class = serializers.UplistSerializer
validators.py
def validate_file_extension(value):
import os
from django.core.exceptions import ValidationError
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.csv']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
In urls add pattern
path('someurl', SomeClass.as_view()),
In your view.py
class SomeClass(generics.ListCreateAPIView):
def post(self, request, **kwargs):
....
When you call post function you goto this view. You can perform your tasks here.
Answer:
class ListUps(generics.ListCreateAPIView):
parser_classes = (MultiPartParser, FormParser)
queryset = models.Uplist.objects.all()
serializer_class = serializers.UplistSerializer
def post(self, request, *args, **kwargs):
#added function here
return self.create(request, *args, **kwargs)

DRF serializer only works one way, output is OK, but input gives error

I am trying to follow this http://www.django-rest-framework.org/api-guide/fields/#custom-fields to serialize a Point in GeoDjango. But only get the exception below. Can't figure out where my mistake is.
It outputs correctly, but get an error while inserting the same output.
Error output:
Got a `TypeError` when calling `Venue.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Venue.objects.create()`. You may need to make the field read-only, or override the VenueSerializer.create() method to handle this correctly.
Original exception was:
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/rest_framework/serializers.py", line 916, in create
instance = ModelClass.objects.create(**validated_data)
File "/usr/local/lib/python3.5/dist-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/django/db/models/query.py", line 394, in create
obj.save(force_insert=True, using=self.db)
TypeError: save() got an unexpected keyword argument 'force_insert'
From serializers.py:
from django.contrib.gis.geos import Point
class LocationField(serializers.Field):
def to_representation(self, obj):
return "%s,%s" % (obj.y, obj.x)
def to_internal_value(self, data):
lat,lng = [str(col) for col in data.split(',')]
pnt = Point(float(lat), float(lng), srid=4326)
return pnt
class VenueSerializer(serializers.ModelSerializer):
location = LocationField()
class Meta:
model = Venue
fields = ('id', 'name', 'description', 'website', 'location')
read_only_fields = ('created_at', 'modified_at')
From models.py:
from __future__ import unicode_literals
from django.contrib.gis.db import models
from django.conf import settings
from django.contrib.auth import get_user_model
from pygeocoder import Geocoder
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='system')[0]
class Venue(models.Model):
"""
Model for venues
"""
name = models.CharField(max_length=254)
description = models.TextField(max_length=512, blank=True)
website = models.CharField(max_length=254, blank=True)
address = models.CharField(max_length=254, blank=True)
location = models.PointField()
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
objects = models.GeoManager()
def __str__(self):
return self.name
class Meta:
ordering = ('created_at',)
def save(self):
if not self.address:
geo = Geocoder.reverse_geocode(self.location.y, self.location.x)
self.address = geo.formatted_address
super(Venue, self).save()
The save() function in models.py was missing the **kwargs
Corrected to the one below:
def save(self, **kwargs):
if not self.address:
geo = Geocoder.reverse_geocode(self.location.y, self.location.x)
self.address = geo.formatted_address
super(Venue, self).save()

Django save image from url and connect with ImageField

I have in models.py:
class Item(models.Model):
image_file = models.ImageField(upload_to='images')
image_url = models.URLField()
I want django automatically download and locally save image from image_url and "connect" it with image_file
How it should act:
I Paste https://docs.djangoproject.com/s/img/site/hdr_logo.gif
into image_url field in admin
Click "save"
In templates write <img src="{{ item.image_file.url }}">. It shows
image from my server, not djangoproject.com
What I've tried:
I've overwritten save method of Item class. I saved image locally via urllib, but I am stuck on connecting this saved image with image_file field
from django.core.files import File
import os
class Item(models.Model):
image_file = models.ImageField(upload_to='images')
image_url = models.URLField()
...
def get_remote_image(self):
if self.image_url and not self.image_file:
result = urllib.urlretrieve(self.image_url)
self.image_file.save(
os.path.basename(self.image_url),
File(open(result[0]))
)
self.save()
You can override the default save() method to automatically invoke get_remote_image().
See: https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-model-methods
from django.db import models
from django.core.files import File
from urllib.request import urlopen
from tempfile import NamedTemporaryFile
class Item(models.Model):
image_file = models.ImageField(upload_to='images')
image_url = models.URLField()
...
def get_remote_image(self):
if self.image_url and not self.image_file:
img_temp = NamedTemporaryFile(delete=True)
img_temp.write(urlopen(self.image_url).read())
img_temp.flush()
self.image_file.save(f"image_{self.pk}", File(img_temp))
self.save()
This solution avoid any utf-8 errors received during url process.
It works only with python 3.6+ because the f string.
Check this link: https://twigstechtips.blogspot.com/2012/04/django-programmatically-saving-image.html
For python3
from django.core.files import File
from urllib import request
import os
class Item(models.Model):
image_file = models.ImageField(upload_to='images')
image_url = models.URLField()
...
def get_remote_image(self):
if self.image_url and not self.image_file:
result = request.urlretrieve(self.image_url)
self.image_file.save(
os.path.basename(self.image_url),
File(open(result[0], 'rb'))
)
self.save()
from here: http://stackoverflow.com/questions/17960942/attributeerror-module-object-has-no-attribute-urlretrieve
Python3
from django.db import models
from django.core.files import File
from urllib.request import urlopen
from tempfile import NamedTemporaryFile
class Item(models.Model):
image_file = models.ImageField(upload_to='images')
image_url = models.URLField()
def save(self, *args, **kwargs):
if self.image_url and not self.image_file:
img_temp = NamedTemporaryFile(delete=True)
img_temp.write(urlopen(self.image_url).read())
img_temp.flush()
self.image_file.save(f"image_{self.pk}", File(img_temp))
super(Item, self).save(*args, **kwargs)
It`s similar but with automated save 'image_file', when add 'image_url'

How to use a foreign key in Django?

I have a video model in django. Currently when a video is saved, the current logged user is not saved in the model (Other fields have a value, except the user field). The form uses a generic create django view.
I would like to know how to save the current logged user when a new video is saved?
multimedia/models.py
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
from django.core.exceptions import PermissionDenied
from django.db.models.signals import post_save
from django.contrib.auth.decorators import login_required
class Video(models.Model):
user = models.ForeignKey(User, related_name='+',blank=True, null=True)
title = models.CharField(max_length=200)
description = models.TextField()
created = models.DateTimeField('date created', auto_now_add=True, blank=False)
file_url = models.CharField(max_length=2000, blank=True)
file_name = models.CharField(max_length=255, blank=True)
file_uploaded = models.DateTimeField('date file uploaded', null=True, blank=True)
file_upload_speed = models.FloatField(null=True, blank=True)
file_size = models.IntegerField(null=True, blank=True)
def has_file(self):
return len(self.file_url) > 0
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('multimedia_video_detail', [self.id])
class VideoForm(ModelForm):
class Meta:
model = Video
# fields = ('title', 'description')
exclude = ('file_url', 'file_name', 'file_uploaded','file_upload_speed', 'file_size')
multimedia/views.py
from django.conf.urls.defaults import patterns, include, url
from models import Video, VideoForm
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$','django.views.generic.list_detail.object_list',{ 'queryset': Video.objects.all() }, name='multimedia_video_list'),
url(r'^new$', 'django.views.generic.create_update.create_object',{ 'model': Video },name='multimedia_video_new'),
url(r'^(?P<object_id>[\d]*)$', 'django.views.generic.list_detail.object_detail',{ 'queryset': Video.objects.all() }, name='multimedia_video_detail'),
url(r'^(?P<object_id>[\d]*)/edit$','django.views.generic.create_update.update_object',{ 'form_class': VideoForm }, name='multimedia_video_edit'),
url(r'(?P<object_id>[\d]*)/delete$', 'django.views.generic.create_update.delete_object', { 'model': Video, 'post_delete_redirect': '/videos' }, name='multimedia_video_delete'),
url(r'^(?P<object_id>[\d]*)/upload$','multimedia.views.upload_video',name='multimedia_video_upload'),
url(r'^(?P<object_id>[\d]*)/upload/done$','multimedia.views.upload_video_done',name='multimedia_video_upload_done'),
)
Thanks for any help to solve this issue
Instead of directly using the generic creation view, you need to use a wrapper around it that pulls the current user out of the request. Additionally, you create a model form that accepts the user, and overrides the save() method to set the user value on the model instance.
def VideoForm(user):
class _wrapped(forms.ModelForm):
class Meta:
model = models.Video
def save(self, *args, **kwargs):
self.instance.user = user
super(_wrapped, self).save(*args, **kwargs)
return _wrapped
#login_required
def create(request):
return django.views.generic.create_update.create_object(form_class=VideoForm(request.user), name='multimedia_video_new')