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
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)
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)
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()
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'
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')