Я слишком долго борюсь с DRF, так что теперь я должен задать вопрос .. Как поменять ForeignKey на другой? У меня есть профиль пользователя и отношение к статусной модели.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
ldap_uid = models.CharField(max_length=100, blank=True, null=True, default=None)
redmine_id = models.IntegerField(blank=True, null=True, default=None)
status = models.ForeignKey(Status, models.SET_NULL, blank=False, null=True, default=DEFAULT_STATUS_ID)
location = models.ForeignKey(Location, models.SET_NULL, blank=False, null=True, default=DEFAULT_LOCATION_ID)
online = models.BooleanField(default=False)
class SelectValuesModel(models.Model):
name = models.CharField(max_length=100)
display_name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Meta:
abstract = True
class Status(SelectValuesModel):
pass
class Location(SelectValuesModel):
pass
Как лучше изменить статус профиля на другой? Я безуспешно пытаюсь сделать что-то подобное
views.py
class UserStatusView(viewsets.ViewSet):
def partial_update(self, request, pk=None):
user = User.objects.get(pk=pk)
user_profile = user.profile
new_stauts = Status.objects.get(request.data.status)
serialized_data = ProfileSerializer(user_profile)
if (serialized_data.is_valid()):
serialized_data.save(status=new_stauts)
return Response(serialized_data.errors)
И пытаюсь отправить новый идентификатор через PATCH. Я пытаюсь найти решение, но и здесь безуспешно. А как это хорошо? Сделать другой маршрут для обновления статуса профиля? Или сделать что-то вроде profile / 1 / update_status / 2? Теперь моя маршрутизация выглядит так:
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'redmine', views.RedmineCurrentTaskView, base_name='redmine')
router.register(r'parameters', views.ParametersView, base_name='parameters')
router.register(r'update_status', views.UserStatusView, base_name='update_status')
router.register(r'debug', views.DebugStatus, base_name='debug')
urlpatterns = [
path('', views.index, name='index'),
path('api/', include(router.urls))
]
И serializers.py
class SelectValuesSerializer(serializers.ModelSerializer):
class Meta:
fields = ('pk', 'name', 'display_name')
class LocationSerializer(SelectValuesSerializer):
class Meta(SelectValuesSerializer.Meta):
model = Location
class StatusSerializer(SelectValuesSerializer):
class Meta(SelectValuesSerializer.Meta):
model = Status
class ProfileSerializer(serializers.ModelSerializer):
status = StatusSerializer()
location = LocationSerializer()
class Meta:
model = Profile
fields = ('status', 'location', 'online', 'redmine_id')
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(read_only=True)
class Meta:
model = User
fields = ('pk', 'first_name', 'profile')
read_only_fields = ('first_name',)





Просто передайте request.data сериализатору с аргументом partial=True:
class UserStatusView(viewsets.ViewSet):
def partial_update(self, request, pk=None):
user = User.objects.get(pk=pk)
user_profile = user.profile
serialized_data = ProfileSerializer(user_profile, data=request.data, partial=True)
if serialized_data.is_valid():
serialized_data.save()
return Response(serialized_data.data)
return Response(serialized_data.errors)
Вам нужно предоставить status_id с телом запроса следующим образом:
{"status": 1}
UPD
Чтобы передать статус как id, измените свой сериализатор на это:
class ProfileSerializer(serializers.ModelSerializer):
location = LocationSerializer()
class Meta:
model = Profile
fields = ('status', 'location', 'online', 'redmine_id')
def to_representation(self, instance):
self.fields['status'] = StatusSerializer()
return super(ProfileSerializer, self).to_representation(instance)
Это позволяет публиковать status_id, но получать информацию о статусе с помощью вашего API.
Я полагаю, вы установили в сериализаторе status=StatusSerializer()? Вы можете просто добавить его в метод to_representation, чтобы отображать детали статуса только для запроса GET.
@Sierran Я обновил ответ :) Вам нужно добавить to_representation и удалить status = StatusSerializer().
Боже мой! Оно работает! Спасибо! Но на будущее .. Это хорошее решение? Я не могу найти это в документации DRF. И как лучше всего создавать маршрутизацию?
@Sierran, да, это обычная практика, чтобы переопределить to_representation. Что касается маршрутизации, я предлагаю вам использовать DefaultRouter, как вы это уже сделали. Проверить ссылку о переопределении метода to_presentation: django-rest-framework.org/api-guide/relations/#example_1
Спасибо! Я знаю, что это неубедительный вопрос .. Но вы можете объяснить мне to_presentation в моем примере? В документации 100% создано для меня, как его использовать, но в моем примере? Я не понимаю разницы с to_presentation и без него в моей проблеме, в чем разница между status = StatusSerializer () и self.fields ['status'] = StatusSerializer (). А почему мы используем супер?
Позвольте нам продолжить обсуждение в чате.
Я связал это и всегда получаю ошибку: {"status": {"non_field_errors": ["Недействительные данные. Ожидал словарь, но получил int." ]}}