Distinct field Rest Framework Django - 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 !

Related

How can I create the associated OneToOne Field in Django automatically?

I have tried Django Annoying as mentioned in this answer
Create OneToOne instance on model creation
But I still get NOT NULL CONSTRAINT FAILED on the OneToOne Field when creating my object, which I suppose means that the associated object is not created, hence NULL
If I use A signal Handler, that will be activated every time the Model's save method will be called. I will end up creating a new Object even when updating the Parent object.
My Profile structure is as follows:
{
"id": 3,
"password": "pbkdf2_sha256$320000$5TQCdD5wIelYpO4ktpuuAk$oBC9xUT+8RjOxZHvE8C+eowS4PvdCT8vUAuS4Y2n7sM=",
"last_login": null,
"is_superuser": false,
"username": "hamad",
"first_name": "",
"last_name": "alahmed",
"email": "",
"is_staff": false,
"is_active": true,
"date_joined": "2022-06-17T13:04:51.927199Z",
"height": null,
"weight": null,
"createddate": "2022-06-17T13:04:52.362396Z",
"date": null,
"hobbies": null,
"dailyRoutine": {
"id": 8,
"steps": 0,
"diet": "No Specified Diet",
"maintained": 0
},
"groups": [],
"user_permissions": [],
"friends": [
{
"id": 1,
"password": "pbkdf2_sha256$320000$YRcHWSjLi1CMbfrolZ0W7W$9LgjH2m5c8emE66pjdExmgep47BAdKTrCJ7MBiJx74w=",
"last_login": "2022-06-17T17:50:48.410366Z",
"is_superuser": true,
"username": "super",
"first_name": "Super1",
"last_name": "Admin1",
"email": "super#gmail.com",
"is_staff": true,
"is_active": true,
"date_joined": "2022-06-17T12:27:37.575631Z",
"height": 160,
"weight": 75,
"createddate": "2022-06-17T12:27:37.789754Z",
"date": null,
"hobbies": "Football",
"dailyRoutine": 10,
"groups": [],
"user_permissions": [],
"friends": [
2,
3
]
}
]
}
The Object that I want to create automatically is DailyRoutine
The Routine code:
class Routine(models.Model):
steps = models.IntegerField(default=0)
diet = models.TextField(default='No Specified Diet')
maintained = models.IntegerField(default=0)
The Profile code
class Profile(AbstractUser):
height = models.IntegerField(blank=True, null=True)
weight = models.IntegerField(blank=True, null=True)
createddate = models.DateTimeField(auto_now_add=True)
date = models.DateField(blank=True, null=True)
hobbies = models.TextField(blank=True, null=True)
dailyRoutine = models.OneToOneField(Routine, related_name='dailyRoutine', on_delete=models.CASCADE)
friends = models.ManyToManyField("Profile", blank=True)
# def save(self, *args, **kwargs): Doing this will always create new DailyRoutine objects even when updating
# self.dailyRoutine = Routine.objects.create()
# super(AbstractUser, self).save(*args, **kwargs)

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: 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}

Post Request to Django Rest Api that has a filter. So messages/?room=4

My Backend is built like this. Every 'Room' has 'Messages' And Every Message has a Sender (person who sends it).
I want to make a post request to messages/?room=4. So I want to basically add a message directly to the room with id=4.
//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, related_name='room')
messages = models.ManyToManyField(Message, blank=True, related_name='room')
class Meta:
verbose_name_plural = 'Rooms'
def __str__(self):
return "{name}".format(name=self.name)
//serializers, views
class UserProfileSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = UserProfile
fields = ('id', 'username')
class MessageSerializer(serializers.ModelSerializer):
sender_obj = UserProfileSerializer(source='sender', read_only=True)
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender', 'sender_obj')
class RoomSerializer(serializers.ModelSerializer):
messages = MessageSerializer(many=True, read_only=True)
members = UserProfileSerializer(many=True, read_only=True)
class Meta:
model = Room
fields = ('id', 'name', 'members', 'messages')
class UserProfileView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
filter_backends = (
django_filters.rest_framework.DjangoFilterBackend,
rest_framework.filters.OrderingFilter,
)
filter_fields = ['room']
class MessageView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerializer
filter_backends = (
django_filters.rest_framework.DjangoFilterBackend,
rest_framework.filters.OrderingFilter,
)
filter_fields = ['room']
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)
API all messages:
[
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": 1,
"sender_obj": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": 2,
"sender_obj": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": 3,
"sender_obj": {
"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": 2,
"sender_obj": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": 1,
"sender_obj": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": 2,
"sender_obj": {
"id": 2,
"username": "eric"
}
},
{
"id": 13,
"content": "hej",
"date": "2019-07-09",
"sender": 1,
"sender_obj": {
"id": 1,
"username": "william"
}
},
{
"id": 14,
"content": "hej william",
"date": "2019-07-09",
"sender": 3,
"sender_obj": {
"id": 3,
"username": "ryan"
}
}
]
API messages/?room=4
[
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": 1,
"sender_obj": {
"id": 1,
"username": "william"
}
},
{
"id": 13,
"content": "hej",
"date": "2019-07-09",
"sender": 1,
"sender_obj": {
"id": 1,
"username": "william"
}
},
{
"id": 14,
"content": "hej william",
"date": "2019-07-09",
"sender": 3,
"sender_obj": {
"id": 3,
"username": "ryan"
}
}
]
If someone has a solution it would help loads. I need to get this to work because its a chat application I am developing on flutter- mobile.
Change your MessageSerializer to expose the room related_field ( which is a ManyToManyField and thus each message can be associated to multiple rooms...):
class MessageSerializer(serializers.ModelSerializer):
[...]
fields = ('id', 'content', 'date', 'sender', 'sender_obj', 'room')
# ^^^^^^^^
POST to your /message interface like:
{
"content": "foodefafa",
"sender": 17,
"rooms":[42]
}

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"
}
]
}