Django-tastypie: ์˜ค๋ฅ˜: "ํด๋ž˜์Šค ๋ฉ”ํƒ€์— 'object_class' ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค."

์— ๋งŒ๋“  2016๋…„ 07์›” 21์ผ  ยท  6์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: django-tastypie/django-tastypie

์•ˆ๋…•ํ•˜์„ธ์š”,

๋‚ด tastypie๋ฅผ 13.3์—์„œ ํ—ค๋“œ๋กœ ์—…๋ฐ์ดํŠธํ–ˆ์„ ๋•Œ ์›น ์•ฑ์„ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Request Method: GET
Request URL: http://192.168.0.104:8888/accounts/login/?next=/dashboard/

Django Version: 1.8.8
Python Version: 2.7.12
Installed Applications:
('longerusernameandemail',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'tastypie',
 'myapp',
 'widget_tweaks',
 'corsheaders')
Installed Middleware:
('corsheaders.middleware.CorsMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')

Traceback:
File "/home/user/anaconda2/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  119.                 resolver_match = resolver.resolve(request.path_info)
File "/home/user/anaconda2/lib/python2.7/site-packages/django/core/urlresolvers.py" in resolve
  365.             for pattern in self.url_patterns:
File "/home/user/anaconda2/lib/python2.7/site-packages/django/core/urlresolvers.py" in url_patterns
  401.         patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/home/user/anaconda2/lib/python2.7/site-packages/django/core/urlresolvers.py" in urlconf_module
  395.             self._urlconf_module = import_module(self.urlconf_name)
File "/home/user/anaconda2/lib/python2.7/importlib/__init__.py" in import_module
  37.     __import__(name)
File "/home/user/webserver/myapp/urls.py" in <module>
  7. from myapp.api import UserResource
File "/home/user/webserver/myapp/api.py" in <module>
  303. class MyResource(ModelResource):
File "/home/user/anaconda2/lib/python2.7/site-packages/tastypie/resources.py" in __new__
  1797.             if meta and meta.object_class:

Exception Type: AttributeError at /accounts/login/
Exception Value: class Meta has no attribute 'object_class'

๋ฒ„์ „ 13.3์œผ๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•˜๋ฉด(a71dd6e85e18ec38e978e904c0c7a91dee11043d ์ปค๋ฐ‹) ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋ฌด์—‡์ด ์ž˜๋ชป๋˜์—ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
๊ฐ์‚ฌ ํ•ด์š”

bug unconfirmed

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@SeanHayes : ์ถ”์ƒ ๊ธฐ๋ณธ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฉ๊ธˆ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์žฌ์ƒ์‚ฐ์ž…๋‹ˆ๋‹ค.

class BaseResource(ModelResource):
    class Meta:
        authentication = DefaultAuthentication()

class FooResource(BaseResource):
    class Meta(BaseResource.Meta):
        resource_name = 'foo'
        queryset = Foo.objects.all()

class BarResource(BaseResource):
    class Meta(BaseResource.Meta):
        resource_name = 'bar'
        queryset = Bar.objects.all()

BaseResource์— ์ฟผ๋ฆฌ ์„ธํŠธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— class BaseResource(ModelResource): ํ–‰์— hashhemian์ด ๋ถ™์—ฌ๋„ฃ์€ ๋™์ผํ•œ ์Šคํƒ ์ถ”์ ์œผ๋กœ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ object_class = None ๋ฅผ BaseResource.Meta ์— ์ถ”๊ฐ€ํ•˜๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ์ˆ˜์ • ์‚ฌํ•ญ์€ resources.py ํ–‰ 1797์„ if meta and getattr(meta, 'object_class'):

... ๋˜๋Š” ์ฟผ๋ฆฌ ์„ธํŠธ๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์„ ๋•Œ ModelResource ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น ์˜ค๋ฅ˜๊ฐ€ ๋” ๋ช…์‹œ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด BaseResource๊ฐ€ ์‹คํŒจํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„๋กœ ์—ฌ๊ธฐ์—์„œ ํ•˜๋ ค๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌ ํ•ด์š”!

