我正在尝试通过POST使用django-tastypie
创建用户资源型号:
资源:
我一直收到错误
无法将关键字“city”解析为字段。选项包括:api_key,date_joined,email,first_name,groups,id,is_active,is_staff,is_superuser,last_login,last_name,logentry,password,profile,rating,user_permissions,username
我是django-tastypie的新手,但在我的代码或django / tastypie代码的跟踪中找不到错误。它为什么这样做? 我的代码基于以下博文:http://psjinx.com/programming/2013/06/07/so-you-want-to-create-users-using-djangotastypie/
提前谢谢大家!!
Models.py
from django.utils.translation import ugettext as gtext
class UserProfile(models.Model):
"""
A Model to store extra information for each user
"""
user = models.OneToOneField(User, related_name='profile')
gender = models.CharField(gtext("gender"), max_length=10)
city = models.CharField(gtext("city"), max_length=20)
def __unicode__(self):
return self.user.get_full_name()
Api.py
class CreateUserResource(ModelResource):
user = fields.ForeignKey('RecommenuAPI.api.UserResource', 'user', full=True)
class Meta:
allowed_methods = ['post']
always_return_data = True
authentication = Authentication()
authorization = Authorization()
queryset = UserProfile.objects.all()
resource_name = "create_user"
always_return_data = True
def hydrate(self, bundle):
"""
Makes sure all required fields in UserProfile
and User are fulfilled. Custom error message returned if not
"""
REQUIRED_USER_PROFILE_FIELDS = ( "city", "gender", "user")
for field in REQUIRED_USER_PROFILE_FIELDS:
if field not in bundle.data["user"]:
raise CustomBadRequest(
code = "missing_key",
message = "Must provide {missing_key} when creating a user."
.format(missing_key=field))
REQUIRED_USER_FIELDS = ("username", "email", "first_name", "last_name", "raw_password")
for field in REQUIRED_USER_FIELDS:
if field not in bundle.data["user"]:
raise CustomBadRequest(
code = "missing_key",
message="Must provide {missing_key} when creating a user."
.format(missing_key=field))
return bundle
def obj_create(self, bundle, **kwargs):
"""
Creates new user. Checks for existing password
and email match.
"""
try:
email = bundle.data["user"]["email"]
username = bundle.data["user"]["username"]
if User.objects.filter(email=email):
raise CustomBadRequest(
code = "duplicate_exception",
message = "That email is already used.")
if User.objects.filter(username=username):
raise CustomBadRequest(
code = "duplicate_exception",
message = "That username is already used")
except KeyError as missing_key:
raise CustomBadRequest(
code = "missing_key",
message = "Must provide {missing_key} when creating a user."
.format(missing_key=missing_key))
except User.DoesNotExist:
pass
#setting resource_name to 'user_profile' here because we want
#resource_uri in response to be same as UserProfileResource resource
self._meta.resource_name = UserProfileResource._meta.resource_name
return super(CreateUserResource, self).obj_create(bundle, **kwargs)
class UserResource(ModelResource):
# We need to store raw password in a virtual field because hydrate method
# is called multiple times depending on if it is a POST/PUT/PATCH request
raw_password = fields.CharField(attribute=None, readonly=True, null=True, blank=True)
class Meta:
# For authentication, allow both basic and api key so that the key
# can be grabbed, if needed
authentication = MultiAuthentication(
BasicAuthentication(),
ApiKeyAuthentication())
authorization = Authorization()
# Because this can be updated nested under the UserProfile, it needed
# 'put'. No idea why, since patch is supposed to be able to handle
# partial updates
allowed_methods = ['get', 'patch', 'put']
always_return_data = True
queryset = User.objects.all().select_related("api_key")
excludes = ['is_active', 'is_staff', 'is_superuser', 'date_joined', 'last_login']
def authorized_read_list(self, object_list, bundle):
return object_list.filter(id=bundle.request.user.id).select_related()
def hydrate(self, bundle):
if "raw_password" in bundle.data:
# Pop our raw_password and validate it
# This will prevent re-validation because hydrate is called multiple times
# "Cannot resolve keyword 'raw_password' into field." wont occur
raw_password = bundle.data.pop["raw_password"]
#Validate password
if not validate_password(raw_password):
if len(raw_password) < MINIMUM_PASSWORD_LENGTH:
raise CustomBadRequest(
code="invalid_password",
message=(
"Your password should contain at least {length} "
"characters.".format(length=
MINIMUM_PASSWORD_LENGTH)))
raise CustomBadRequest(
code="invalid_password",
message=("Your password should contain at least one number"
", one uppercase letter, one special character,"
" and no spaces."))
bundle.data["password"] = make_password(raw_password)
return bundle
def dehydrate(self, bundle):
bundle.data["key"] = bundle.obj.api_key.key
try:
#Don't return 'raw_password' in response
del bundle.data["raw_password"]
except KeyError:
pass
return bundle
class UserProfileResource(ModelResource):
user = fields.ForeignKey(UserResource, 'user', full=True)
class Meta:
# For authentication, allow both basic and api key so that the key
# can be grabbed, if needed
authentication = MultiAuthentication(
BasicAuthentication(),
ApiKeyAuthentication())
authorization = Authorization()
always_return_data = True
allowed_methods = ['get', 'patch', ]
detail_allowed_methods = ['get', 'patch', 'put']
queryset = UserProfile.objects.all()
resource_name = 'user_profile'
def authorized_read_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user).select_related()
## Since there is only one user profile object, call get_detail instead
def get_list(self, request, **kwargs):
kwargs["pk"] = request.user.profile.pk
return super(UserProfileResource, self).get_detail(request, **kwargs)
[编辑]添加痕迹
Traceback (most recent call last):
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 217, in wrapper
response = callback(request, *args, **kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 459, in dispatch_list
return self.dispatch('list', request, **kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 491, in dispatch
response = method(request, **kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 1357, in post_list
updated_bundle = self.obj_create(bundle, **self.remove_api_resource_names(kwargs))
File \"/Users/Carlos/PycharmProjects/RecommenuBackend/RecommenuAPI/api.py\", line 82, in obj_create
return super(CreateUserResource, self).obj_create(bundle, **kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 2149, in obj_create
bundle = self.full_hydrate(bundle)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 909, in full_hydrate
value = field_object.hydrate(bundle)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/fields.py\", line 737, in hydrate
return self.build_related_resource(value, request=bundle.request)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/fields.py\", line 661, in build_related_resource
return self.resource_from_data(self.fk_resource, value, **kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/fields.py\", line 605, in resource_from_data
return fk_resource.obj_update(fk_bundle, skip_errors=True, **data)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 2205, in obj_update
bundle.obj = self.obj_get(bundle=bundle, **lookup_kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/tastypie/resources.py\", line 2125, in obj_get
object_list = self.get_object_list(bundle.request).filter(**kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/django/db/models/query.py\", line 655, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/django/db/models/query.py\", line 673, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File \"/Users/Carlos/.virtualenvs/recommenu/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1266, in add_q
can_reuse=us(
答案 0 :(得分:0)
CreateUserResource
提供UserProfile
个对象。在此资源user
字段中是User
对象。 User
对象没有city
字段。 city
是UserProfile
字段。
更改您的请求以及dehydrate
功能的一部分:
REQUIRED_USER_PROFILE_FIELDS = ( "city", "gender", "user")
for field in REQUIRED_USER_PROFILE_FIELDS:
if field not in bundle.data: