#django #django-rest-framework #django-views #django-serializer
#django #django-rest-framework #django-просмотры #django-сериализатор
Вопрос:
Я работаю над genericAPIViews в DRF. Я использую встроенную пользовательскую модель с моделью UserProfile, имеющей отношение один к одному с ней. Но я не могу создать пользователя из-за вложенного сериализатора. Мой вопрос заключается в том, как я могу создать свою встроенную модель пользователя и модель профиля пользователя одновременно с тем, как модель UserProfile вложена в модель пользователя.Вот мой код:
Models.py
USER_CHOICE = (
('SS', 'SS'),
('SP', 'SP')
)
LOGIN_TYPE = (
('Local', 'Local'),
('Facebook', 'Facebook'),
('Google', 'Google')
)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
cell_phone = models.CharField(max_length=15, blank=True, default="", null=True)
country = models.CharField(max_length=50, blank=True, default="", null=True)
state = models.CharField(max_length=50, blank=True, default="", null=True)
profile_image = models.FileField(upload_to='user_images/', default='', blank=True)
postal_code = models.CharField(max_length=50, blank=True, default="", null=True)
registration_id = models.CharField(max_length=200, null=True, blank=True, default=None)
active = models.BooleanField(default=True)
# roles = models.ForeignKey(Role, null=True, on_delete=models.CASCADE, related_name='role', blank=True)
user_type = models.CharField(max_length=50, choices=USER_CHOICE, null=True, blank=True)
login_type = models.CharField(max_length=40, choices=LOGIN_TYPE, default='local')
reset_pass = models.BooleanField(default=False)
confirmed_email = models.BooleanField(default=False)
remember_me = models.BooleanField(default=False)
reset_code = models.CharField(max_length=200, null=True, blank=True, default="")
reset_code_time = models.DateTimeField(auto_now_add=True, blank=True)
longitude = models.DecimalField(max_digits=80, decimal_places=10, default=0.00)
latitude = models.DecimalField(max_digits=80, decimal_places=10, default=0.00)
r_code = models.CharField(max_length=15, null=True, blank=True)
refer_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="user_refer")
referred = models.ManyToManyField(User, related_name="user_referred", null=True, blank=True)
otp = models.CharField(max_length=6, blank=True, default="", null=True)
def __str__(self):
return self.user.username
Seralizers.py
from rest_framework import serializers
from django.contrib.auth.models import User
from .models import UserProfile
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
class UserSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer()
class Meta:
model = User
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'profile']
Views.py
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
Я знаю, что есть метод .create(), который может быть переопределен в соответствии с документацией DRF. Кроме того, я хочу переопределить этот метод в views.py . Есть ли какой-нибудь подход к этому? Заранее благодарю за ваше дополнение в моих знаниях.
Комментарии:
1. Позвольте мне прояснить ситуацию: вы создали представление для создания
User
и теперь ищете способ, чтобы приUser
создании anUserProfile
также создавался для этого пользователя, верно?2. Вот именно! но с использованием genericAPIviews. Мой APIView работает нормально, когда я создаю только пользователя, но проблема возникает, когда я вкладываю UserProfile serializer в пользовательскую сборку в модели.
Ответ №1:
Насколько мне известно, есть два способа сделать это.
Первый переопределяет метод create общего представления. Который заключается в следующем:
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def create(self, request, *args, **kwargs):
#let django create the user with generic view
response = super().create(request, *args, **kwargs)
# response.data contains the serialized data of the created user
user_data = response.data
user_id = response.data.get("id")
profile = UserProfile()
profile.user = User.objects.get(id=user_id)
profile.save()
# return the response created by the generic view
return response
Будьте осторожны, что Django Rest Framework не поддерживает create
метод для вложенных сериализаторов. Установите для поля профиля значение только для чтения в UserSerializer
class UserSerializer(serializers.ModelSerializer):
profile = SerializerMethodField()
class Meta:
model = User
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'profile']
read_only_fields = ('profile',)
def get_profile(self, user):
profile = UserProfile.objects.filter(user=user).first()
return UserProfileSerializer(profile).data if profile is not None else None
Второй способ — использование сигналов. Signals — это диспетчер событий, который отслеживает такие события, как обновление, удаление, изменение m2m и т. Д. Здесь мы можем использовать post_save
сигналы, которые запускаются всякий раз, когда модель обновляется. Итак, если User
модель будет создана, мы получим сигнал и, следовательно, создадим ящик a UserProfile
для этого пользователя. Вы можете узнать больше о сигналах на странице сигналов Django.
@receiver(post_save, sender=User, dispatch_uid="create_user_profile")
def on_user_create(sender, instance, created, **kwargs):
# here instance is the user object that just got created
# created is a boolean value which will be true if the record is newly created
if created:
profile = UserProfile()
profile.user = instance
profile.save()
Комментарии:
1. мой код выходит из строя здесь: response = super().create(запрос, * аргументы, ** kwargs)
2. По
.create()
умолчанию метод не поддерживает доступные для записи вложенные поля. Напишите явный.create()
метод для сериализатораmyapp.serializers.UserSerializer
или установитеread_only=True
для вложенных полей сериализатора.3. удалите
profile
поле изUserSerializer
. DRF не поддерживаетcreate
метод для вложенных сериализаторов.4. что ж, спасибо за помощь. Но я знаю это и пытался выяснить, есть ли какой-либо метод для переопределения метода create() и выполнения этой задачи.
5. Я обновил свой фрагмент. Пожалуйста, попробуйте это сейчас.