Django join ManyToManyField with Intersection Table - Soft Delete - django

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

Related

Django Search in many to many field

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.

How to divide Json strings.?

I have 4 models Category, Vendor, Location, Product. Vendor fall under the Category model (vendor is a foreign key to category). The remaining models are under Vendor (Location, Product)
ProductSerializer and LocationSerializer are nested to VendorSerializer, and VendorSerializer is nested to CategorySerializer.
class ProductSerializer(WritableNestedModelSerializer):
class Meta:
model = Product
fields = ['id', 'item_name', 'price']
read_only_fields = ['id']
class LocationSerializer(WritableNestedModelSerializer):
class Meta:
model = Location
fields = ['place']
class VendorSerializer(WritableNestedModelSerializer):
vendor_location = LocationSerializer()
product = ProductSerializer(many=True)
class Meta:
model = Vendor
fields = ['vendor_name','vendor_location','product']
read_only_fields = ['id']
class CategorySerializer(WritableNestedModelSerializer):
vendor = VendorSerializer(many=True)
class Meta:
model = Category
fields = ['id', 'category_name', 'tittle', 'vendor']
read_only_fields = ['id']
# View
class ProductView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None, *args, **kwargs):
products = Category.objects.all()
serializer = CategorySerializer(products, many=True, context={'request': request})
return Response({'response': 'ok', 'result': serializer.data})
# Output
{
"response": "ok",
"result": [
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 1,
"item_name": "test_1",
"price": 3200,
},
{
"id": 2,
"item_name": "test_2",
"price": 2010,
}
]
}
]
}
]
}
# Expected output
{
"response": "ok",
"result": [
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 1,
"item_name": "test_1",
"price": 3200,
}
]
}
]
},
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 2,
"item_name": "test_2",
"price": 2010,
}
]
}
]
}
]
}
In my output, two products are listed. There may be more than two. I only need one product under the product. All products must be printed in the same structure as I mentioned in expected output. How do I do this? Is it possible? Can someone help me do this?
You can modify this line:
# old:
products = Category.objects.all() # definately these are not products
# new:
products = Product.objects.values_list('id', flat=True) # get all products ids
categories = Category.objects.filter(vendor__product__in=products)
And send categories to CategorySerializer, thought this is still not what you want, as every duplicated category will hold information about all products (not only one).
Where I would go from this point? I'd create method get_product in VendorSerializer and somehow save information what Category/Vendor are we in right now and if we have already added a Product for this Category - I'd skip adding next.
PS. I still don't get why you need this format though.

Django: Make a GET Request to a URL that is advanced

