authtoken.Token.user :(字段E304)“ Token.user”的反向访问者与

时间:2019-04-12 12:44:20

标签: django django-rest-framework

我已经阅读了很多与clashes reverse accessor相关的问题,但似乎没有什么帮助我。

我正在尝试自定义Token中的DRF字段,以便能够向其中添加一些字段(我希望每个Token有一个CompanyCompanies可以创建FiscalEntities,每个FiscalEntity都有自己的Token

我关注了以下问题:How to use custom token model in Django Rest Framework

核心/型号

from django.db import models
from django.utils.translation import ugettext_lazy as _
from rest_framework import authentication


from company.models import Company
from fiscalentity.models import FiscalEntity


class CustomAuthenticationToken(models.Model):
    """
    The default authorization token model.
    """
    key = models.CharField(_("Key"), max_length=40, primary_key=True)
    company = models.OneToOneField(
        Company, related_name='auth_token',
        on_delete=models.CASCADE, verbose_name=_("Company")
    )
    created = models.DateTimeField(_("Created"), auto_now_add=True)
    # Fiscal entity can be null because if it is null this token belongs to the parent Company
    fiscal_entity = models.ForeignKey(FiscalEntity, null=True, on_delete=models.CASCADE)

    class Meta:
        verbose_name = _("Token")
        verbose_name_plural = _("Tokens")

    def save(self, *args, **kwargs):
        if not self.key:
            self.key = self.generate_key()
        return super(CustomAuthenticationToken, self).save(*args, **kwargs)

    @staticmethod
    def generate_key():
        return binascii.hexlify(os.urandom(20)).decode()

    def __str__(self):
        return self.key


class BearerAuthentication(authentication.TokenAuthentication):
    """
    Simple token based authentication using utvsapitoken.

    Clients should authenticate by passing the token key in the 'Authorization'
    HTTP header, prepended with the string 'Bearer '.  For example:

    Authorization: Bearer 956e252a-513c-48c5-92dd-bfddc364e812
    """
    keyword = 'Bearer'
    model = CustomAuthenticationToken

核心/身份验证

from rest_framework.authentication import TokenAuthentication

from core.models import CustomAuthenticationToken


class CustomTokenAuthentication(TokenAuthentication):
    model = CustomAuthenticationToken

应用/设置

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
    'core',
    ...
]

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 5,
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'core.models.BearerAuthentication',
        'core.authentication.CustomTokenAuthentication'
    ),
}

AUTHENTICATION_BACKENDS = [
    'core.models.BearerAuthentication',
]

尝试运行迁移时出现以下错误:

authtoken.Token.user: (fields.E304) Reverse accessor for 'Token.user' clashes with reverse accessor for 'CustomAuthenticationToken.company'.
    HINT: Add or change a related_name argument to the definition for 'Token.user' or 'CustomAuthenticationToken.company'.
authtoken.Token.user: (fields.E305) Reverse query name for 'Token.user' clashes with reverse query name for 'CustomAuthenticationToken.company'.
    HINT: Add or change a related_name argument to the definition for 'Token.user' or 'CustomAuthenticationToken.company'.
core.CustomAuthenticationToken.company: (fields.E304) Reverse accessor for 'CustomAuthenticationToken.company' clashes with reverse accessor for 'Token.user'.
    HINT: Add or change a related_name argument to the definition for 'CustomAuthenticationToken.company' or 'Token.user'.
core.CustomAuthenticationToken.company: (fields.E305) Reverse query name for 'CustomAuthenticationToken.company' clashes with reverse query name for 'Token.user'.
    HINT: Add or change a related_name argument to the definition for 'CustomAuthenticationToken.company' or 'Token.user'.

我尝试省略

company = models.OneToOneField(
        Company, related_name='auth_token',
        on_delete=models.CASCADE, verbose_name=_("Company")
    )

但是这样做,我收到一个新错误,说Invalid field name(s) given in select_related: 'user'. Choices are: (fiscal_entity)

谢谢您的帮助

1 个答案:

答案 0 :(得分:1)

我遵循的答案(How to use custom token model in Django Rest Framework)适用于具有默认Custom Tokens实现的Token。由于我正在使用BearerAuthentication,因此我需要重写从authenticate_credentials继承的方法TokenAuthentication。最后,我的结局BearerAuthentication如下所示:

class BearerAuthentication(authentication.TokenAuthentication):
    """
    Simple token based authentication using utvsapitoken.

    Clients should authenticate by passing the token key in the 'Authorization'
    HTTP header, prepended with the string 'Bearer '.  For example:

    Authorization: Bearer 956e252a-513c-48c5-92dd-bfddc364e812
    """
    keyword = 'Bearer'
    model = CustomAuthenticationToken

    def authenticate_credentials(self, key):
        model = self.get_model()
        try:
            token = model.objects.select_related('company').get(key=key)
        except model.DoesNotExist:
            raise exceptions.AuthenticationFailed(_('Invalid token.'))

        if not token.company.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        return token.company, token