Django - TastyPie 无法将关键字解析为字段



我正在尝试使用 django-tastypie 通过 POST 创建一个用户资源

模型:

  • 用户配置文件
  • 用户(来自django.contrib.auth.models)

资源:

  • 创建用户资源
  • 用户资源
  • UserProfileResrouce

我不断收到错误

无法将关键字"city"解析为字段。选项包括:api_key、date_joined、电子邮件、first_name、组、ID、is_active、is_staff、is_superuser、last_login、last_name、日志条目、密码、配置文件、评级、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(

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:

最新更新