So I have Chat Rooms and I have Messages. Then I have two urls: /messages and /rooms. And these display all your rooms and messages. Also a message can be assigned to a room. So in the Room API I have the messages assigned to that room.
Let's say that the room is called 'Room1' and the messages are 'hey', 'yo' and 'wassup'. If I make a request to just /messages I will get all of the messages. Let's say that only two of the messages are assigned to 'Room1' and the other message is assigned to another room not named.
I want a way to make a get request and only get those two messages assigned to 'Room1 with id = 3' (localhost:8000/rooms/3/messages) instead of: (localhost:8000/messages).
This is an example of when I make a get request to /rooms/3/
{
"id": 3,
"name": "Room 1",
"members": [
{
"id": 1,
"username": "william"
},
{
"id": 2,
"username": "eric"
},
{
"id": 3,
"username": "ryan"
}
],
"messages": [
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": {
"id": 3,
"username": "ryan"
}
},
{
"id": 10,
"content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": {
"id": 2,
"username": "eric"
}
}
]
}
This is what I want to get in response if I do rooms/3/messages:
"messages": [
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": {
"id": 3,
"username": "ryan"
}
},
{
"id": 10,
"content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": {
"id": 2,
"username": "eric"
}
}
]
}
Django Models:
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'All Users'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_data(sender, update_fields, created, instance, **kwargs):
if created:
user = instance
profile = UserProfile.objects.create(user=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)
class Room(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(UserProfile, blank=True)
messages = models.ManyToManyField(Message, blank=True)
class Meta:
verbose_name_plural = 'Rooms'
def __str__(self):
return "{name}".format(name=self.name)enter code here
Django Serializers:
class UserProfileSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = UserProfile
fields = ('id', 'username')
class MessageSerializer(serializers.ModelSerializer):
sender = UserProfileSerializer()
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender')
class RoomSerializer(serializers.ModelSerializer):
messages = MessageSerializer(many=True)
members = UserProfileSerializer(many=True)
class Meta:
model = Room
fields = ('id', 'name', 'members', 'messages')
Django Views:
class UserProfileView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
class MessageView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerializer
class UserMessageView(MessageView):
def get_queryset(self):
return Message.objects.filter(canview__user=self.request.user)
class RoomView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Room.objects.all()
serializer_class = RoomSerializer
class UserRoomView(RoomView):
def get_queryset(self):
return Room.objects.filter(members__user=self.request.user)
Django Urls:
router = routers.DefaultRouter()
router.register('users', views.UserProfileView),
router.register('rooms', views.UserRoomView),
router.register('messages', views.UserMessageView),
urlpatterns = [
path('', include(router.urls)),
]
To get all Messages assigned to a room, let's:
Install django-filter:
pip install django-filter
Modify the Room model to specify a related_name:
class Room(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(UserProfile, blank=True)
messages = models.ManyToManyField(Message, blank=True, related_name='rooms')
# ^^^^^^^^^^^^^^^^^^^^^^
Enable filtering for the rooms related field:
import django_filters
import rest_framework.filters
[...]
class MessageView(viewsets.ModelViewSet):
# vvvvvvvvvvv I don't think this line is needed vvvvvvvvvvvvvv
# http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerialize
filter_backends = (
django_filters.rest_framework.DjangoFilterBackend,
rest_framework.filters.OrderingFilter,
)
filter_fields = ['rooms']
Then, you can request all messages for that room with a GET to:
localhost:8000/messages/?rooms=3
Comment question:
You also need to expose the Message object's sender field. Currently it is aliased:
class MessageSerializer(serializers.ModelSerializer):
# vvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
sender_obj = UserProfileSerializer(source='sender', read_only=True)
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender', 'sender_obj')
# ^^^^^^^^^^^^^^
Then you can POST to /message with the data {"content": "blah", "date": "2019-07-09","sender": 1}

Django-Tastypie self children

Trying to make api for multiple subtasks.
I have the task model, that can have another task as a parent:
class Task(models.Model):
parent_task = models.ForeignKey("Task", null=True, blank=True)
name = models.CharField(max_length=64)
def __unicode__ (self):
return self.name
Now I'm trying to make tastypie resource:
class TaskResource(ModelResource):
parent_task = fields.ForeignKey(TaskResource, 'parent_task', full=False) <-- ERROR HERE
class Meta:
queryset = Task.objects.all()
resource_name = 'task'
list_allowed_methods = ['get', 'put', 'post', 'delete']
include_resource_uri = False
def dehydrate(self, bundle, for_list=False):
bundle.data["subtasks"] = "how?" <-- HOW??
return bundle
Thanks for your time.
P.S. I need something like this:
[
{
"id": 1,
"name": "Task 1",
"subtasks": [
{
"id": 1,
"name": "Task 1",
"subtasks": [...]
}
]
},
{
"id": 2,
"name": "Task 2",
"subtasks": "how?"
}
]
Almost a copy of Including child resources in a Django Tastypie API but not exactly.
So your first problem is that you specify relation to self wrong. It should be just self:
parent_task = fields.ForeignKey('self', 'parent_task', null=True, full=False)
Secondly, notice null=True - parent could be null.
Lastly, you just need to add another relation field and ask for the full details
subtasks = fields.ToManyField('self', 'task_set', full=True)
task_set is a related_name for the Task.parent_task field.
The resulting code is:
class TaskResource(ModelResource):
parent_task = fields.ForeignKey('self', 'parent_task', null=True, full=False)
subtasks = fields.ToManyField('self', 'subtasks', full=True)
class Meta:
queryset = Task.objects.all()
resource_name = 'task'
list_allowed_methods = ['get', 'put', 'post', 'delete']
include_resource_uri = False
And the result:
{
"meta": {
"previous": null,
"total_count": 3,
"offset": 0,
"limit": 20,
"next": null
},
"objects": [
{
"parent_task": null,
"subtasks": [
{
"parent_task": "/api/v1/task/1/",
"subtasks": [],
"id": 2,
"name": "Root's Child 1"
},
{
"parent_task": "/api/v1/task/1/",
"subtasks": [],
"id": 3,
"name": "Root's Child 2"
}
],
"id": 1,
"name": "Root Task"
},
{
"parent_task": "/api/v1/task/1/",
"subtasks": [],
"id": 2,
"name": "Root's Child 1"
},
{
"parent_task": "/api/v1/task/1/",
"subtasks": [],
"id": 3,
"name": "Root's Child 2"
}
]
}

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)