How to Save Data from Serializer to Model Database. Following is an example Code but Not Saving Data to Database!
For Example I am using a Sample Example View:
views.py
#api_view(['GET', 'POST', ])
def login(request):
if request.method == "POST":
s = LoginSerializer(data=request.data)
if s.is_valid():
s.save()
return Response(s.data, status=201)
else:
return Response(s.data, status=203)
else:
return Response("", status=404)
models.py
from django.db.models import Model
from django.db import models
class UserDetails(Model):
userid = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
phone = models.CharField(max_length=15)
class UserLogin(Model):
userid = models.ForeignKey(UserDetails, on_delete=None)
email = models.CharField(max_length=20)
password = models.CharField(max_length=30)
serializers.py
from rest_framework import serializers
from api.models import UserLogin, UserDetails
class LoginSerializer(serializers.Serializer):
userid = serializers.Field()
email = serializers.EmailField()
password = serializers.CharField(max_length=20)
def create(self, validated_data):
return UserLogin.objects.create(**validated_data)
serializers.py
from rest_framework import serializers
from api.models import UserLogin, UserDetails
class LoginSerializer(serializers.Serializer):
userid = serializers.Field()
email = serializers.EmailField()
password = serializers.CharField(max_length=20)
def create(self, validated_data):
return super().create(validated_data)
Related
I am trying to stop the instance if the data matches in the DB. But i tried and failed again and again.
My Code:
models.py
class Doctor(models.Model):
"""
Manages data of consulting doctors working in the Hospital
"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.CharField(max_length=40)
contact = models.IntegerField()
department = models.CharField(max_length=50)
active = models.BooleanField(default=False)
def __str__(self):
return f"{self.user} ({self.department})"
class Patient(models.Model):
"""
Manages data of patient
"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.CharField(max_length=40)
contact = models.IntegerField()
symptoms = models.CharField(max_length=50)
active = models.BooleanField(default=False)
def __str__(self):
return f"{self.user} ({self.symptoms})"
class Appointment(models.Model):
"""
Manages the appointment details
"""
patient_name = models.ForeignKey(Patient, on_delete=models.CASCADE, related_name='doctor')
doctor_name = models.ForeignKey(Doctor, on_delete=models.CASCADE, related_name='patient')
appointment_date = models.DateTimeField()
active = models.BooleanField(default=False)
def __str__(self):
return str(self.patient_name) + " has appointment with " + str(self.doctor_name)
serializers.py
from rest_framework import serializers
from api.models import Patient, Doctor, Appointment
class AppointmentSerializer(serializers.ModelSerializer):
"""
Appointment serializer class
"""
class Meta:
model = Appointment
fields = "__all__"
class DoctorSerializer(serializers.ModelSerializer):
"""
Doctor serializer class
"""
user = serializers.StringRelatedField(read_only=True)
patient = AppointmentSerializer(many=True, read_only=True)
class Meta:
model = Doctor
fields = "__all__"
class PatientSerializer(serializers.ModelSerializer):
"""
Patient serializer class
"""
user = serializers.StringRelatedField(read_only=True)
doctor = AppointmentSerializer(many=True, read_only=True)
class Meta:
model = Patient
fields = "__all__"
views.py
from django.shortcuts import render
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework import status, viewsets
from rest_framework.views import APIView
from api.models import Doctor, Patient, Appointment
from api.serializers import DoctorSerializer, PatientSerializer, AppointmentSerializer
from rest_framework import generics
from rest_framework.decorators import action
# Create your views here.
class DoctorAPI(generics.ListAPIView):
"""
Doctor working in hospitals list
"""
queryset = Doctor.objects.all()
serializer_class = DoctorSerializer
class PatientAPI(generics.ListAPIView):
"""
Patient visiting in hospital list
"""
queryset = Patient.objects.all()
serializer_class = PatientSerializer
class DoctorDetailAPI(generics.ListAPIView):
serializer_class = DoctorSerializer
def get_queryset(self):
pk = self.kwargs['pk']
return Doctor.objects.filter(patient=pk)
class PatientDetailAPI(generics.ListAPIView):
serializer_class = PatientSerializer
def get_queryset(self):
pk = self.kwargs['pk']
return Patient.objects.filter(doctor=pk)
class AppointmentDetailAPI(APIView):
def get(self, request):
appointment = Appointment.objects.all()
serializer = AppointmentSerializer(appointment, many=True)
return Response(serializer.data)
def post(self, request):
serializer = AppointmentSerializer(data=request.data)
patient_name = Patient.objects.all()
doctor_name = Doctor.objects.all()
# print(serializer)
if serializer.is_valid():
appoint_data = Appointment.objects.filter(patient_name=patient_name)
print(appoint_data)
class AppointmentCreateAPI(generics.RetrieveUpdateDestroyAPIView):
queryset = Appointment.objects.all()
serializer_class = AppointmentSerializer
My task:
--> TO Resitrict the user to make appointment if there is already an appoinment is schedule to the Doctor.
You can also add a validation in the serializer to check if an existing appointment already exists like this:
class AppointmentSerializer(serializers.ModelSerializer):
...
def validate(self, attrs):
if not self.instance: # I'm creating an appointment
if Appointment.objects.filter(
doctor_name=attrs['doctor_name'],
appointment_date=attrs['appointment_date'],
active=True,
).exists():
raise serializers.ValidationError(
f'Appointment already exists for {attrs['doctor_name']}'
)
You have to override post method in LISTAPIVIEW and get data which you are going to filter before saving. For example;
class DoctorAPI(generics.ListAPIView):
queryset = Doctor.objects.all()
serializer_class = DoctorSerializer
def post(self,request,*args,**kwargs):
data=request.data.get("the name of input")
instance = Doctor.objects.filter(the field name which you are going
to compare).exist()
if instance:
return Response({"error":"This data is in database"})
I'm developing a backend with the django rest api. I have the same problem with my advertise model except for my user model. My choice linked to positiveintegerfielder is not displayed in restframework for post method.I'm doing an action like in serializer.py, whose photo I shared to display. When I do this, it is not displayed in restframework and I cannot use the post method.
Thank you very much in advance
serializer.py##
from user.models import User
from rest_auth.serializers import *
class ChoicesSerializerField(serializers.SerializerMethodField):
def __init__(self, choices, **kwargs):
self._choices = choices
super(ChoicesSerializerField, self).__init__(**kwargs)
def to_representation(self, value):
# sample: 'get_XXXX_display'
method_name = 'get_{field_name}_display'.format(field_name=self.field_name)
# retrieve instance method
method = getattr(value, method_name)
# finally use instance method to return result of get_XXXX_display()
return method()
def to_internal_value(self, data):
return getattr(self._choices, data)
class UserSerializer(serializers.ModelSerializer):
gender = ChoicesSerializerField(choices=User.gender)
class Meta:
model = User
fields = ('gender',)
view.py##
from rest_framework.viewsets import ModelViewSet
from user.serializer import UserSerializer
from .models import *
from rest_framework import permissions
from rest_framework.generics import CreateAPIView, ListAPIView, GenericAPIView, get_object_or_404
class CreateUserView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
User model##
from django.contrib.auth.models import AbstractUser
from django.core.validators import RegexValidator
from django.db import models
from user.choices.choice import MartialStatusChoices,
EducationalStatusChoices, ProfessionChoices, GenderChoices
class Interest(models.Model):
name = models.CharField(max_length=50, null=True, blank=True )
def __str__(self):
return self.name
class User(AbstractUser):
birthday = models.DateField(null=True)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$')
phone_number = models.CharField(validators=[phone_regex],
max_length=17, blank=True)
gender =
models.PositiveIntegerField(null=True,choices=GenderChoices.CHOICES)
martial_status = models.PositiveIntegerField(null=True,
choices=MartialStatusChoices.CHOICES)
educational_status = models.PositiveIntegerField(null=True,
choices=EducationalStatusChoices.CHOICES)
profession = models.PositiveIntegerField(null=True,
choices=ProfessionChoices.CHOICES)
interests = models.ManyToManyField(to=Interest,null=True,
blank=True)
class Meta:
verbose_name= "User"
You should try serializers.ChoiceField.
from user.choices.choice import GenderChoices
class UserSerializer(serializers.ModelSerializer):
gender = serializers.ChoiceField(choices=GenderChoices.CHOICES)
class Meta:
model = User
fields = ('gender',)
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class UserView(APIView):
permission_classes = (permissions.AllowAny,) # remove this if you're using authentication
def get(self, request):
serializer = UserSerializer(instance=request.user)
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
def post(self, request):
serializer = UserSerializer(instance=request.user, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response()
I am creating nested abstract user "Teacher from User", My use case is "Create User" -> "Then make user to teacher"
I am able to create user and make the user to Teacher, but I am unable to update the field, In below case want to update "teacher_cost"
Model.py
from django.contrib.postgres.fields import JSONField
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
uid = models.AutoField(verbose_name='ID',
serialize=False,
auto_created=True,
primary_key=True)
TEACHER = "Teacher"
STUDENT = "Student"
user_type = models.CharField(max_length=30, default=STUDENT)
contact_number = models.CharField(max_length=20, null=True, blank=True)
address = models.TextField(null=True, blank=True)
photo = models.ImageField(null=True, blank=True)
image = models.ImageField(upload_to='users/',
default='default/avatar.png')
approved = models.BooleanField(default=True)
def save(self, *args, **kwargs):
if self.user_type == User.TEACHER and self._state.adding:
self.approved = False
super().save(*args, **kwargs)
#property
def dishes(self):
ret = self.teacher.dish_set.all()
if ret:
return ret
else:
return ''
class Teacher(models.Model):
uid = models.AutoField(verbose_name='ID',
serialize=False,
auto_created=True,
primary_key=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(null=True, blank=True)
teacher_cost = models.DecimalField(
max_digits=5, decimal_places=2, null=True, blank=True)
languages = models.CharField(
max_length=50, null=True, blank=True)
address = models.TextField(null=True, blank=True)
def __str__(self):
return self.user.username
Serializer.py
from rest_framework import serializers, exceptions
from django.contrib.auth.forms import PasswordResetForm
from django.conf import settings
from .models import *
from rest_auth import serializers as rest_auth_serializers
from django.utils.translation import ugettext_lazy as _
class UserDetailsSerializer(serializers.ModelSerializer):
"""
User model w/o password
"""
class Meta:
model = User
fields = ('pk', 'username', 'email',
'first_name', 'last_name', 'contact_number', 'user_type', 'photo', 'address')
read_only_fields = ('email', )
class UserTeacher(serializers.ModelSerializer):
class Meta:
model = User
fields = ('teacher',)
class TeacherDetails(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = '__all__'
class TeacherFullDetails(serializers.ModelSerializer):
user_id = serializers.CharField(source='user.uid')
username = serializers.CharField(source='user.username')
first_name = serializers.CharField(source='user.first_name')
last_name = serializers.CharField(source='user.last_name')
photo = serializers.ImageField(
source='user.photo', max_length=None, use_url=True)
class Meta:
model = Teacher
fields = ('user_id', 'username', 'first_name', 'last_name', 'photo', 'teacher_cost')
class TeacherBriefDetails(serializers.ModelSerializer):
uid = serializers.CharField(source='user.uid')
first_name = serializers.CharField(source='user.first_name')
last_name = serializers.CharField(source='user.last_name')
class Meta:
model = Teacher
fields = ('uid', 'first_name', 'last_name',)
class TeacherProfileDetails(serializers.ModelSerializer):
contact_number = serializers.CharField(source='user.contact_number', required=False)
first_name = serializers.CharField(source='user.first_name', required=False)
last_name = serializers.CharField(source='user.last_name', required=False)
email = serializers.CharField(source='user.email', required=False)
photo = serializers.ImageField(
source='user.photo', max_length=None, use_url=True, required=False)
user = UserDetailsSerializer(read_only=True)
teacher_cost = serializers.CharField()
class Meta:
model = Teacher
fields = ('user', 'first_name', 'last_name', 'contact_number', 'email', 'photo',
'bio', 'teacher_cost')
class TeacherProfileSerializer(serializers.ModelSerializer):
user = UserDetailsSerializer()
class Meta:
model = Teacher
fields = ("bio", "teacher_cost", "user")
view.py
from rest_framework import generics, viewsets, status, permissions
from .models import *
from .serializers import *
from rest_framework.response import Response
from django.db.models import Q
from .permissions import IsAuthenticatedAndOwner, IsTeacher
from django.shortcuts import get_object_or_404
from django.utils.datastructures import MultiValueDictKeyError
from rest_framework.views import APIView
import json
import logging
class TeacherProfile(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
lookup_field = "username"
def get_object(self):
if self.action == "partial_update":
return get_object_or_404(User, username=self.kwargs['username'])
return get_object_or_404(Teacher, user__username=self.kwargs['username'])
def get_serializer_class(self):
if self.action == "partial_update":
return UserDetailsSerializer
else:
return TeacherProfileDetails
class TeacherListCreateAPIView(APIView):
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
teacherList = Teacher.objects.filter(user__username=kwargs["username"])
self.logger.info("Printing teacher list")
self.logger.info(teacherList)
serializers = TeacherProfileDetails(teacherList, many=True)
return Response(serializers.data)
def post(self, request, *args, **kwargs):
self.logger.info("-----------------put ------------")
serializers = TeacherProfileDetails(data=request.data)
# photo = request.FILES['file']
if serializers.is_valid():
serializers.save()
return Response(serializers.data, status=status.HTTP_201_CREATED)
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, *args, **kwargs):
serializers = TeacherProfileDetails(data=request.data, many=True)
self.logger.info(serializers)
if serializers.is_valid():
serializers.save()
return Response(serializers.data, status=status.HTTP_201_CREATED)
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
# /user/<str:username>/profile
class UserProfile(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
lookup_field = "username"
def get_object(self):
return get_object_or_404(User, username=self.kwargs['username'])
def get_serializer_class(self):
return UserDetailsSerializer
urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('teacher/<str:username>/profile',
TeacherProfile.as_view({'get': 'retrieve', 'delete': 'destroy', 'patch': 'partial_update'})),
path('teacherlist/<str:username>/',
TeacherListCreateAPIView.as_view(), name="teacher-list"),
]
Getting below error while calling post command to update the user profile
post
http://localhost:8002/api/v1/teacherlist/rayees/
Form json data
{
"teacher_cost": "25.00"
}
Getting below error
IntegrityError at /api/v1/teacherlist/rayees/
null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (2, null, 25.00, null, null, null).
Request Method: POST
Request URL: http://localhost:8002/api/v1/teacherlist/rayees/
Django Version: 2.2.4
since in model Teacher user is required fields, and you are sending the post request, it will create the new teacher with that user.If you want create new teacher then you should use the post, for that you need the user
if you want update the details of the user you can use patch method, checkout the put method code
class TeacherListCreateAPIView(APIView):
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
teacherList = Teacher.objects.filter(user__username=kwargs["username"])
self.logger.info("Printing teacher list")
self.logger.info(teacherList)
serializers = TeacherProfileDetails(teacherList, many=True)
return Response(serializers.data)
def post(self, request, *args, **kwargs):
""" creating new user """
serializers = TeacherProfileDetails(data=request.data)
# photo = request.FILES['file']
if serializers.is_valid():
serializer.validated_data['user'] = User.objects.filter(username=kwarsg['username'])
serializers.save()
return Response(serializers.data, status=status.HTTP_201_CREATED)
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
def patch(self, request, *args, **kwargs):
teacher = TeacherProfileDetails.objects.get(user__username=kwargs['username'])
serializers = TeacherProfileDetails(data=request.data, instance=teacher)
self.logger.info(serializers)
if serializers.is_valid():
serializers.save()
return Response(serializers.data, status=status.HTTP_201_CREATED)
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
now you can make patch request on http://localhost:8002/api/v1/teacherlist/rayees/
with given data it will update the record.
Models:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
nationality = models.CharField(max_length=20)
def __str__(self):
return self.user.first_name
#receiver(post_save, sender=User)
def create_user_profile(self, sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(self, sender, instance, **kwargs):
instance.profile.save()
Forms:
from allauth.account.forms import SignupForm
class CustomSignupForm(SignupForm):
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
class Meta:
model = Profile
fields = ('first_name', 'last_name', 'nationality', 'bio')
def signup(self, request, user):
# Save your user
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
user.profile.nationality = self.cleaned_data['nationality']
user.profile.gender = self.cleaned_data['bio']
user.profile.save()
Views:
ACCOUNT_FORMS = {'signup': 'myproject.forms.CustomSignupForm',}
This process isn't work. Error is: Model class all_auth.models.Profile doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
How can I solve it? Or, How can i add more field with SignupForm using django-allauth?
Create an application, such as accounts and it has this code, but you need to create a database only after creating this code, it is more accurate to perform the first migration in the project
accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
phone = models.CharField(max_length=12)
accounts/forms.py
from allauth.account.forms import SignupForm
from django import forms
from .models import *
class SimpleSignupForm(SignupForm):
phone = forms.CharField(max_length=12, label='Телефон')
def save(self, request):
user = super(SimpleSignupForm, self).save(request)
user.phone = self.cleaned_data['phone']
user.save()
return user
settings.py
...
ACCOUNT_FORMS = {'signup': 'accounts.forms.SimpleSignupForm'}
AUTH_USER_MODEL = 'accounts.CustomUser'
accounts/admin.py
from django.contrib import admin
from .models import *
admin.site.register(CustomUser)
I am still experiencing some problems with understanding forms and relationships between model-forms.
I am getting an error:
UserProfile.location" must be a "Location" instance.
I've set location in models to blank=True, null=True and required=False in forms.py.
And I dont really know at this point what to do with that.
How I can fix that problem?
from django.db import models
from django.contrib.auth.models import User
class Location(models.Model):
location = models.CharField(max_length=32)
#county = models.CharField(max_length=32)
#province = models.CharField(max_length=32)
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True, primary_key=True)
location = models.ForeignKey("Location", null=True, blank=True)
website = models.URLField("Site", null=True, blank=True)
accepted_rules = models.BooleanField(default=False)
accepted_rules_date = models.DateTimeField(auto_now_add=True)
#points_count = models.IntegerField(default=0, null=True, blank=True)
#posts_count = models.IntegerField(default=0, null=True, blank=True)
#comments_count = models.IntegerField(default=0, null=True, blank=True)
Forms:
from django import forms
from django.forms import Form
from django.forms.models import ModelForm
from accounts.models import UserProfile, Location
from django.contrib.auth.models import User
class UserCreationForm(forms.Form):
username = forms.CharField(max_length=32)
password = forms.CharField(widget=forms.PasswordInput())
email = forms.EmailField()
#password_repeat = forms.CharField(widget=forms.PasswordInput(render_value=False))
def clean_username(self):
try:
# iexact = case-insensitive match / important for validation
User.objects.get(username__iexact=self.cleaned_data['username'])
print "User does already exist"
except User.DoesNotExist:
return self.cleaned_data['username']
else:
raise forms.ValidationError("User already exists")
def clean_email(self):
if User.objects.filter(email__iexact=self.cleaned_data['email']):
print u'Adres email jest już używany.'
raise forms.ValidationError('Adres email jest już używany.')
else:
return self.cleaned_data['email']
def save(self):
user = User.objects.create(username = self.cleaned_data['username'], email = self.cleaned_data['email'],)
user.set_password(self.cleaned_data['password'])
return user
class UserProfileForm(ModelForm):
website = forms.URLField(label="website", required=False)
location = forms.ChoiceField(required=False)
class Meta:
model = UserProfile
include = ['website', 'location']
exclude = ('user', 'type', 'accepted_rules')
Views
contrib.auth.models import User
from django.template.response import TemplateResponse
from django.views.decorators.csrf import csrf_protect
from django.core.context_processors import csrf
from django.forms.models import inlineformset_factory
from django.http import HttpResponseRedirect
from accounts.forms import UserCreationForm, UserProfileForm
def index(request):
return TemplateResponse(request, "base.html")
#csrf_protect
def register(request):
form = UserCreationForm()
user_profile = UserProfileForm()
if request.method == "POST":
form = UserCreationForm(prefix='user', data=request.POST or None)
user_profile = UserProfileForm(prefix='profile', data= request.POST or None)
if form.is_valid() and user_profile.is_valid():
user = form.save()
profile = user_profile.save(commit=False)
profile.user = user
profile.save()
return HttpResponseRedirect("/")
return TemplateResponse(request, 'accounts/register.html', {
'form':form,
'user_profile':user_profile ,
}
)
The problem is here.
class UserProfileForm(ModelForm):
website = forms.URLField(label="website", required=False)
location = forms.ChoiceField(required=False)
class Meta:
model = UserProfile
include = ['website', 'location']
exclude = ('user', 'type', 'accepted_rules')
ModelForm will generate needed fields for your form. You don't need to define them manually. So you should use something like this.
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
include = ['website', 'location']
exclude = ('user', 'type', 'accepted_rules')
Another thing. There is no include option, I think you wanted to use fields. But you don't have to use both fields and exclude, usually you need to use one them. In your case exclude is enough. Final result:
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
exclude = ('user', 'type', 'accepted_rules')