How should I store an entity key in a webapp2 session? - google-app-engine

I've been trying to use webapp2 to store user data in session.
I tried to store the Key of the parent object in session data:
self.session['client'] = client.key
But I keep getting a:
TypeError: Key('Client', 6401356696911872) is not JSON serializable
How should I store an entity key in a session?
My code fairly simple:
import os
import urllib
import logging
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
from webapp2_extras import sessions
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
self.session_store = sessions.get_store(request=self.request)
try:
# dispatch the request
webapp2.RequestHandler.dispatch(self)
finally:
# save all sessions
import pdb; pdb.set_trace()
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
JINJA_ENVIRONMENT = jinja2.Environment(
loader = jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
DEFAULT_LEADBOOK_NAME = 'whatsmyname'
def leadbook_key(leadbook_name=DEFAULT_LEADBOOK_NAME):
"""Constructs a Datastore key for a LeadBook entity with leadbook_name."""
return ndb.Key('LeadBook', leadbook_name)
class Client(ndb.Model):
email = ndb.StringProperty()
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
# this just creates a Client to use
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
logging.info("create Admin")
client = Client(
email = "bryan#mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
class Customer(ndb.Model):
client = ndb.KeyProperty(kind=Client)
email = ndb.StringProperty(indexed=True)
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
class MainPage(BaseHandler):
def get(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
# This should be the Client record that shows the info of the owner of the local clinic
# the question is how do I get the site to show the correct Client?
client = Client.query( Client.name == "Bryan Wheelock").get()
self.session['client'] = client.key
template_values = {
'client': client,
'leadbook_name': urllib.quote_plus(leadbook_name),
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
class LeadBook(webapp2.RequestHandler):
def post(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
client = self.session.get('client')
cl = Client.query(client.key )
customer = Customer( client = cl.key)
customer.name = self.request.get('id_name')
customer.street = self.request.get('id_street')
customer.phone = self.request.get('id_phone')
customer.zip = self.request.get('id_zip')
import pdb; pdb.set_trace()
# How can I see the number of Customers before and after save?
customer.put()
query_params = {'leadbook_name': leadbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
}
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', LeadBook),
], config = config,
debug=True)
Traceback (most recent call last):
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 22, in dispatch
self.session_store.save_sessions(self.response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 420, in save_sessions
session.save_session(response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 205, in save_session
response, self.name, dict(self.session), **self.session_args)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 423, in save_secure_cookie
value = self.serializer.serialize(name, value)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/securecookie.py", line 47, in serialize
value = self._encode(value)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/securecookie.py", line 92, in _encode
return json.b64encode(value)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/json.py", line 84, in b64encode
return base64.b64encode(encode(value, *args, **kwargs))
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/json.py", line 55, in encode
return json.dumps(value, *args, **kwargs).replace("</", "<\\/")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 250, in dumps
sort_keys=sort_keys, **kw).encode(obj)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: Key('Client', 6401356696911872) is not JSON serializable

Use a urlsafe version of the key:
https://cloud.google.com/appengine/docs/python/ndb/entities#retrieving_entities
self.session['client'] = client.key.urlsafe()
On retrieval, use
client = ndb.Key(urlsafe=self.session['client']).get()

Related

AttributeError at admin: 'NoneType' object has no attribute 'startswith'

Below is my error:
AttributeError at /admin/r/31/3/
'NoneType' object has no attribute 'startswith'
Request Method: GET
Request URL: http://127.0.0.1:8000/admin/r/31/3/
Django Version: 3.2.13
Exception Type: AttributeError
Exception Value:
'NoneType' object has no attribute 'startswith'
Exception Location: C:\github\project\venv\lib\site-packages\django\contrib\contenttypes\views.py, line 41, in shortcut
Python Executable: C:\github\project\venv\Scripts\python.exe
Python Version: 3.7.1
This occurs when I'm trying to access certain type of model via admin, since I cannot access it through the tag related to get_absolute_url function of the model. The template appears, but never let me access the get_absolute_url.
The thing is, there is another model in another app which is almost identical in views.py, urls.py and models.py but only difference is 'permission_required' decorator which I can't sure if it's outdated.
views.py of error model.
from django.urls import reverse_lazy
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import login_required, permission_required
from .models import *
def landing(request):
return render(
request,
'instructor/landing.html'
)
def paymentrequired(request):
return render(
request,
'instructor/paymentrequired.html'
)
def lecture_in_category(request, category_slug=None):
current_category = get_object_or_404(Category, slug=category_slug)
categories = Category.objects.all()
lectures = Lecture.objects.filter(category=current_category)
return render(request, 'instructor/lecture_list.html',
{'current_category': current_category, 'categories': categories, 'lectures': lectures})
class LectureDetail(DetailView):
model = Lecture
def lecture_detail(request, id):
lecture = get_object_or_404(Lecture, id=id)
return render(request, 'instructor/lecture_detail.html', {'lecture':lecture})
# Create your views here.
models.py of the error page
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
import os
class Category(models.Model):
name = models.CharField(max_length=200, db_index=True)
meta_description = models.TextField(blank=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True, allow_unicode=True)
class Meta:
ordering = ['name']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('instructor:lecture_in_category', args=[self.slug])
class Lecture(models.Model):
title = models.CharField(max_length=40)
description = models.CharField(max_length=200, blank=True)
video_key = models.CharField(max_length=20, blank=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True, allow_unicode=True)
video_upload = models.FileField(upload_to='instructor/files/%Y/%m/%d', blank=True)
head_image = models.ImageField(upload_to='instructor/images/%Y/%m/%d', blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
available_display = models.BooleanField('Display', default=True)
author = models.CharField(max_length=40)
category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
class Meta:
ordering = ['-created_at']
index_together = [['id', 'slug']]
def __str__(self):
return self.title
def get_absolute_url(self):
reverse('instructor:lecture_detail', args=[self.id, self.slug])
# Create your models here.
urls.py of the error page
from django.urls import path
from . import views
from .views import *
app_name = 'instructor'
urlpatterns = [
path('', landing, name='landing'),
path('<slug:category_slug>/', lecture_in_category, name='lecture_list_category'),
path('<int:id>/<lecture_slug>/', LectureDetail.lecture_detail, name="lecture_detail"),
path('payment_required/', paymentrequired, name="paymentrequired"),
]
this is my database setting
DATABASES = {
'default': {
'ENGINE': os.environ.get("SQL_ENGINE", 'django.db.backends.sqlite3'),
'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')),
'USER': os.environ.get('SQL_USER', 'user'),
'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
'HOST': os.environ.get('SQL_HOST', 'localhost'),
'PORT': os.environ.get("SQL_PORT", '5432'),
}
}
This is the traceback.
Traceback (most recent call last):
File "C:\github\rhizomeedu\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\contrib\admin\sites.py", line 250, in wrapper
return self.admin_view(view, cacheable)(*args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\views\decorators\cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\contrib\admin\sites.py", line 232, in inner
return view(request, *args, **kwargs)
File "C:\github\rhizomeedu\venv\lib\site-packages\django\contrib\contenttypes\views.py", line 41, in shortcut
if absurl.startswith(('http://', 'https://', '//')):
AttributeError: 'NoneType' object has no attribute 'startswith'
With that model, the error doesn't appear so I once deleted the decorator but the result was same.
So I assume it's about settings.py ..?
Help me.

Getting mistake while importing xlsx file via django admin

# Line number: 1 - 'id'
# 28799772, 306509594, "GOLDEN NILE AAA" MChJ, 1726294, Toshkent shahri, Chilonzor tumani, X.TURSUNQULOV KOʻCHASI, 38-UY, 974079981, makhmudjon.khakimjonov#mail.ru, 47190
# Traceback (most recent call last):
# File "C:\Users\AbdulAziz\AppData\Local\Programs\Python\Python38\lib\site-packages\import_export\resources.py", line 708, in import_row
# instance, new = self.get_or_init_instance(instance_loader, row)
# File "C:\Users\AbdulAziz\AppData\Local\Programs\Python\Python38\lib\site-packages\import_export\resources.py", line 378, in get_or_init_instance
# instance = self.get_instance(instance_loader, row)
# File "C:\Users\AbdulAziz\AppData\Local\Programs\Python\Python38\lib\site-packages\import_export\resources.py", line 365, in get_instance
# import_id_fields = [
# File "C:\Users\AbdulAziz\AppData\Local\Programs\Python\Python38\lib\site-packages\import_export\resources.py", line 366, in <listcomp>
# self.fields[f] for f in self.get_import_id_fields()
# KeyError: 'id'
models.py
class Company(models.Model):
okpo = models.PositiveIntegerField(null=True,blank=True)
inn = models.PositiveIntegerField(null=True,blank=False)
name = models.CharField(max_length=25,blank=False,default='Tashkilot Nomi')
soato = models.PositiveIntegerField(null=True,blank=False)
address = models.CharField(max_length=50,blank=True,null=True,default='Tashkilot Adresi')
street = models.CharField(max_length=50,blank=True,null=True,default='Tashkilot Street')
phonenumber = models.CharField(max_length=13, blank=True, null=True,default='+998')
email = models.EmailField(max_length=25,default='tashkilot#email.com')
oked = models.PositiveIntegerField(null=True,blank=False)
resources.py
class CompanyResources(resources.ModelResource):
class Meta:
models = Company
fields = ('id','okpo','inn','name','soato','address','street','phonenumber','email','oked')
exclude = ['id']
import_id_fields = ['id']
admin.py
class CompanyAdmin(ImportExportActionModelAdmin):
resource_class = CompanyResources
list_display = [field.name for field in Company._meta.fields if field.name != "id"]
admin.site.register(Company,CompanyAdmin)
views.py
def import_file(request):
if request.method == 'POST' :
Company = CompanyResources()
dataset = Dataset()
new_employee = request.FILES['myfile']
data_import = dataset.load(new_employee.read())
result = CompanyResources.import_data(dataset,dry_run=True)
if not result.has_errors():
CompanyResources.import_data(dataset,dry_run=False)
return render(request, 'home.html',{})

How to make use of filter using ContentType to check if model instance is already present or not

I am trying to implement like functionality based on this . I want to restrict user to hit like on a event only once. But I am getting the following error. I have added full error details at bottom
Exception Type: AttributeError at /api/event/likes/create/
Exception Value: 'str' object has no attribute '_meta'
models.py
class ThumbsUpManager(models.Manager):
def create_by_model_type(self, model_type, slug, content, user, parent_obj=None):
model_qs = ContentType.objects.filter(model=model_type)
if model_qs.exists():
some_model = model_qs.first().model_class()
obj_qs = some_model.objects.filter(slug=slug)
if obj_qs.exists() and obj_qs.count() == 1:
instance = self.model()
instance.content = content
instance.user = user
instance.content_type = model_qs.first()
instance.object_id = obj_qs.first().id
if parent_obj:
instance.parent = parent_obj
instance.save()
return instance
return None
class Thumbsup(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE)
content = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=True)
objects = ThumbsUpManager()
class Meta:
ordering = ['-timestamp']
def __str__(self):
return str(self.user.username)
#property
def is_parent(self):
if self.parent is not None:
return False
return True
urls.py
urlpatterns = [
path('create/', ThumbsUpCreateAPIView.as_view(), name='create'),
]
view.py
class ThumbsUpCreateAPIView(CreateAPIView):
queryset = Thumbsup.objects.all()
permission_classes = [IsAuthenticated, ]
def get_serializer_class(self):
model_type = self.request.GET.get("type")
slug = self.request.GET.get("slug")
obj_qs = Thumbsup.objects.all()
print(obj_qs)
parent_id = self.request.GET.get("parent_id", None)
return create_thumbs_up_serializer(
model_type=model_type,
slug=slug,
parent_id=parent_id,
user=self.request.user
)
serializers.py
def create_thumbs_up_serializer(model_type=None, slug=None, parent_id=None, user=None):
class ThumbsUpCreateSerializer(ModelSerializer):
class Meta:
model = Thumbsup
fields = [
'id',
'content',
'timestamp',
]
def __init__(self, *args, **kwargs):
self.model_type = model_type
self.slug = slug
self.parent_obj = None
self.user = user
if parent_id:
parent_qs = Thumbsup.objects.filter(id=parent_id)
if parent_qs.exists() and parent_qs.count() == 1:
self.parent_obj = parent_qs.first()
return super(ThumbsUpCreateSerializer, self).__init__(*args, **kwargs)
def validate(self, data):
model_type = self.model_type
slug = self.slug
model_qs = ContentType.objects.filter(model=model_type)
if not model_qs.exists() or model_qs.count() != 1:
raise ValidationError("This is not a valid content type")
SomeModel = model_qs.first().model_class()
obj_qs = SomeModel.objects.filter(slug=self.slug)
if not obj_qs.exists() or obj_qs.count() != 1:
raise ValidationError("This is not a slug for this content type")
######################### ######################### #########################
How do I need to make query here to check if the user already liked the Event or not?
I tried the following way, but it is not working.
user_act = Thumbsup.objects.filter(user=self.user, content_type=ContentType.objects.get_for_model(model_type))
if user_act.exists():
raise ValidationError("You have already liked the event")
return data
def create(self, validated_data):
content = validated_data.get("content")
if user:
main_user = user
else:
main_user = User.objects.all().first()
model_type = self.model_type
slug = self.slug
parent_obj = self.parent_obj
thumbsup = Thumbsup.objects.create_by_model_type(
model_type, slug, content, main_user,
parent_obj=parent_obj,
)
return thumbsup
return ThumbsUpCreateSerializer
Traceback:
File "E:\GIT\blog\backend\venv\lib\site-packages\django\core\handlers\exception.py" in inner
34. response = get_response(request)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\views\generic\base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in dispatch
497. response = self.handle_exception(exc)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in handle_exception
457. self.raise_uncaught_exception(exc)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in raise_uncaught_exception
468. raise exc
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\views.py" in dispatch
494. response = handler(request, *args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\generics.py" in post
190. return self.create(request, *args, **kwargs)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\mixins.py" in create
18. serializer.is_valid(raise_exception=True)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\serializers.py" in is_valid
235. self._validated_data = self.run_validation(self.initial_data)
File "E:\GIT\blog\backend\venv\lib\site-packages\rest_framework\serializers.py" in run_validation
433. value = self.validate(value)
File "E:\GIT\test-heroku4\thumbsup\api\serializers.py" in validate
124. user_act = Thumbsup.objects.filter(user=self.user, content_type=ContentType.objects.get_for_model(model_type))
File "E:\GIT\blog\backend\venv\lib\site-packages\django\contrib\contenttypes\models.py" in get_for_model
40. opts = self._get_opts(model, for_concrete_model)
File "E:\GIT\blog\backend\venv\lib\site-packages\django\contrib\contenttypes\models.py" in _get_opts
27. model = model._meta.concrete_model
Exception Type: AttributeError at /api/event/likes/create/
Exception Value: 'str' object has no attribute '_meta'
I checked the model instance before saving in model manager like below and it is working fine. I do not know whether this is the correct way to do the task or not (I'm very new to django. Suggestions are most welcome)
def create_by_model_type(self, model_type, slug, content, user, parent_obj=None):
model_qs = ContentType.objects.filter(model=model_type)
if model_qs.exists():
some_model = model_qs.first().model_class()
obj_qs = some_model.objects.filter(slug=slug)
if obj_qs.exists() and obj_qs.count() == 1:
instance = self.model()
instance.content = content
instance.user = user
instance.content_type = model_qs.first()
instance.object_id = obj_qs.first().id
if parent_obj:
instance.parent = parent_obj
#### Here I have checked for existence before saving the instance ####
if Thumbsup.objects.filter(object_id=instance.object_id, user=instance.user).exists():
raise ValidationError({'already_liked': 'You have already liked the item'})
instance.save()
return instance
return None

Django model import issue via Python interpreter

I was trying to add data to my fields via the Python interpreter(manage.py shell). I can import the other two models (Tag, Startup), but Newslink model throws an error:
...
Traceback (most recent call last):
File "/usr/lib/python3.5/code.py line 91, in runcode
exec(code, self.locals)
File "<console>", line1 in <module>
ImportError: cannot import name 'Newslink'
Typed in Python interpreter:
from organizer.models import Tag
from organizer.models import Startup
from organizer.models import Newslink <--- issue
Here is my /organizer/models.py file:
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=31,unique = True)
slug = models.SlugField(
max_length=31,
unique = True,
help_text ="A label for URL config.")
def __str__(self):
return self.name.title()
class Meta:
ordering = ['name']
class Startup(models.Model):
name = models.CharField(
max_length=31
,db_index= True)
slug = models.SlugField(
max_length= 31,
unique = True,
help_text = "A label for URL config.")
description = models.TextField()
founded_date = models.DateField('date founded')
contact = models.EmailField()
website = models.URLField(max_length =255)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Meta:
ordering = ['name']
get_latest_by = 'founded_date'
class NewsLink(models.Model):
title = models.CharField(max_length=63)
pub_date = models.DateField('date published')
link = models.URLField(max_length=255)
startup = models.ForeignKey(Startup)
def __str__ (self):
return"{}:{}".format (self.startup, self.title)
class Meta:
verbose_name = 'news article'
ordering = ['-pub_date']
get_latest_by = 'pub_date'

angularjs http post image file to drf rest interface got error: AttributeError: 'OrderedDict' object has no attribute 'pk'

I am creating a system consisting angularjs frontend web app and DRF rest interface.
I can use command line 'curl' to upload image file to DRF rest interface, but when I use angularjs http post, I got the error message: 'OrderedDict' object has no attribute 'pk'
My DRF setup is as follows:
models.py:
def upload_to(instance, filename):
return 'post_image/{0}/{1}'.format(instance.author.id, filename)
class PostImage(models.Model):
author = models.ForeignKey(Author, blank=False, editable=False, related_name='images')
post = models.ForeignKey(Post, blank=False, editable=False, related_name='images')
image = models.ImageField(_('image'), blank=True, null=True, upload_to=upload_to)
created = models.DateTimeField(editable=False)
updated = models.DateTimeField(editable=False)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = timezone.now()
self.updated = timezone.now()
return super(PostImage, self).save(*args, **kwargs)
serializers.py
class PostImageSerializer(serializers.HyperlinkedModelSerializer):
author = serializers.HyperlinkedRelatedField(read_only=True, view_name='author-detail')
post = serializers.HyperlinkedRelatedField(read_only=True, view_name='post-detail')
class Meta:
model = PostImage
fields = ('url', 'image', 'author', 'post', 'created', 'updated')
views.py
class PostImageView(generics.ListCreateAPIView):
"""
List and Create post image endpoint
Allowed request method: Get, Post
"""
serializer_class = PostImageSerializer
permission_classes = [permissions.IsAuthenticated]
parser_classes = (FormParser, MultiPartParser, FileUploadParser,)
def get_queryset(self):
queryset = super(PostImageView, self).get_queryset()
return queryset.filter(post__pk=self.kwargs['pk'])
def perform_create(self, serializer):
post = Post.objects.get(pk=self.kwargs['pk'])
if 'upload' in self.request.data:
file_obj = self.request.data['upload']
serializer.save(author=self.request.user, post=post, image=file_obj)
return Response(status=status.HTTP_201_CREATED)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
I am using JWT authentication:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
) ,
}
Log error message:
Internal Server Error: /api/v1/post/22/image
Traceback (most recent call last):
File "/root/rest_drf/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/views.py", line 452, in dispatch
response = self.handle_exception(exc)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/views.py", line 449, in dispatch
response = handler(request, *args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/generics.py", line 244, in post
return self.create(request, *args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 21, in create
headers = self.get_success_headers(serializer.data)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 466, in data
ret = super(Serializer, self).data
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 215, in data
self._data = self.to_representation(self.validated_data)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 435, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/relations.py", line 264, in to_representation
return self.get_url(value, self.view_name, request, format)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/relations.py", line 199, in get_url
if obj.pk is None:
AttributeError: 'OrderedDict' object has no attribute 'pk'
[pid: 29484|app: 0|req: 2/4] 76.114.185.25 () {54 vars in 1242 bytes} [Sun Jan 24 16:41:13 2016] POST /api/v1/post/22/image => generated 107983 bytes in 153 msecs (HTTP/1.1 500) 2 headers in 92 bytes (1 switches on core 1)

Resources