Django Rest Framework: SerializerMethodField and get_queryset












1














In my database I have two tables - users and user_properties



I need to filter output using GET parameter phone. But both this tables has column phone and has different values.



When I doing GET request (ex. "?phone=123456789") I need to search User by phone number using not only user_properties.phone, but user.phone too!



I googled and found a way partially to do this using get_queryset(filtering) and SerializerMethodField(to modify output):



models.py



class User(models.Model):
balance = models.DecimalField(decimal_places=35, max_digits=40)
fio = models.CharField(max_length=64)
phone = models.CharField(max_length=64, blank=True, null=True)

class Meta:
managed = False
db_table = 'user'


class UserProperties(models.Model):
user_id = models.IntegerField(primary_key=True)
phone = models.CharField(max_length=11)

class Meta:
managed = False
db_table = 'user_properties'


views.py



class UserPropertiesViewSet(viewsets.ModelViewSet):
queryset = UserProperties.objects.all()
serializer_class = serializers.UserPropertiesSerializer

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

# Search users matches in user_properties using by phone number
if phone:
queryset = UserProperties.objects.all()
users = queryset.filter(phone__contains=phone)
return users
else:
return queryset


serializers.py



class UserPropertiesSerializer(serializers.ModelSerializer):
all_phones = serializers.SerializerMethodField()

class Meta:
model = models.UserProperties
fields = ['user_id', 'phone', 'fio', 'url', 'all_phones',]

# phone numbers from user and user_properties tables
def get_all_phones(self, obj):
# search phones in <user> table by user_id
user_phones = models.User.objects.filter(id__exact=obj.user_id).values_list('phone', flat=True)
# add phones from user_properties table
result = [obj.phone,]
# add phones from user table
for phone in user_phones[0].split(','):
result.append(''.join(filter(lambda x: x.isdigit(), phone)))

# return list with all phones
return set(result)


And I get all_phones column in my filtered results:



{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"user_id": 17897,
"phone": "123456789", <--- user_properties table
"fio": "....",
"url": "....",
"all_phones": [
"123456789",
"5512222",
"49543"
] <--- user_properties.phone + user.phone
}
]


}



But in the get_queryset I filtering only using "real" phone column in user_properties table. How to filter results using "virtual" all_phones column? Or search in two tables and get User who has one of this phone numbers? Is it's possible? Or my way is not correct?



Thanks!










share|improve this question
























  • You cannot depend on the Django ORM to search through 2 different tables. You will either have to query twice and join the results, or normalize your data and move all phone numbers to one table.
    – LaundroMat
    Nov 21 '18 at 14:05
















1














In my database I have two tables - users and user_properties



I need to filter output using GET parameter phone. But both this tables has column phone and has different values.



When I doing GET request (ex. "?phone=123456789") I need to search User by phone number using not only user_properties.phone, but user.phone too!



I googled and found a way partially to do this using get_queryset(filtering) and SerializerMethodField(to modify output):



models.py



class User(models.Model):
balance = models.DecimalField(decimal_places=35, max_digits=40)
fio = models.CharField(max_length=64)
phone = models.CharField(max_length=64, blank=True, null=True)

class Meta:
managed = False
db_table = 'user'


class UserProperties(models.Model):
user_id = models.IntegerField(primary_key=True)
phone = models.CharField(max_length=11)

class Meta:
managed = False
db_table = 'user_properties'


views.py



class UserPropertiesViewSet(viewsets.ModelViewSet):
queryset = UserProperties.objects.all()
serializer_class = serializers.UserPropertiesSerializer

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

# Search users matches in user_properties using by phone number
if phone:
queryset = UserProperties.objects.all()
users = queryset.filter(phone__contains=phone)
return users
else:
return queryset


serializers.py



class UserPropertiesSerializer(serializers.ModelSerializer):
all_phones = serializers.SerializerMethodField()

class Meta:
model = models.UserProperties
fields = ['user_id', 'phone', 'fio', 'url', 'all_phones',]