๋ชจ๋“  6 ๋Œ“๊ธ€

๋ฆฌ์†Œ์Šค๋ฅผ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚ด urls.py์—์„œ tastypie.api.Api ๋ฅผ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ ๋ฆฌ์†Œ์Šค๋ฅผ ํ•˜๋‚˜์”ฉ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ฆฌ์†Œ์Šค๋ฅผ ๋กœ๋“œํ•˜๋ ค๊ณ  ํ•˜์ž๋งˆ์ž ์‹คํŒจํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ์€ ๋ฆฌ์†Œ์Šค ์ค‘ ํ•˜๋‚˜์ด์ง€๋งŒ ์ด๊ฒƒ์„ ์ฃผ์„ ์ฒ˜๋ฆฌํ•ด๋„ ๋‹ค์Œ ๋ฆฌ์†Œ์Šค์—์„œ ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค.

class MyResource(ModelResource):
    class Meta:
        queryset = MyModel.objects.all()
        fields = ['my_field']
        allowed_methods = ['get']
        resource_name = 'my_resource'
        authentication = BasicAuthentication()
        include_resource_uri = False

๋ฐฉ๊ธˆ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์ง€๋งŒ ์˜ค๋ฅ˜๋ฅผ ์žฌํ˜„ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. 3e1f5527b698c7121d4c5434d073b08d364d31f2

๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ฝ”๋“œ ์ƒ˜ํ”Œ์ด ์‹ค์ œ ์ฝ”๋“œ์™€ ์–ผ๋งˆ๋‚˜ ๊ฐ€๊น์Šต๋‹ˆ๊นŒ?

์ด์— ๋Œ€ํ•ด ์กฐ์‚ฌํ•œ Sean์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” ๋งค์šฐ ์œ ์‚ฌํ•˜๋ฉฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋ฆ„๋งŒ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‚ด ๋์—์„œ ๋‹ค์‹œ ํ™•์ธํ•˜๊ณ  ๊ด€๋ จ์„ฑ์ด ์žˆ๊ณ  ๋ˆ„๋ฝ ๋œ ์š”์†Œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ, ๋” ์ž์„ธํ•œ ์ •๋ณด๊ฐ€ ์žˆ์œผ๋ฉด ์–ธ์ œ๋“ ์ง€ ๋Œ“๊ธ€์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š”.

@SeanHayes : ์ถ”์ƒ ๊ธฐ๋ณธ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฉ๊ธˆ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์žฌ์ƒ์‚ฐ์ž…๋‹ˆ๋‹ค.

class BaseResource(ModelResource):
    class Meta:
        authentication = DefaultAuthentication()

class FooResource(BaseResource):
    class Meta(BaseResource.Meta):
        resource_name = 'foo'
        queryset = Foo.objects.all()

class BarResource(BaseResource):
    class Meta(BaseResource.Meta):
        resource_name = 'bar'
        queryset = Bar.objects.all()

BaseResource์— ์ฟผ๋ฆฌ ์„ธํŠธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— class BaseResource(ModelResource): ํ–‰์— hashhemian์ด ๋ถ™์—ฌ๋„ฃ์€ ๋™์ผํ•œ ์Šคํƒ ์ถ”์ ์œผ๋กœ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ object_class = None ๋ฅผ BaseResource.Meta ์— ์ถ”๊ฐ€ํ•˜๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ์ˆ˜์ • ์‚ฌํ•ญ์€ resources.py ํ–‰ 1797์„ if meta and getattr(meta, 'object_class'):

... ๋˜๋Š” ์ฟผ๋ฆฌ ์„ธํŠธ๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์„ ๋•Œ ModelResource ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น ์˜ค๋ฅ˜๊ฐ€ ๋” ๋ช…์‹œ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด BaseResource๊ฐ€ ์‹คํŒจํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„๋กœ ์—ฌ๊ธฐ์—์„œ ํ•˜๋ ค๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌ ํ•ด์š”!

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