为什么同一个序列化器在Django中会产生不同的结果呢?

tkclm6bt  于 2023-06-25  发布在  Go
关注(0)|答案(1)|浏览(93)

我正面临着一个相当恼人的问题,而不是一个困难的问题。问题如下:

  • 一个名为UserSerializer的给定djangorestframework ModelSerializer类使用来自模型的FileField属性的正确图像结果序列化经过身份验证的用户示例
  • 当调用djangorestframework的一些通用API视图,并使用完全相同的序列化程序时,默认情况下,图像路径接收域地址

Django版本:4.2.2,Django REST Framework版本:3.14

我希望在输出中接收的内容:Django文档中提到的存储文件的路径(MEDIA_URL是'media/'),没有附加localhost域。

下图显示在RootLayout中,我收到了以/media/etc开头的正确路径。因此,我根据模式从环境变量中附加域地址,而在UsersLayout中,每个用户从某处获得我MANUAL附加域和一个自动域。

这是我的urls.py

from django.urls import include, path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

from .views import *

urlpatterns = [
path('change-password/<int:pk>', UserChangePasswordView.as_view(), name='auth_change_password'),  # ---- Untestable
path('languages/', LanguagesL.as_view()),  # ----------------------------------------------------------- Tested
path('password_reset/', include('django_rest_passwordreset.urls', namespace='password_reset')),  # -----
path('payment/barion/ipn/', PaymentBarionIPN.as_view()),  # -------------------------------------------- Untestable
path('payment/barion/start/<int:pk>', UserSubscriptionCreateStart.as_view()),  # ----------------------- Untestable
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),  # ----------------------------
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),  # ---------------------------
path('user-factor-relation-strategies/', UserFactorRelationStrategiesLC.as_view()),  # ----------------- Tested
path('user-factor-relation-strategies/history/', UserFactorRelationStrategiesHistory.as_view()),  # -----
path('user-factor-relations/', UserFactorRelationsLC.as_view()),  # ------------------------------------ Tested
path('user-factor-relations/history/<int:pk>', UserFactorRelationsHistory.as_view()),  # ---------------
path('user-factors/', UserFactorsLC.as_view()),  # ----------------------------------------------------- Tested
path('user-factors/history/', UserFactorsHistory.as_view()),  # -----------------------------------------
path('user-operative-actions/', UserOperativeActionsLC.as_view()),  # ---------------------------------- Tested
path('user-operative-actions/history/', UserOperativeActionsHistory.as_view()),  # ----------------------
path('user-swots/', UserSwotsLC.as_view()),  # --------------------------------------------------------- Tested
path('user-swots/<int:pk>', UserSwotsRUD.as_view()),  # ------------------------------------------------ Tested
path('users/', UsersLC.as_view()),  # ------------------------------------------------------------------ Tested
path('users/<int:pk>', UsersRU.as_view()),  # ---------------------------------------------------------  Tested
path('users/authenticated/', AuthenticatedUser.as_view()),  # ------------------------------------------ Tested
]

以上就是提到的观点

class UsersLC(generics.ListCreateAPIView):
permission_classes = [IsStaffOrWriteOnly]
serializer_class = UserSerializer

def get_queryset(self):
    queryset = User.objects.all().prefetch_related('usersubscription_set')
    email = self.request.query_params.get('email')
    return queryset.filter(email__icontains=email) if email else queryset

class AuthenticatedUser(generics.GenericAPIView):
serializer_class = UserSerializer

def get_object(self):
    return self.request.user

def get(self, request):
    return Response(self.serializer_class(self.get_object()).data, status=status.HTTP_200_OK)

这是我的序列化程序类

class UserSerializer(ModelSerializer):
full_name = ReadOnlyField()
has_billing_information = ReadOnlyField()
has_valid_subscription = ReadOnlyField()
language_code = ReadOnlyField()
on_trial = ReadOnlyField()
usersubscription_set = UserSubscriptionSerializer(many=True, read_only=True)
valid_subscriptions = UserSubscriptionSerializer(many=True, read_only=True)