# phone numbers from user and user_properties tables
def get_all_phones(self, obj):
# search phones in <user> table by user_id
user_phones = models.User.objects.filter(id__exact=obj.user_id).values_list('phone', flat=True)
# add phones from user_properties table
result = [obj.phone,]
# add phones from user table
for phone in user_phones[0].split(','):
result.append(''.join(filter(lambda x: x.isdigit(), phone)))

# return list with all phones
return set(result)


And I get all_phones column in my filtered results:



{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"user_id": 17897,
"phone": "123456789", <--- user_properties table
"fio": "....",
"url": "....",
"all_phones": [
"123456789",
"5512222",
"49543"
] <--- user_properties.phone + user.phone
}
]


}



But in the get_queryset I filtering only using "real" phone column in user_properties table. How to filter results using "virtual" all_phones column? Or search in two tables and get User who has one of this phone numbers? Is it's possible? Or my way is not correct?



Thanks!










share|improve this question
























  • You cannot depend on the Django ORM to search through 2 different tables. You will either have to query twice and join the results, or normalize your data and move all phone numbers to one table.
    – LaundroMat
    Nov 21 '18 at 14:05














1












1








1







In my database I have two tables - users and user_properties



I need to filter output using GET parameter phone. But both this tables has column phone and has different values.



When I doing GET request (ex. "?phone=123456789") I need to search User by phone number using not only user_properties.phone, but user.phone too!



I googled and found a way partially to do this using get_queryset(filtering) and SerializerMethodField(to modify output):



models.py



class User(models.Model):
balance = models.DecimalField(decimal_places=35, max_digits=40)
fio = models.CharField(max_length=64)
phone = models.CharField(max_length=64, blank=True, null=True)

class Meta:
managed = False
db_table = 'user'


class UserProperties(models.Model):
user_id = models.IntegerField(primary_key=True)
phone = models.CharField(max_length=11)

class Meta:
managed = False
db_table = 'user_properties'


views.py



class UserPropertiesViewSet(viewsets.ModelViewSet):
queryset = UserProperties.objects.all()
serializer_class = serializers.UserPropertiesSerializer

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

# Search users matches in user_properties using by phone number
if phone:
queryset = UserProperties.objects.all()
users = queryset.filter(phone__contains=phone)
return users
else:
return queryset


serializers.py



class UserPropertiesSerializer(serializers.ModelSerializer):
all_phones = serializers.SerializerMethodField()

class Meta:
model = models.UserProperties
fields = ['user_id', 'phone', 'fio', 'url', 'all_phones',]

# phone numbers from user and user_properties tables
def get_all_phones(self, obj):
# search phones in <user> table by user_id
user_phones = models.User.objects.filter(id__exact=obj.user_id).values_list('phone', flat=True)
# add phones from user_properties table
result = [obj.phone,]
# add phones from user table
for phone in user_phones[0].split(','):
result.append(''.join(filter(lambda x: x.isdigit(), phone)))

# return list with all phones
return set(result)


And I get all_phones column in my filtered results:



{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"user_id": 17897,
"phone": "123456789", <--- user_properties table
"fio": "....",
"url": "....",
"all_phones": [
"123456789",
"5512222",
"49543"
] <--- user_properties.phone + user.phone
}
]


}



But in the get_queryset I filtering only using "real" phone column in user_properties table. How to filter results using "virtual" all_phones column? Or search in two tables and get User who has one of this phone numbers? Is it's possible? Or my way is not correct?



Thanks!










share|improve this question















In my database I have two tables - users and user_properties



I need to filter output using GET parameter phone. But both this tables has column phone and has different values.



When I doing GET request (ex. "?phone=123456789") I need to search User by phone number using not only user_properties.phone, but user.phone too!



I googled and found a way partially to do this using get_queryset(filtering) and SerializerMethodField(to modify output):



models.py



class User(models.Model):
balance = models.DecimalField(decimal_places=35, max_digits=40)
fio = models.CharField(max_length=64)
phone = models.CharField(max_length=64, blank=True, null=True)

class Meta:
managed = False
db_table = 'user'


