In my model, i have a family table where user are able to enter their family details and store their information. But how do i get/query all the family member based on current userId ?
For eg: userId=1 added 2 family member, mother and father. How do i get these 2 family member based on the query of the current user's userId ?
here is my code :
models
class MyUser(AbstractUser):
userId = models.AutoField(primary_key=True)
gender = models.CharField(max_length=6, blank=True, null=True)
nric = models.CharField(max_length=40, blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
birthTime = models.TimeField(blank=True, null=True)
class Family(models.Model):
userId = models.ForeignKey(MyUser)
relationship = models.CharField(max_length=100)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
gender = models.CharField(max_length=6, blank=True, null=True)
serializers
class MyUserSerializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
birthTime = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats, allow_null=True, required=False)
class Meta:
model = MyUser
fields = ['userId', 'username', 'email', 'first_name', 'last_name', 'gender', 'nric', 'birthday', 'birthTime']
read_only_fields = ('userId',)
extra_kwargs = {"password": {"write_only": True}}
def update(self, instance, validated_data):
for attr, value in validated_data.items():
if attr == 'password':
instance.set_password(value)
else:
setattr(instance, attr, value)
instance.save()
return instance
class FamilySerializer(serializers.ModelSerializer):
class Meta:
model = Family
fields = ('id', 'userId', 'first_name', 'last_name', 'gender', 'relationship')
views
class MyUserViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = MyUser.objects.all()
serializer_class = MyUserSerializer
filter_backends = (filters.SearchFilter,)
search_fields = ('=userId', 'username', 'email', 'first_name', 'last_name')
class FamilyViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = Family.objects.all()
serializer_class = FamilySerializer
def get_object(self, *args, **kwargs):
return self.request.user
def perform_update(self, serializer):
super(CurrentFamilyView, self).perform_update(serializer)
user = serializer.instance
if settings.SEND_ACTIVATION_EMAIL and not user.is_active:
context = {'user': user}
to = [MyUser(user)]
email.ActivationEmail(self.request, context).send(to)
Can anyone help me with get current user's family
You can try this:
class Family(models.Model):
userId = models.ForeignKey(MyUser, related_name='user_family')
relationship = models.CharField(max_length=100)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
gender = models.CharField(max_length=6, blank=True, null=True)
serializers.py
class FamilySerializer(serializers.ModelSerializer):
class Meta:
model = Family
fields = ('id', 'first_name', 'last_name', 'gender', 'relationship')
class MyUserSerializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
birthTime = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats, allow_null=True, required=False)
my_family = FamilySerializer(many=True, source='user_family')
class Meta:
model = MyUser
fields = ('userId', 'username', 'email', 'first_name', 'last_name', 'gender', 'nric', 'birthday', 'birthTime', 'my_family')
read_only_fields = ('userId',)
extra_kwargs = {"password": {"write_only": True}}
MyUserSerializer now will show userid related family members. If you want to get current user family member you need to overwrite get_queryset method.
your views.py:
class MyUserViewSet(viewsets.ModelViewSet):
serializer_class = MyUserSerializer
get_queryset(self):
return MyUser.objects.get(id=self.request.user.id)
Now the view will return current user family members.
Updates
Added related_name in Family model.
Added source in MyUserSerializer
Let's assume we have a user with id=1
usr = MyUser.objects.get(id=1)
usr_famly = usr.family_set.values()
usr_famly will have all family data related to user with id=1
Related
I need to pass data from EmployeeSerializer to VacationSerializer as nested json. This is my serializer.py:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ('pk', 'first_name', 'surname', 'patronymic', 'birthday', 'email', 'position', 'phone_number')
class VacationSerializer(serializers.ModelSerializer):
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id', 'employee')
and my models.py:
class Employee(models.Model):
first_name = models.CharField("Name", max_length=50)
surname = models.CharField("surname", max_length=50)
patronymic = models.CharField("patronymic", max_length=50)
birthday = models.DateField()
email = models.EmailField()
position = models.CharField("position", max_length=128)
phone_number = models.CharField("phone", max_length=12, null=True)
is_deleted = models.BooleanField(default=False)
def __str__(self):
return f'{self.surname} {self.first_name} {self.patronymic}'
class Vacation(models.Model):
start_date = models.DateField()
end_date = models.DateField()
employee_id = models.ForeignKey(Employee, related_name='employee', on_delete=models.PROTECT, default=-1)
def __str__(self):
return f'{self.start_date} - {self.end_date}'
#property
def date_diff(self):
return (self.end_date - self.start_date).days
in views.py I have this:
#api_view(['GET', 'POST'])
def vacations_list(request):
if request.method == 'GET':
data = Vacation.objects.all()
serializer = VacationSerializer(data, context={'request': request}, many=True)
return Response(serializer.data)
I've tried this:
class VacationSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer(read_only=True, many=True)
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id', 'employee')
but it doesn't show me even empty nested json, it shows me only VacationSerializer data.
I easily can access VacationSerializer from EmployeeSerializer using PrimaryKeySerializer or any other serializer and get nested json where VacationSerializer data is nested in EmployeeSerializer data. But I want it opposite - nested json of employee related to this vacation. How to achieve this?
That is because of the naming on your model. You need to serialize the 'employee_id' field:
class VacationSerializer(serializers.ModelSerializer):
employee_id = EmployeeSerializer()
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id')
I'm using Djago 2.0 and Django REST Framework
I have following model classes for contacts/models.py
class Contact(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100, blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
class ContactPhoneNumber(models.Model):
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
phone = models.CharField(max_length=100)
primary = models.BooleanField(default=False)
contacts/views.py
class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactSerializer
permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)
def get_queryset(self):
return Contact.objects.filter(user=self.request.user)
def perform_create(self, serializer):
serializer.save(user_id=self.request.user)
and contacts/serializers.py is defined as
class ContactPhoneNumberSerializer(serializers.ModelSerializer):
class Meta:
model = ContactPhoneNumber
fields = ('id', 'phone', 'primary', 'created', 'modified')
class ContactSerializer(serializers.HyperlinkedModelSerializer):
phone_numbers = ContactPhoneNumberSerializer(source='contactphonenumber_set', many=True)
user = serializers.CurrentUserDefault()
class Meta:
model = Contact
fields = ('url', 'id', 'first_name', 'last_name', 'date_of_birth', 'phone_numbers')
def create(self, validated_data):
phone_numbers = validated_data.pop('contactphonenumber_set')
user = validated_data.pop('user_id')
instance = Contact.objects.create(
user=user,
**validated_data
)
for phone_data in phone_numbers:
ContactPhoneNumber.objects.create(contact=instance, **phone_data)
return instance
I want to be able to create multiple phone_number instances with new contact object.
How can I pass multiple phone_numbers with fields phone, primary along with contact data?
Your JSON Post body needs to look like this:
{
"user": 1,
"first_name": "Anuj",
"last_name": "TBE",
"date_of_birth": "1990-01-01",
"contactphonenumber_set": [
{
"phone": "+91999999999",
"primary": false
},
{
"phone": "+91999999993",
"primary": true
}
]
}
Do think about how you want to deal with duplicates in this context.
I've simplified my code to make problem more clear.
I have two related models in my Django REST project. In my models.py:
class ClinicalResearch(models.Model):
name = models.CharField(max_length=150, null=True)
description = models.TextField(blank=True, null=True)
class Patient(models.Model):
research = models.ForeignKey(ClinicalResearch, on_delete=models.CASCADE, blank=True)
first_name = models.CharField(max_length=50)
second_name = models.CharField(max_length=50, blank=True, null=True)
middle_name = models.CharField(max_length=50, blank=True, null=True)
location = models.CharField(max_length=50, blank=True)
birth_date = models.DateTimeField(blank=True, null=True)
observation_date = models.DateTimeField(blank=True, null=True)
desease = models.CharField(max_length=50, blank=True, null=True)
desease_date = models.DateTimeField(blank=True, null=True)
gender = models.CharField(max_length=10)
Then I create a serialiser:
class PatientSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Patient
fields = ('id', 'research_id', 'first_name', 'second_name', 'middle_name', 'location', 'birth_date', 'observation_date', 'desease', 'desease_date', 'gender')
def create(self, validated_data):
# for tests only
print(validated_data)
return Patient(**validated_data)
View set:
class PatientViewSet(viewsets.ModelViewSet):
queryset = Patient.objects.all()
serializer_class = PatientSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('id', 'research_id', 'first_name', 'second_name', 'middle_name', 'location', 'birth_date', 'observation_date', 'desease', 'desease_date', 'gender')
Router:
router.register(r'patients', ItemViewSet)
This implementation works fine for models without foreign keys. But when I post something like:
{
'id': null,
'research_id': 1,
'first_name': "john",
'second_name': "doe",
'middle_name', "",
'location': "Love Street",
'birth_date': "...",
'observation_date': "...",
'desease': "Lovefool",
'desease_date': "...",
"gender": "male to fem"
}
(the project with id=1 exists)
my ItemSerializer doesn't pass { research_id: 1 } to validated_fields.
The project_id field is completely lost during validation.
How to configure Serializer or ViewSet to make it workable?
Looks like problem related to HyperlinkedModelSerializer in this case Django expecting url for related object instead of id. Try to override type of serializer's field research:
class PatientSerializer(serializers.HyperlinkedModelSerializer):
research = serializers.PrimaryKeyRelatedField()
class Meta:
model = Patient
fields = ('id', 'research', 'first_name', 'second_name', 'middle_name', 'location', 'birth_date', 'observation_date', 'desease', 'desease_date', 'gender')
def create(self, validated_data):
# for tests only
print(validated_data)
return Patient(**validated_data)
# If you need URLs for representation use this method
def to_representation(self, instance):
"""Set field type for output only"""
self.fields['research'] = serializers.HyperlinkedRelatedField()
return super().to_representation(instance)
You have to link it:
accept
Looks like problem related to HyperlinkedModelSerializer in this case Django expecting url for related object instead of id. Try to override type of serializer's field research:
class PatientSerializer(serializers.ModelSerializer):
research = serializers.PrimaryKeyRelatedField(queryset=ClinicalResearch.objects.all())
class Meta:
model = Patient
fields = ('id', 'research', 'first_name', 'second_name', 'middle_name', 'location', 'birth_date', 'observation_date', 'desease', 'desease_date', 'gender')
def create(self, validated_data):
# for tests only
print(validated_data)
return Patient.objects.create(**validated_data)
2nd Screenshot of APIAPI Sample Screenshot
I'm New in Django, i want to help regarding validations in screenshot there is company_name, location, title and user_location fields except user info with proper validation
but i want to remove validations from company_name, location, title and user_location fields how to do?
Please find the above api screenshot and
Please find the below scripts,
views.py
class UserRegistrationView(generics.CreateAPIView):
"""
Register a new user.
"""
queryset = User.objects.all()
permission_classes = (permissions.AllowAny, )
def get_serializer_class(self, user_type=None):
if user_type == 'student':
return StudentRegistrationSerializer
return ProfessionalRegistrationSerializer
def post(self, request, user_type=None, format=None):
serializer_class = self.get_serializer_class(user_type)
serializer = serializer_class(data=request.data, context={'request': request})
if serializer.is_valid(raise_exception=True)
user = serializer.save(work_status=user_type)
token, created = Token.objects.get_or_create(user=user)
data = BasicUserSerializer(user, context={'request': request}).data
data.update({"token": token.key})
return Response(data)
serializes.py
class ProfessionalRegistrationSerializer(serializers.HyperlinkedModelSerializer):
password = serializers.CharField(max_length=20, write_only=True)
experiences = ExperienceSerializer(required=False)
email = serializers.EmailField()
first_name = serializers.CharField(max_length=30)
last_name = serializers.CharField(max_length=30)
class Meta:
model = User
fields = ('url', 'id', 'first_name', 'last_name', 'email', 'password',
'experiences', 'headline')
def validate_email(self, value):
from validate_email_address import validate_email
if User.all_objects.filter(email=value.lower()).exists():
raise serializers.ValidationError('User with this email already exists.')
# if not validate_email(value.lower(), check_mx=True):
# raise serializers.ValidationError('It looks like you may have entered an incorrect email address.')
return value.lower()
def create(self, validated_data):
experiences = validated_data.pop('experiences')
password = validated_data.pop('password')
email = validated_data.pop('email')
user = User.objects.create(
username=email.lower(),
email=email.lower(),
role_id=1)
user.set_password(password)
user.save()
user_location = experiences.pop('user_location')
if hasattr(user, 'location'):
user.location.location = user_location
user.save()
else:
UserLocation.objects.create(user=user, location=user_location)
Experience.objects.create(user=user)
return user
Another serializes.py for Experiance
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
I want to Remove Validation from company_name, company, description, location, title, start_date, end_date, user_location
actually these fields are second page means after complete the first step users move on second step so second step fields are optional
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
def create(self, validated_data):
return Experience.objects.create(field_a='value', field_b='value')
in the above class, what should be do to remove validation of
"error_msg": {
"location": [
"Expected a dictionary of items but got type \"str\"."
],
"start_date": [
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]."
],
"end_date": [
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]."
],
"user_location": [
"Expected a dictionary of items but got type \"str\"."
]
}
Experience Model
class Experience(models.Model):
"""
"""
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='experiences')
company_name = models.CharField(max_length=200, db_index=True, blank=True)
company = models.ForeignKey('organisations.Organisation', null=True, blank=True, on_delete=models.SET_NULL)
description = models.TextField(null=True, blank=True)
location = models.ForeignKey('regions.Location', null=True, blank=True, on_delete=models.SET_NULL)
start_date = models.DateField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
title = models.CharField(max_length=200, db_index=True, blank=True)
is_current = models.BooleanField(default=False)
is_associated = models.BooleanField(default=False)
created_at = models.DateTimeField(_('created at'), auto_now_add=True)
modified_at = models.DateTimeField(_('modified at'), auto_now=True)
class Meta:
db_table = 'experience'
verbose_name = _('experience')
verbose_name_plural = _('experiences')
ordering = ('-start_date',)
def __str__(self):
return getattr(self, 'title', '')
#property
def experience(self):
if self.end_date:
return (self.end_date - self.start_date).days
else:
return (datetime.datetime.now().date() - self.start_date).days
def get_formated_experience(self):
days = self.experience
total_months = round(days/30)
years = int(total_months/12)
months = round(((total_months/12)%1)*12)
year_txt = 'years' if years > 1 else 'year'
month_txt = 'months' if months > 1 else 'month'
return "%s %s %s %s" %(years, year_txt, months, month_txt)
Location Model
class Location(models.Model):
"""
"""
id = models.TextField(primary_key=True)
display_name = models.TextField(null=True, blank=True)
latitude = models.DecimalField(max_digits=15, decimal_places=10, null=True, blank=True)
longitude = models.DecimalField(max_digits=15, decimal_places=10, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
objects = LocationManager()
You are getting Two types of validation error according to snapshot.
Field is required
Expected a dictionary and got a string
The required field error occurs when you have set field as required in your model. You can change this by adding blank=True in your model for that field.
For second error, your serializer is expecting a dictionary and you are sending a string. You can remove this validation by writing your custom create method.
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
def create(self, validated_data):
# you create code for that models.
Your seriailzers will be like this
class ProfessionalRegistrationSerializer(serializers.HyperlinkedModelSerializer):
password = serializers.CharField(max_length=20, write_only=True)
experiences = ExperienceSerializer(required=False)
email = serializers.EmailField()
first_name = serializers.CharField(max_length=30)
last_name = serializers.CharField(max_length=30)
class Meta:
model = User
fields = ('url', 'id', 'first_name', 'last_name', 'email', 'password',
'experiences', 'headline')
def validate_email(self, value):
from validate_email_address import validate_email
if User.all_objects.filter(email=value.lower()).exists():
raise serializers.ValidationError('User with this email already exists.')
# if not validate_email(value.lower(), check_mx=True):
# raise serializers.ValidationError('It looks like you may have entered an incorrect email address.')
return value.lower()
def create(self, validated_data):
experiences = validated_data.get('experiences')
password = validated_data.get('password')
email = validated_data.get('email')
user = User.objects.create(
username=email.lower(),
email=email.lower(),
role_id=1)
user.set_password(password)
user.save()
user_location = experiences.get('user_location')
location_object = None
if user_location:
location_object, created = Location.objects.get_or_create(display_name=user_location.get('display_name'), latitude= user_location.get('latitude'), longitude=user_location.get('longitude'))
user_experience = Experience.objects.create(user=user, company_name=experiences.get('company_name'), location=location_object)
return user
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
Currently in my ModelViewSet I'm returning all contacts for today, additionally I'm checking if the query_params on the request for searching/filtering is available and not empty, In that case I'm not adding "today" to the queryset so that will perform search on the entire queryset.
Problem is that I need to extend search so the user can see other users contacts, but only when he search for them, default view should not be changing if you are not searching, so how can I extend my current filter and return all objects in search.
My current view:
from rest_framework import viewsets, permissions, filters
from cms.restapi.pagination import StandardResultsOffsetPagination
from cms_sales.models import LeadContact
from cms_sales.restapi.permissions.lead_contact_permissions import LeadContactPermissions
from cms_sales.restapi.serializers.lead_contact_serializer import LeadContactSerializer
class LeadContactViewSet(viewsets.ModelViewSet):
def get_queryset(self):
queryset = LeadContact.objects.none()
user = self.request.user
if user.has_perm('cms_sales.can_view_full_lead_contact_list'):
queryset = LeadContact.objects.all()
elif user.has_perm('cms_sales.can_view_lead_contact'):
queryset = LeadContact.objects.filter(account_handler=user)
filter_date = self.request.query_params.get('filter_date', None)
search_params = self.request.query_params.get('search', None)
if filter_date is not None and (search_params is None or len(search_params) == 0):
queryset = queryset.filter(next_action_date=filter_date)
return queryset
serializer_class = LeadContactSerializer
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
filter_fields = ('account_handler',)
ordering_fields = (
'first_name', 'last_name', 'account_handler__first_name', 'account_handler__last_name',
'sub_organization_name', 'organization_name', 'next_action_date', 'serial_number',
'status_text')
search_fields = (
'first_name', 'last_name', 'account_handler__first_name', 'account_handler__last_name',
'sub_organization_name', 'organization_name', 'next_action_date', 'serial_number',
'status_text')
pagination_class = StandardResultsOffsetPagination
permission_classes = [permissions.IsAuthenticated, LeadContactPermissions]
Current Serializer:
from django.conf import settings
from django.contrib.auth.models import User
from rest_framework import serializers
from cms_sales.models import LeadContact
class AccountHandlerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name')
class LeadContactSerializer(serializers.ModelSerializer):
account_handler = AccountHandlerSerializer()
next_action_date = serializers.DateTimeField(format=settings.CUSTOM_DATE_FORMAT_NO_TIME)
absolute_url = serializers.URLField(source='get_absolute_url')
class Meta:
model = LeadContact
fields = (
'pk', 'organization_name', 'sub_organization_name', 'serial_number', 'account_handler', 'status_text',
'first_name', 'last_name', 'next_action_date', 'absolute_url', 'status_display_class'
)
depth = 1
Current Model:
class LeadContact(models.Model):
organization_name = models.CharField(max_length=200, blank=False, null=True)
sub_organization_name = models.CharField(max_length=200, blank=False, null=True)
serial_number = models.CharField(max_length=30, db_index=True, blank=True, null=True)
account_handler = models.ForeignKey(User, blank=True, null=True, related_name='handling_leads', on_delete=models.SET_NULL)
next_action_date = models.DateField(null=True, verbose_name="Next action on lead")
status_text = models.CharField(max_length=20, default='', blank=True)
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=30)
move the code to check permissions below the code where you check for search param so that you are applying the user filter after checking for search_params
def get_queryset(self):
queryset = LeadContact.objects.all()
if (not user.has_perm('cms_sales.can_view_full_lead_contact_list') and
not user.has_parm('cms_sales.can_view_lead_contact')):
return queryset.none()
user = self.request.user
filter_date = self.request.query_params.get('filter_date', None)
search_params = self.request.query_params.get('search', None)
if filter_date is not None and (search_params is None or len(search_params) == 0):
queryset = queryset.filter(next_action_date=filter_date)
if user.has_perm('cms_sales.can_view_lead_contact') and not search_params:
queryset = queryset.filter(account_handler=user)
return queryset