class Meta:
    exclude = ('last_login',)
    extra_kwargs = {'password': {'write_only': True}}
    model = User
    read_only_fields = ('is_active', 'is_staff')

def create(self, validated_data):
    return User.objects.create_user(**validated_data)

最后,这是我的模型课

class User(AbstractBaseUser):
id = models.AutoField(db_column='ID', primary_key=True)

class Meta:
    constraints = [models.CheckConstraint(check=models.Q(country__length__gte=2), name='User.country__min_length')]
    db_table = 'Users'

accepted_eula_and_privacy_policy = models.BooleanField(db_column='AcceptedEULAandPrivacyPolicy', default=False)
address_1 = models.CharField(blank=True, db_column='Address 1', max_length=50)
address_2 = models.CharField(blank=True, db_column='Address 2', max_length=50)
city = models.CharField(blank=True, db_column='City', max_length=50)
country = models.CharField(db_column='Country (ISO 3166-1)', default='HU', max_length=2)
email = models.EmailField(db_column='Email', max_length=50, unique=True)
first_name = models.CharField(blank=True, db_column='FirstName', max_length=255)
image = models.ImageField(blank=True, db_column='Image', max_length=1000, upload_to='API_Authentication/user/image/')
is_active = models.BooleanField(db_column='Active', default=True)
is_staff = models.BooleanField(db_column='Staff', default=False)
job_title = models.CharField(blank=True, db_column='JobTitle', max_length=50)
language = models.ForeignKey(Language, db_column='LanguageID', default=2, on_delete=models.SET_DEFAULT)
last_name = models.CharField(blank=True, db_column='LastName', max_length=255)
phone_number = models.CharField(blank=True, db_column='PhoneNumber', max_length=50)
registration_date = models.DateTimeField(auto_now_add=True, db_column='RegistrationDate')
tax_number = models.CharField(blank=True, db_column='TaxNumber', max_length=13)
zip_code = models.CharField(blank=True, db_column='ZipCode', max_length=16)

objects = UserManager()

USERNAME_FIELD = 'email'

@property
def full_name(self):
    return f'{self.last_name} {self.first_name}' if self.first_name and self.last_name else None

@property
def has_billing_information(self):
    return (
        len(self.address_1) > 0
        and len(self.city) > 0
        and len(self.country) > 0
        and len(self.first_name) > 0
        and len(self.last_name) > 0
        and len(self.zip_code) > 0
    )

@property
def has_valid_subscription(self):
    has_valid_subscription = False
    for subscription in self.usersubscription_set.all():
        if subscription.validity_start < timezone.now() and subscription.validity_end > timezone.now():
            has_valid_subscription = True
            break
    return has_valid_subscription

@property
def language_code(self):
    return self.language.iso_639_1

@property
def on_trial(self):
    return not self.has_valid_subscription and self.registration_date + timedelta(days=3) > timezone.now()

@property
def valid_subscriptions(self):
    return self.usersubscription_set.filter(validity_end__gte=timezone.now(), validity_start__lte=timezone.now())

def __str__(self):
    return self.email

如果你能给我一些提示,我会很高兴,谢谢!

aamkag61

aamkag611#

DRF的ImageField派生自FileField,其to_representation在DRF调用序列化器时查看序列化器上下文,该上下文通常包括Django request-但如果您只是手动调用序列化器,则默认情况下上下文将为空。
如果存在requestto_representation将在生成的URL上调用request.build_absolute_url(),这将预先考虑当前请求的主机、协议等。一个部分URL。
似乎没有一个简单的方法来避免这种情况发生,所以如果你总是希望图像URL作为可能的相对路径,从drf.fields.ImageField派生,例如。

class URLImageField(fields.ImageField):
    def to_representation(self, value):
        if value:
            try:
                return value.url
            except AttributeError:
                pass
        return None

并将其插入序列化器:

class UserSerializer(...):
    image = URLImageField()

相关问题