Django Search in many to many field - django

I am trying to create a search in my Django Rest Framework application I have a table of follower and following via one model called: UserFollowing and the code is:
class UserFollowing(TimeStampedModel):
user_id = models.ForeignKey(
User, related_name="following", on_delete=models.CASCADE, blank=True)
following_user_id = models.ForeignKey(
User, related_name="followers", on_delete=models.CASCADE, blank=True)
#property
def username(self):
profile_instance = Profile.objects.get(user=self.user_id)
username = profile_instance.profile_username
return username
#property
def name(self):
profile_instance = Profile.objects.get(user=self.user_id)
name = profile_instance.name
return name
class Meta:
unique_together = ("user_id", "following_user_id")
ordering = ["-user_id"]
def __str__(self):
return str(self.id)
Here everything works fine but in my following list API, I am appending username and name of the user. When I am getting a list of follower using:
paginator = PageNumberPagination()
query_set = UserFollowing.objects.filter(user_id=request.user.id)
context = paginator.paginate_queryset(query_set, request)
serializer = UserFollowingSerializer(context, many=True)
Now I want to search via the result my serializer.data look like:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 233,
"username": "Username1",
"user_profile_image": "url",
"name": "CDE",
"is_active": true,
"created_at": "2020-07-25T06:00:31.786154Z",
"updated_at": "2020-07-25T06:00:31.786185Z",
"user_id": 88,
"following_user_id": 53,
"is_following": true
},
{
"id": 49,
"username": "username",
"user_profile_image": "URL",
"name": "ABC",
"is_active": true,
"created_at": "2020-07-15T08:32:35.352484Z",
"updated_at": "2020-07-15T08:32:35.352517Z",
"user_id": 88,
"following_user_id": 144,
"is_following": true
}
]
}
So based on my output how can I search a result where username = What can be the best way to search in this case.

Related

Django join ManyToManyField with Intersection Table - Soft Delete

There are three models - Role,Permission, and their intersection as RolePermission
Every models have a active_status flag to denote soft delete. Now when we are trying to fetch all roles joined with their respective active positions through RolePosition model, the Inactive ones are still there.
class Role(models.Model):
name = models.CharField(_('Role Name'),null=False,max_length=255,unique=True,blank=False)
organization = models.ForeignKey('organization.Organization',blank=False, null=True,on_delete=models.SET_NULL)
active_status = models.CharField(max_length=40,choices=(('ACTIVE','ACTIVE'),('INACTIVE','INACTIVE')),default='ACTIVE')
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(null=True)
permissions = models.ManyToManyField(Permission, through='RolePermission')
#------------------plan details ---------------------
class Meta:
verbose_name = "role"
db_table = 'ontym_roles'
def __str__(self):
return self.name
def save(self, *args, **kwargs):
''' On save, update timestamps '''
timestamp = timezone.now()
if not self.id:
self.created_at = timestamp
self.updated_at = timestamp
return super(Role, self).save(*args, **kwargs)
#----------------------- manp many to many role permissions -------------------
class RolePermission(models.Model):
role = models.ForeignKey(Role,null=False,blank=False,on_delete=models.CASCADE)
permission = models.ForeignKey(Permission,null=False,blank=False,on_delete=models.CASCADE)
active_status = models.CharField(max_length=40,choices=(('ACTIVE','ACTIVE'),('INACTIVE','INACTIVE')),default='ACTIVE')
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(null=True)
class Meta:
verbose_name = "role_permission"
db_table = 'ontym_role_permission'
def save(self, *args, **kwargs):
''' On save, update timestamps '''
timestamp = timezone.now()
if not self.id:
self.created_at = timestamp
self.updated_at = timestamp
return super(RolePermission, self).save(*args, **kwargs)
roles = Role.objects.filter(rolepermission__permission__active_status__exact='ACTIVE')
And getting a response ->
{
"status": true,
"code": 200,
"message": "All Roles fetched sucessfully for current organization",
"data": [
{
"id": 1,
"name": "ROLE_MANAGER",
"active_status": "ACTIVE",
"permissions": [
{
"id": 1,
"name": "ROLE_CREATE",
"active_status": "ACTIVE",
},
{
"id": 2,
"name": "ROLE_VIEW",
"active_status": "ACTIVE",
}
]
},
{
"id": 4,
"name": "MANAGE_",
"active_status": "ACTIVE",
"permissions": [
{
"id": 1,
"name": "ROLE_CREATE",
"active_status": "ACTIVE",
},
{
"id": 2,
"name": "ROLE_VIEW",
"active_status": "ACTIVE",
}
]
},
{
"id": 5,
"name": "ROLE_MANAGER_NEW",
"active_status": "ACTIVE",
"permissions": [
{
"id": 1,
"name": "ROLE_CREATE",
"active_status": "ACTIVE",
},
{
"id": 2,
"name": "ROLE_VIEW",
"active_status": "ACTIVE",
}
]
}
]
}
Snapshot of DB ->
https://drive.google.com/drive/folders/1b_KSyZE7vEwXuoLDEpkWo4YmmaaAQH0n?usp=sharing

