2013-10-01 17 views
0

我试图通过POST来创建一个用户资源与Django的tastypieDjango的 - TastyPie不能关键词解析成场

型号:

  • 用户配置
  • 用户(从django.contrib.auth。型号)

资源:

  • CreateUserResource
  • UserResource
  • UserProfileResrouce

我不断收到错误

无法解析关键词 '城市' 到现场。选项包括:API_KEY,date_joined,电子邮件,FIRST_NAME,组ID,IS_ACTIVE,is_staff,is_superuser,LAST_LOGIN,姓氏,logentry,密码,个人资料,等级,user_permissions,用户名

我是新来的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

CreateUserResource提供UserProfile对象。在此资源user字段中是User对象。 User对象没有city字段。 city是一个UserProfile字段。

改变你dehydrate功能的要求,THID部分:

REQUIRED_USER_PROFILE_FIELDS = ("city", "gender", "user") 
for field in REQUIRED_USER_PROFILE_FIELDS: 
    if field not in bundle.data: