如何配置 Tastypie 将字段视为唯一字段?

发布于 2024-12-05 05:29:14 字数 2551 浏览 0 评论 0原文

如何配置 Tastypie 将字段视为唯一字段?如果我尝试为标记为唯一的字段插入重复条目,我的期望是收到某种非 500 错误(可能是 409 冲突?)作为响应。


我已经浏览了文档,看起来这对我来说应该是显而易见的,但由于某种原因,我没有得到我期望看到的响应。

这是文档链接:

http://readthedocs.org/ docs/django-tastypie/en/latest/fields.html?highlight=unique


示例代码如下:

urls.py

v1_api = Api(api_name='v1')
v1_api.register(CompanyResource())

urlpatterns = patterns('',
    (r'^api/', include(v1_api.urls)),
)

resources.py

class CompanyResource(ModelResource):

    CompanyName = fields.CharField(attribute='company_name')
    CompanyId = fields.CharField(attribute='company_id', unique=True)
    Contact = fields.CharField(attribute='contact')
    Email = fields.CharField(attribute='email')
    Phone = fields.CharField(attribute='phone')

    class Meta:
        queryset = Company.objects.all()
        authentication = BasicAuthentication()
        authorization = Authorization()
        allowed_methods = ['get', 'post']

models.py

class Company(models.Model):

    company_name = models.TextField(default=None, blank=True, null=True)
    company_id = models.CharField(default='', unique=True, db_index=True, max_length=20)
    contact = models.TextField(default=None, blank=True, null=True)
    email = models.EmailField(default=None, blank=True, null=True)
    phone = models.TextField(default=None, blank=True, null=True)

我收到的错误是以下(使用curl来访问我的本地服务):

curl --dump-header - -H "Content-Type: application/json" -X POST --user user:password --data '{"CompanyName": "company", "CompanyId": "1234567890", "Contact": "John", "Email": "[email protected]", "Phone": "555-555-5555"}' http://localhost:8000/api/v1/company/
HTTP/1.0 500 INTERNAL SERVER ERROR
Date: Thu, 15 Sep 2011 18:25:20 GMT
Server: WSGIServer/0.1 Python/2.7.1
Content-Type: application/json; charset=utf-8

{"error_message": "(1062, \"Duplicate entry '1234567890' for key 'api_company_company_id_uniq'\")", 
...<snip>...
raise errorclass, errorvalue\n\nIntegrityError: (1062, \"Duplicate entry '1234567890' for key 'api_company_company_id_uniq'\")\n"}

当我从公司模型中删除unique=True, db_index=True,时,我没有收到完整性错误,而是收到一个新的重复错误资源已创建。同样,这不是预期的结果,因为我期望 unique 执行一些验证并导致一些非 500 响应。

How do I configure Tastypie to treat a field as unique? My expectation would be to receive some sort of non-500 error (possibly a 409 conflict?) as a response if I try to insert duplicate entries for the field marked as unique.


I've looked through the docs and it looks like it should be obvious to me, but for some reason I'm not getting the response I would expect to see.

Here's the documentation link:

http://readthedocs.org/docs/django-tastypie/en/latest/fields.html?highlight=unique


The sample code is as follows:

urls.py

v1_api = Api(api_name='v1')
v1_api.register(CompanyResource())

urlpatterns = patterns('',
    (r'^api/', include(v1_api.urls)),
)

resource.py

class CompanyResource(ModelResource):

    CompanyName = fields.CharField(attribute='company_name')
    CompanyId = fields.CharField(attribute='company_id', unique=True)
    Contact = fields.CharField(attribute='contact')
    Email = fields.CharField(attribute='email')
    Phone = fields.CharField(attribute='phone')

    class Meta:
        queryset = Company.objects.all()
        authentication = BasicAuthentication()
        authorization = Authorization()
        allowed_methods = ['get', 'post']

models.py

class Company(models.Model):

    company_name = models.TextField(default=None, blank=True, null=True)
    company_id = models.CharField(default='', unique=True, db_index=True, max_length=20)
    contact = models.TextField(default=None, blank=True, null=True)
    email = models.EmailField(default=None, blank=True, null=True)
    phone = models.TextField(default=None, blank=True, null=True)

The error I receive is the following (using curl to hit my local service):

curl --dump-header - -H "Content-Type: application/json" -X POST --user user:password --data '{"CompanyName": "company", "CompanyId": "1234567890", "Contact": "John", "Email": "[email protected]", "Phone": "555-555-5555"}' http://localhost:8000/api/v1/company/
HTTP/1.0 500 INTERNAL SERVER ERROR
Date: Thu, 15 Sep 2011 18:25:20 GMT
Server: WSGIServer/0.1 Python/2.7.1
Content-Type: application/json; charset=utf-8

{"error_message": "(1062, \"Duplicate entry '1234567890' for key 'api_company_company_id_uniq'\")", 
...<snip>...
raise errorclass, errorvalue\n\nIntegrityError: (1062, \"Duplicate entry '1234567890' for key 'api_company_company_id_uniq'\")\n"}

When I remove unique=True, db_index=True, from the Company model, I don't receive the Integrity error, but instead, a new, duplicate resource is created. Again, this isn't the expected result as I would expect unique to preform some validation and cause some non-500 response.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

許願樹丅啲祈禱 2024-12-12 05:29:14

以下是我解决问题的方法:

根据验证文档,我能够实现一个自定义验证器来为我检查字段的唯一性。
http://django-tastypie.readthedocs.org/en/latest/validation。 在CompanyResource

中,我向类元添加了 CustomValidation。我将 CustomValidation 的实现放置在validations.py 文件中。如果 isValid 返回错误,API 将返回 400,并包含错误中的消息。

class CompanyResource(ModelResource):
    """
    CompanyIds should be unique
    """     
    CompanyName = fields.CharField(attribute='company_name')     
    CompanyId = fields.CharField(attribute='company_id', unique=True)     
    Contact = fields.CharField(attribute='contact')     
    Email = fields.CharField(attribute='email')     
    Phone = fields.CharField(attribute='phone')    

    class Meta:        
        queryset = Company.objects.all()        
        authentication = BasicAuthentication()        
        authorization = Authorization()        
        allowed_methods = ['get', 'post']                
        validation = CustomValidation()

验证.py

class CustomValidation(Validation):
    """
    The custom validation checks two things:
       1) that there is data
       2) that the CompanyId exists (unique check)
    """
    def is_valid(self, bundle, request=None):
        if not bundle.data:
            return {'__all__': 'Missing data, please include CompanyName, CompanyId, Contact, Email, and Phone.'}

        errors = {}                                    
        company_id=bundle.data.get('CompanyId', None)

        # manager method, returns true if the company exists, false otherwise
        if Company.objects.company_exists(company_id):
            errors['CompanyId']='Duplicate CompanyId, CompanyId %s already exists.' % company_id
        return errors

Here is how I solved the problem:

Based on the documentation for validation, I was able to implement a custom validator that checked the uniqueness of the field for me.
http://django-tastypie.readthedocs.org/en/latest/validation.html

In the CompanyResource, I added to the class meta a CustomValidation. I placed the implementation for CustomValidation in a validations.py file. If isValid returns errors, the api will return a 400 with the messages included in errors.

class CompanyResource(ModelResource):
    """
    CompanyIds should be unique
    """     
    CompanyName = fields.CharField(attribute='company_name')     
    CompanyId = fields.CharField(attribute='company_id', unique=True)     
    Contact = fields.CharField(attribute='contact')     
    Email = fields.CharField(attribute='email')     
    Phone = fields.CharField(attribute='phone')    

    class Meta:        
        queryset = Company.objects.all()        
        authentication = BasicAuthentication()        
        authorization = Authorization()        
        allowed_methods = ['get', 'post']                
        validation = CustomValidation()

validations.py

class CustomValidation(Validation):
    """
    The custom validation checks two things:
       1) that there is data
       2) that the CompanyId exists (unique check)
    """
    def is_valid(self, bundle, request=None):
        if not bundle.data:
            return {'__all__': 'Missing data, please include CompanyName, CompanyId, Contact, Email, and Phone.'}

        errors = {}                                    
        company_id=bundle.data.get('CompanyId', None)

        # manager method, returns true if the company exists, false otherwise
        if Company.objects.company_exists(company_id):
            errors['CompanyId']='Duplicate CompanyId, CompanyId %s already exists.' % company_id
        return errors
天邊彩虹 2024-12-12 05:29:14

我今天也遇到了同样的问题。以下是我的处理方法:

覆盖资源定义中的 [request_method]_[request_type] 方法。例如,我覆盖 FooResource 中的 post_list:

def post_list(self, request, **kwargs):
    from django.db import IntegrityError
    try:
        return super(FooResource, self).post_list(request, **kwargs)
    except IntegrityError, e:
        if e.args[0] == 1062:
            return http.HttpConflict()

希望它对您有用。

I had the same problem today. Here is how I deal with it:

Override [request_method]_[request_type] method in your resource definition. For example, I override post_list in FooResource:

def post_list(self, request, **kwargs):
    from django.db import IntegrityError
    try:
        return super(FooResource, self).post_list(request, **kwargs)
    except IntegrityError, e:
        if e.args[0] == 1062:
            return http.HttpConflict()

Hope it works for you.

何必那么矫情 2024-12-12 05:29:14

无论如何,我创建了一个稍微不同的解决方案,它更适合我。它基于 thoslin 的答案。

我发现 e.args[0] == 1062 检查对我来说失败了。我很确定这是一个 MySQL 错误,而且我正在使用 Postgres。

我还在 obj_create 方法中实现了这一点,以便它将处理所有对象创建,而不仅仅是通过 post_list 完成的对象创建。

from tastypie.exceptions import ImmediateHttpResponse
from tastypie.http import HttpConflict
from django.db import IntegrityError

...

class MyBaseResource(ModelResource):
    def obj_create(self, bundle, **kwargs):
        try:
            return super(MyBaseResource, self).obj_create(bundle, **kwargs)
        except IntegrityError, e:
            if e.args[0] == 1062 or e.args[0].startswith('duplicate key'):
                raise ImmediateHttpResponse(HttpConflict())

...

class MyResource(MyBaseResource):
    [usual resource stuff]

For what it's worth, I've created a slightly different solution that works better for me. It's based on thoslin's answer.

I found that the e.args[0] == 1062 check fails for me. I'm pretty sure this is a MySQL error and I'm using Postgres.

I also implemented this in the obj_create method so that it will handle all object creation, not just that done via post_list.

from tastypie.exceptions import ImmediateHttpResponse
from tastypie.http import HttpConflict
from django.db import IntegrityError

...

class MyBaseResource(ModelResource):
    def obj_create(self, bundle, **kwargs):
        try:
            return super(MyBaseResource, self).obj_create(bundle, **kwargs)
        except IntegrityError, e:
            if e.args[0] == 1062 or e.args[0].startswith('duplicate key'):
                raise ImmediateHttpResponse(HttpConflict())

...

class MyResource(MyBaseResource):
    [usual resource stuff]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文