Django Rest Framework serialize additional fields from intermediate model

I am developing a small application that lists the customers of a store. I'm trying to retrieve the additional fields of the intermediate model because a contact can belong to several stores but depending on the store it is premium or not and if he is happy or not.
Here's the JSON response I'd like to get for a Store like /contacts/?store=my_store
[
{
"id": "UX",
"first_name": "UX",
"last_name": "UX",
"email": null,
"mobile": null,
"happy": True,
"premium": True
},
{
"id": "AX",
"first_name": "AX",
"last_name": "AX",
"email": null,
"mobile": null,
"happy": False,
"premium": True
}
]
here are my models:
class Store(BaseModel):
id = models.CharField(primary_key=True, max_length=200)
name = models.CharField(max_length=100)
class Contact(BaseModel):
id = models.CharField(primary_key=True, max_length=200)
first_name = models.CharField(max_length=100, null=True, blank=True)
last_name = models.CharField(max_length=100, null=True, blank=True)
email = models.CharField(max_length=100, null=True, blank=True)
mobile = models.CharField(max_length=100, null=True, blank=True)
stores = models.ManyToManyField(
Store, through="MemberShip", through_fields=("contact", "store")
)
class MemberShip(BaseModel):
contact = models.ForeignKey(
Contact, on_delete=models.CASCADE, related_name="contact_to_store"
)
store = models.ForeignKey(
Store, on_delete=models.CASCADE, related_name="store_to_contact"
)
happy = models.BooleanField(default=True)
premium = models.BooleanField(default=False)
and my serializers:
class MemberShipSerializer(serializers.ModelSerializer):
class Meta:
model = MemberShip
fields = ("contact", "store", "happy", "premium")
class StoreSerializer(serializers.ModelSerializer):
class Meta:
model = Store
fields = ("id", "name")
class ContactSerializer(serializers.ModelSerializer):
infos = MemberShipSerializer(
source="contact_to_store" many=True, read_only=True
)
class Meta:
model = Contact
fields = (
"id", "first_name", "last_name", "email", "mobile", "infos"
)
As you can see, I first tried to gather all the information of the intermediate model in a field before displaying happy and premium but, strangely enough, the infos field is returned with an empty array value.
Python v 3.7
Django v 2.1
DRF v 3.9
You must provide data to MemberShipSerializer . You can use SerializerMethodField. Like that:
class ContactSerializer(serializers.ModelSerializer):
infos = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Contact
fields = (
"id", "first_name", "last_name", "email", "mobile", "infos"
)
def get_infos(self,obj:Contact):
return MemberShipSerializer(obj.contact_to_store.all(),many=True).data
I tried kamilyrb's solution here's what I changed:
class MemberShipSerializer(serializers.ModelSerializer):
class Meta:
model = MemberShip
fields = ("contact", "store", "happy", "premium")
class StoreSerializer(serializers.ModelSerializer):
class Meta:
model = Store
fields = ("id", "name")
class ContactSerializer(serializers.ModelSerializer):
happy = serializers.SerializerMethodField(read_only=True)
premium = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Contact
fields = (
"id", "first_name", "last_name", "email", "mobile", "happy", "premium"
)
def get_premium(self, obj):
return MemberShipSerializer(obj.contact_to_store.all(), many=True).data
def get_happy(self, obj):
return MemberShipSerializer(obj.contact_to_store.all(), many=True).data
This is what i have now:
[
{
"id": "UX",
"first_name": "UX",
"last_name": "UX",
"email": "0",
"mobile": null,
"happy": [
{
"store": "my-store",
"contact": "UX",
"happy": true,
"premium": false,
},
{
"store": "my-store2",
"contact": "UX",
"happy": false,
"premium": false,
}
],
"premium": [
{
"store": "my-store",
"contact": "UX",
"optin_sms": true,
"happy": false,
"premium": false
}
]
}
]
how can i get that ?
[
{
"id": "UX",
"first_name": "UX",
"last_name": "UX",
"email": null,
"mobile": null,
"happy": True,
"premium": True
},
{
"id": "AX",
"first_name": "AX",
"last_name": "AX",
"email": null,
"mobile": null,
"happy": False,
"premium": True
}
]
I also noticed that all the stores to which a contact is affiliated are shown but as I said before the url is called as follows contact/?store=my-store

Django-Rest-Framework POST request to ManyToMany Field

I have a django model that is a message. It has a name which is a CharField, then also an array of users which is a ManyToManyField.
So This is what my API looks like:
[
{
"id": 13,
"content": "hej",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 14,
"content": "hej william",
"date": "2019-07-09",
"sender": {
"id": 3,
"username": "ryan"
}
}
]
What I've tried to send via postman POST:
{
"content": "Hello",
"sender": {"username": "william"},
"date": "2019-09-02"
}
The Error I get:
sqlite3.IntegrityError: NOT NULL constraint failed: chat_message.sender_id
ManyToManyField(Userprofile=User):
class Message(models.Model):
sender = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name="sendermessage")
content = models.CharField(max_length=500)
date = models.DateField(default=date.today)
canview = models.ManyToManyField(UserProfile, blank=True, related_name="messagecanview")
class Meta:
verbose_name_plural = 'Messages'
def __str__(self):
return "{sender}".format(sender=self.sender)
Assuming that you have a MessageSerializer class implemented, you could override its create() method in order to support writable nested representations:
class MessageSerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
sender_data = validated_data.pop('sender')
sender = UserProfile.objects.create(**sender_data)
return Message.objects.create(sender=sender, **validated_data)
You pop the sender data from the dictionary, create a UserProfile instance with the attributes in there and then attach it to your Message creation.
This will resolve your error since now there is a real sender created before the actual message has been saved.

Inserting foreign key in django rest framework

Here is the code that i am using for serializer
class CitySerializer(serializers.ModelSerializer):
addedBy = serializers.ReadOnlyField(source='addedBy.username')
country = CountrySerializer()
class Meta:
model = City
fields = ('id','name','slug','country','addedBy','createdAt')
class ActivitySerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
tag = ActivityTagSerializer()
location = CitySerializer()
class Meta:
model = Activity
fields = ('id','title','slug','description','location','tag','owner','createdAt')
i am able to insert data if i remove tag and location serializer by adding there pk in form but not with them being serialized. Here is the views that are being used
class ActivityList(generics.ListCreateAPIView):
queryset = Activity.objects.all()
serializer_class = ActivitySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class ActivityDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Activity.objects.all()
serializer_class = ActivitySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
The owner field is read-only so thats why had to create a separate insert for the same. Now here are the outputs from the two case , with and without reference to other serializer (tag and location) in ActivitySerializer
{
"id": 3,
"title": "sdfsdf",
"slug": "sdfsdf",
"description": "sdfsdfsdf",
"location": {
"id": 2,
"name": "goa",
"slug": "goa",
"country": {
"id": 1,
"name": "india",
"slug": "india",
"addedBy": "georoot",
"createdAt": "2016-06-17T05:56:30.099121Z"
},
"addedBy": "georoot",
"createdAt": "2016-06-17T06:01:12.771079Z"
},
"tag": {
"id": 3,
"title": "temp",
"slug": "temp",
"addedBy": "georoot",
"createdAt": "2016-06-17T06:03:44.647455Z"
},
"owner": "georoot",
"createdAt": "2016-06-17T06:24:50.006344Z"
}
This is with reference to serializer which is the output view that i want, but insert not working in this case
and this is without reference to the serializer
{
"id": 3,
"title": "sdfsdf",
"slug": "sdfsdf",
"description": "sdfsdfsdf",
"location": 2,
"tag": 3,
"owner": "georoot",
"createdAt": "2016-06-17T06:24:50.006344Z"
}
Here i can change the values of tag and location by passing in the pk.
How can i do the same while referencing to other serializer as in the previous output
EDIT
structure for models
class City(models.Model):
name = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='name')
country = models.ForeignKey(Country)
addedBy = models.ForeignKey('auth.user')
createdAt = models.DateTimeField(auto_now_add=True, blank=True)
class Activity(models.Model):
owner = models.ForeignKey('auth.user')
title = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='title')
description = models.TextField()
location = models.ForeignKey(City)
tag = models.ForeignKey(ActivityTag)
createdAt = models.DateTimeField(auto_now_add=True, blank=True)

Distinct field Rest Framework Django

I need to make a distinct with a field of my model and not how to make
My model is:
class CheckList(CoreModel):
date = models.DateTimeField(default=datetime.now, blank=True, null=True, verbose_name=_('Date'))
establishment = models.ForeignKey(Establishment, related_name="checklists", on_delete=models.CASCADE, null=True, verbose_name=_('Establishment'))
user = models.ForeignKey(ITManager, related_name="checklists", on_delete=models.CASCADE, null=True, verbose_name=_('User'))
class Meta:
verbose_name_plural = _("Checklist")
verbose_name = _("Checklists")
def __str__(self):
return str(self.date)
My serializer and view:
class CheckListSerializer(BulkSerializerMixin, serializers.ModelSerializer):
user = ITManagerSerializer()
class Meta:
model = CheckList
list_serializer_class = BulkListSerializer
fields = ['id', 'user', 'establishment', 'date']
class ChecklistBulkViewSet(BulkModelViewSet):
queryset = CheckList.objects.values('establishment', 'user', 'date').distinct()
model = CheckList
serializer_class = CheckListSerializer
filter_class = ChecklistFilter
The api return me:
"results": [
{
"id": 1,
"user": {
"id": 3,
"first_name": "Andres",
"last_name": "Gallardo",
"rut": "21312",
"email": null,
"user_name": "andres",
"password": null,
"user": 4,
"country": [],
"active": true
},
"establishment": 3,
"date": "2016-06-14T15:15:00Z"
},
{
"id": 2,
"user": {
"id": 2,
"first_name": "Ramiro",
"last_name": "Gutierrez",
"rut": "15616+",
"email": null,
"user_name": null,
"password": null,
"user": 2,
"country": [
{
"id": 1,
"name": "Argentina",
"code_area": null
}
],
"active": false
},
"establishment": 3,
"date": "2016-06-09T15:40:04Z"
}]
I need you just leave me an establishment with the same id
any suggestions??
Thanks !