class UserProperties(models.Model):
user_id = models.IntegerField(primary_key=True)
phone = models.CharField(max_length=11)

class Meta:
managed = False
db_table = 'user_properties'


views.py



class UserPropertiesViewSet(viewsets.ModelViewSet):
queryset = UserProperties.objects.all()
serializer_class = serializers.UserPropertiesSerializer

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

# Search users matches in user_properties using by phone number
if phone:
queryset = UserProperties.objects.all()
users = queryset.filter(phone__contains=phone)
return users
else:
return queryset


serializers.py



class UserPropertiesSerializer(serializers.ModelSerializer):
all_phones = serializers.SerializerMethodField()

class Meta:
model = models.UserProperties
fields = ['user_id', 'phone', 'fio', 'url', 'all_phones',]

# phone numbers from user and user_properties tables
def get_all_phones(self, obj):
# search phones in <user> table by user_id
user_phones = models.User.objects.filter(id__exact=obj.user_id).values_list('phone', flat=True)
# add phones from user_properties table
result = [obj.phone,]
# add phones from user table
for phone in user_phones[0].split(','):
result.append(''.join(filter(lambda x: x.isdigit(), phone)))

# return list with all phones
return set(result)


And I get all_phones column in my filtered results:



{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"user_id": 17897,
"phone": "123456789", <--- user_properties table
"fio": "....",
"url": "....",
"all_phones": [
"123456789",
"5512222",
"49543"
] <--- user_properties.phone + user.phone
}
]


}



But in the get_queryset I filtering only using "real" phone column in user_properties table. How to filter results using "virtual" all_phones column? Or search in two tables and get User who has one of this phone numbers? Is it's possible? Or my way is not correct?



Thanks!







django rest api django-rest-framework






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 8:16

























asked Nov 21 '18 at 13:49









Serg

286




286












  • You cannot depend on the Django ORM to search through 2 different tables. You will either have to query twice and join the results, or normalize your data and move all phone numbers to one table.
    – LaundroMat
    Nov 21 '18 at 14:05


















  • You cannot depend on the Django ORM to search through 2 different tables. You will either have to query twice and join the results, or normalize your data and move all phone numbers to one table.
    – LaundroMat
    Nov 21 '18 at 14:05
















You cannot depend on the Django ORM to search through 2 different tables. You will either have to query twice and join the results, or normalize your data and move all phone numbers to one table.
– LaundroMat
Nov 21 '18 at 14:05




You cannot depend on the Django ORM to search through 2 different tables. You will either have to query twice and join the results, or normalize your data and move all phone numbers to one table.
– LaundroMat
Nov 21 '18 at 14:05












1 Answer
1






active

oldest

votes


















1














This question is more about the Django ORM than Django REST framework, but rewriting the get_queryset method like this will search on the phone fields of both models:



from django.db.models import Q

...

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

if phone:
queryset = queryset.filter(
Q(phone__contains=phone)
| Q(user__phone__contains=phone)
)

return queryset





share|improve this answer























  • Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
    – Serg
    Nov 21 '18 at 17:40










  • For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
    – kristaps
    Nov 22 '18 at 1:37










  • Updated my post. I couldn't change my database tables - read only.
    – Serg
    Nov 22 '18 at 8:26










  • That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
    – kristaps
    Nov 22 '18 at 13:24












  • THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
    – Serg
    Nov 22 '18 at 13:53











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53413542%2fdjango-rest-framework-serializermethodfield-and-get-queryset%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














This question is more about the Django ORM than Django REST framework, but rewriting the get_queryset method like this will search on the phone fields of both models:



from django.db.models import Q

...

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

if phone:
queryset = queryset.filter(
Q(phone__contains=phone)
| Q(user__phone__contains=phone)
)

return queryset





share|improve this answer























  • Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
    – Serg
    Nov 21 '18 at 17:40










  • For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
    – kristaps
    Nov 22 '18 at 1:37










  • Updated my post. I couldn't change my database tables - read only.
    – Serg
    Nov 22 '18 at 8:26










  • That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
    – kristaps
    Nov 22 '18 at 13:24












  • THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
    – Serg
    Nov 22 '18 at 13:53
















