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

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)

Related

How to set 0, instead of null?

I have 'average_rating' field that takes values from field 'rates' and calculate average value. But when 'rates' field is empty, its shows null. views.py:
class BooksView(viewsets.ModelViewSet):
serializer_class = BooksSerializer
queryset = BooksModel.objects.all()
filter_backends = [filters.DjangoFilterBackend, filtersrest.SearchFilter, filtersrest.OrderingFilter,]
filterset_class = Myfilter
filterset_fields = ('genres','date',)
search_fields = ['title']
def get_queryset(self):
return BooksModel.objects.all().annotate(average_rating=models.ExpressionWrapper(Round(Avg('rates__rate'), 2), output_field=models.FloatField()), _sum_users_cart=Count('users__user'))
In the output i have this:
"id": 18,
"authors": [
{
"author": "Андрей курпатов"
}
],
"age": [],
"tags": [],
"users": [],
"genres": [],
"rates": [],
"average_rating": null,
"sum_users_cart": 0,
"title": "Мозг и бизнес",
"desc": "123",
"url_photo": "https://s1.livelib.ru/boocover/1007572198/o/fde7/Andrej_Kurpatov__Mozg_i_biznes.jpeg",
"is_published": true,
"date": "Декабрь 29, 2022",
"time": "20:20:02"
And i need something like this:
"id": 18,
"authors": [
{
"author": "Андрей курпатов"
}
],
"age": [],
"tags": [],
"users": [],
"genres": [],
"rates": [],
"average_rating": 0,
"sum_users_cart": 0,
"title": "Мозг и бизнес",
"desc": "123",
"url_photo": "https://s1.livelib.ru/boocover/1007572198/o/fde7/Andrej_Kurpatov__Mozg_i_biznes.jpeg",
"is_published": true,
"date": "Декабрь 29, 2022",
"time": "20:20:02"
you can add a default value for the average_ratingin your models.py
for example:
from django.db import models
class BooksModel(models.Model):
...
average_rating = models.DecimalField(max_digits=12, decimal_places=2, default=0, null=False)
...
by doing that you ensure that whenever the value of average_rating is not set it will always be set to 0 instead of None.
You may try to do it like this:
from django.db.models import Case, When, FloatField
return BooksModel.objects.all().annotate(
average_rating=Case(
When(rates__isnull=True, then=0),
default=Round(Avg('rates__rate'), 2),
output_field=FloatField()
),
_sum_users_cart=Count('users__user')
)

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.

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

How to serialize ForeignKey in Django rest?

I'm using the latest version of django rest framework.
I have this model:
class Subscriptions(models.Model):
subs_list = models.ForeignKey(SubsList, verbose_name='Subscription list', on_delete=models.CASCADE, related_name='subs_list') # идентификатор подписного листа
subscriber = models.ForeignKey(Subscribers, verbose_name='Subscriber', on_delete=models.CASCADE) # идентификатор подписчика
created_date = models.DateTimeField(verbose_name='Created date', auto_now=True) # дата добавления подписчика в подписной лист
deleted = models.NullBooleanField(verbose_name='Deleted') # True-удален из подписного листа, False/null-в подписном листе
How do I serialize it? The main question is how to serialize ForeignKey, that would be associated with the query related data, i.e. NOT:
"id": 29,
"created_date": "2018-03-01T14:28:41.237742Z",
"deleted": false,
"subs_list": 1,
"subscriber": 1
but like this
"id": 29,
"subs_list": {
"id": 1,
"uuid": "d183bab7-af26-48f8-9ef5-ea48e09a95a9",
"name": "TEST",
"description": "TEST",
"created_date": "2018-03-01T13:15:18.808709Z",
"deleted": null,
"user": 6
},
"subscriber": {
"id": 1,
"bot_id": "1",
"name_messenger": "11",
"username": "1",
"first_name": "1",
"last_name": "1",
"created_date": "9999-03-01T16:47:51.440000Z",
"subscribed": true,
"chat_bot": "1",
"phone": "1",
"user": 1
},
"created_date": "2018-03-01T14:28:41.237742Z",
"deleted": false
I have such a serializer:
...
class SubscriptionsSerializer(serializers.ModelSerializer):
subs_list = SubsListSerializer(read_only=True)
subscriber = SubscribersSerializer(read_only=True)
class Meta:
model = Subscriptions
fields = '__all__'
When get requests everything is ok, but how to update and add data is not clear, error:
IntegrityError at /subscriptions/subscriptions/
null value in column "subs_list_id" violates not-null constraint
DETAIL: Failing row contains (41, 2018-03-01 16:10:02.383625+00, f, null, null).
I struggle with this problem for a very long time, read all the related answers, but there is no clarity.
remove read_only=True and change your serializer.py as below
class SubscriptionsSerializer(serializers.ModelSerializer):
subs_list = SubsListSerializer()
subscriber = SubscribersSerializer()
class Meta:
model = Subscriptions
fields = '__all__'
def create(self, validated_data):
sub_lst = SubsList.objects.create(**validated_data['subs_list'])
subscriber = Subscribers.objects.create(**validated_data['subscriber'])
return Subscriptions.objects.create(subs_list=sub_lst, subscriber=subscriber, deleted=validated_data['deleted'])
And your creation payload will be like this,
{
"subs_list": {
"uuid": "d183bab7-af26-48f8-9ef5-ea48e09a95a9",
"name": "TEST",
"description": "TEST",
# etc etc
},
"subscriber": {
"bot_id": "1",
"name_messenger": "11",
"username": "1",
# etc etc
},
"deleted": null
}
I think you have several ForeignKey relationships are there, so you have to map those things carefully in create()
Similar way, you can override update() and which can be used while API updation too.
See this official doc for more info

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 !