1














This question is more about the Django ORM than Django REST framework, but rewriting the get_queryset method like this will search on the phone fields of both models:



from django.db.models import Q

...

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

if phone:
queryset = queryset.filter(
Q(phone__contains=phone)
| Q(user__phone__contains=phone)
)

return queryset





share|improve this answer























  • Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
    – Serg
    Nov 21 '18 at 17:40










  • For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
    – kristaps
    Nov 22 '18 at 1:37










  • Updated my post. I couldn't change my database tables - read only.
    – Serg
    Nov 22 '18 at 8:26










  • That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
    – kristaps
    Nov 22 '18 at 13:24












  • THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
    – Serg
    Nov 22 '18 at 13:53














1












1








1






This question is more about the Django ORM than Django REST framework, but rewriting the get_queryset method like this will search on the phone fields of both models:



from django.db.models import Q

...

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

if phone:
queryset = queryset.filter(
Q(phone__contains=phone)
| Q(user__phone__contains=phone)
)

return queryset





share|improve this answer














This question is more about the Django ORM than Django REST framework, but rewriting the get_queryset method like this will search on the phone fields of both models:



from django.db.models import Q

...

def get_queryset(self):
queryset = self.queryset
# phone number from GET
phone = self.request.query_params.get('phone')

if phone:
queryset = queryset.filter(
Q(phone__contains=phone)
| Q(user__phone__contains=phone)
)

return queryset






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 21 '18 at 14:24

























answered Nov 21 '18 at 14:19









kristaps

1,360712




1,360712












  • Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
    – Serg
    Nov 21 '18 at 17:40










  • For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
    – kristaps
    Nov 22 '18 at 1:37










  • Updated my post. I couldn't change my database tables - read only.
    – Serg
    Nov 22 '18 at 8:26










  • That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
    – kristaps
    Nov 22 '18 at 13:24












  • THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
    – Serg
    Nov 22 '18 at 13:53


















  • Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
    – Serg
    Nov 21 '18 at 17:40










  • For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
    – kristaps
    Nov 22 '18 at 1:37










  • Updated my post. I couldn't change my database tables - read only.
    – Serg
    Nov 22 '18 at 8:26










  • That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
    – kristaps
    Nov 22 '18 at 13:24












  • THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
    – Serg
    Nov 22 '18 at 13:53
















Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
– Serg
Nov 21 '18 at 17:40




Hi. Thank You for your answer. I gets an error: ""Cannot resolve keyword 'user' into field. Choices are: email, phone, " ... etc (columns list from user_properties table). Will Q work with two tables without relationships? Seems like no
– Serg
Nov 21 '18 at 17:40












For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
– kristaps
Nov 22 '18 at 1:37




For the example to work, the tables will need to have a relation defined - ForeignKey or OneToOneField. Can you update your post include the relevant parts of your User and UserProperties models?
– kristaps
Nov 22 '18 at 1:37












Updated my post. I couldn't change my database tables - read only.
– Serg
Nov 22 '18 at 8:26




Updated my post. I couldn't change my database tables - read only.
– Serg
Nov 22 '18 at 8:26












That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
– kristaps
Nov 22 '18 at 13:24






That's ok, changing the model definition should be enough. Change the user_id field definition and try again: user = models.OneToOneField(User, primary_key=True) (Note that the field has been renamed from user_id to user)
– kristaps
Nov 22 '18 at 13:24














THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
– Serg
Nov 22 '18 at 13:53




THANK YOU!!! This is what I need. But could You explain me: table user_properties will not be changed by Django after I run "migrate" command in future? I have managed=False and when i running migrate command I add --fake keyword.
– Serg
Nov 22 '18 at 13:53


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53413542%2fdjango-rest-framework-serializermethodfield-and-get-queryset%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

404 Error Contact Form 7 ajax form submitting

How to know if a Active Directory user can login interactively

Refactoring coordinates for Minecraft Pi buildings written in Python