I Have two models clinic and ClinicCredits:
I want a list of clinics withsum of available balance
The Problem is if i use annotate i have to loop for avalibale alance with queryset of cliniccredits :
class Clinic(models.Model):
"""
clinic model
"""
user = models.OneToOneField(User, related_name="clinic", primary_key=True,
on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
db_table = 'clinic'
class ClinicCredits(models.Model):
"""
credit details for clinic
"""
clinic = models.ForeignKey(Clinic, on_delete=models.CASCADE, related_name='c_credits')
credits = models.FloatField('credits', default=0.0)
balance = models.FloatField('balance', default=0.0, help_text="balance after deduction of credits")
def __str__(self):
return self.clinic.name
class Meta:
db_table = 'clinic_credits'
here is my query to fetch clinic:
clinics = Clinic.objects.filter(practice_id__in=user.dietitian.practiceid).order_by(
'user__date_joined').prefetch_related(Prefetch('c_credits',ClinicCredits.objects.filter(balance__gt=0),'credit_'))
and how can i use aggregate in this condition or is there some oter way to retreive clinic list with their available credits.
You can try like this using annotate(...):
clinics = Clinic.objects.filter(
practice_id__in=user.dietitian.practiceid
).order_by('user__date_joined').prefetch_related(
Prefetch(
'c_credits',
ClinicCredits.objects.filter(balance__gt=0),
'credit_'
)
).annotate(
total_cred=Sum('c_credits__balance')
)
Related
Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\
I have form data that I want to serialize to create two objects, Account and AccountClub. AccountClub is the in between table between Account and Club with additional fields, rakeback and chip_value.
I can serialize the formdata but when i call the is.valid() function before saving, I get returned an error with the manytomany fields empty
Here is my models:
class Account(models.Model):
nickname = models.CharField(max_length=64)
club_account_id = models.IntegerField()
agent_players = models.ManyToManyField(
AgentPlayer, related_name="accounts")
clubs = models.ManyToManyField(
Club, through='AccountClub', related_name='accounts')
def __str__(self):
return f"{self.nickname} ({self.club_account_id})"
class AccountClub(models.Model):
account = models.ForeignKey(
Account, on_delete=models.CASCADE, related_name='club_deal')
club = models.ForeignKey(
Club, on_delete=models.CASCADE, related_name='account_deal')
rakeback_percentage = models.DecimalField(
max_digits=3, decimal_places=3, validators=[MinValueValidator(Decimal('0.01'))])
chip_value = models.DecimalField(max_digits=3, decimal_places=2, validators=[
MinValueValidator(Decimal('0.01'))])
def __str__(self):
return f"{self.account.nickname} belongs to {self.club.name} with rakeback of {self.rakeback_percentage} and chip value of {self.chip_value}"
Serializers:
class AgentPlayerSerializer(serializers.ModelSerializer):
class Meta:
model = AgentPlayer
fields = "__all__"
class ClubSerializer(serializers.ModelSerializer):
agent_players = AgentPlayerSerializer(many=True)
class Meta:
model = Club
fields = '__all__'
class AccountSerializer(serializers.ModelSerializer):
agent_players = AgentPlayerSerializer(many=True)
clubs = ClubSerializer(many=True)
class Meta:
model = Account
fields = [
'nickname',
'club_account_id',
'agent_players',
'clubs',
]
def create(self, validated_data):
rakeback_percentage = validated_data.pop('rakeback_percentage')
chip_value = validated_data.pop('chip_value')
club = validated_data.club
account = Account.objects.create(**validated_data)
account.account_club.rakeback_percentage = rakeback_percentage
account.account_club.chip_value = chip_value
AccountClub.create(account=account, club=club,
rakeback_percentage=rakeback_percentage, chip_value=chip_value)
return account
views.py:
def create_account(request):
data = FormParser().parse(request)
serializer = AccountSerializer(data=data)
if serializer.is_valid():
serializer.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next, status=201)
return JsonResponse(serializer.errors, status=400)
your clubs field on the Account model is not blank=True so you can not create an account without at least a club. so you can not do
account = Account.objects.create(**validated_data)
and then do
AccountClub.create(account=account, club=club, rakeback_percentage=rakeback_percentage, chip_value=chip_value)
you may change your Account model code to:
clubs = models.ManyToManyField(Club, through='AccountClub', blank=True, related_name='accounts')
also checkout these links:
https://stackoverflow.com/a/6996358/6484831
https://stackoverflow.com/a/10116452/6484831
Im have two models, Manager and Template, one Template has n Managers,
I want with the template id to get all the managers of the same
I tried to make an api that takes the url template id, and filters the relationship table but it returns me empty
This my models
class Template(TimestampedModel, permissions.TemplatesPermission):
title = models.CharField(
max_length=1000,
db_column='titulo',
verbose_name='título',
db_index=True,
)
description = models.TextField(
db_column='descricao',
verbose_name='descrição',
)
active = models.BooleanField(
default=True,
)
managers = models.ManyToManyField(
Manager,
through='TemplateManager',
)
validity_date = models.DateTimeField(
db_column='data_vigencia',
verbose_name='data de vigência',
)
class Meta:
db_table = 'declaracoes_template'
verbose_name = 'Template'
verbose_name_plural = 'Templates'
def __str__(self):
return self.title
class Manager(TimestampedModel):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
models.CASCADE,
verbose_name='usuário',
)
file = models.CharField(
max_length=1000,
db_column='assinatura',
verbose_name='assinatura do gestor',
)
position = models.ForeignKey(
Position,
models.PROTECT,
db_column='cargo',
verbose_name='cargo',
)
class Meta:
db_table = 'declaracoes_gestor'
verbose_name = 'Gestores'
verbose_name_plural = 'Gestores'
def __str__(self):
return self.user
class TemplateManager(TimestampedModel):
manager = models.ForeignKey(
Manager,
on_delete=models.PROTECT,
db_column='gestor_id',
)
template = models.ForeignKey(
Template,
on_delete=models.CASCADE,
db_column='template_id',
)
This my view
class TemplateManagerView(APIView):
pagination_class = BasePagination
def get(self, request, id):
template = get_object_or_404(models.Template.objects.all(), id=id)
managers = (models.TemplateManager.objects
.filter(template=template)
.all())
serializer = serializers.ManagerSerializer(managers, many=True)
return Response(serializer.data)
and my serializers
class ManagerSerializer(serializers.ModelSerializer):
position = PositionSerializer()
user = serializers.CharField(source='user.first_name')
class Meta:
model = models.Manager
fields = ['id', 'user', 'file', 'position']
class ManagerTemplateSerializer(serializers.ModelSerializer):
manager = ManagerSerializer(many=True)
template = TemplateSerializer(many=True)
class Meta:
fields = ['manager', 'template']
model = models.Template
my url something like /id/managers
First, you don't need to pass a query to get_object_or_404. This will work just fine:
get_object_or_404(models.Template, id=id)
Also, you are passing the wrong queryset:
managers = (models.TemplateManager.objects
.filter(template=template)
.all())
This can be changed to this:
models.TemplateManager.objects
.filter(template=template)
Which is a queryset from TemplateManager model while you're using the serializer for
ManagerSerializer serializer for Manager model.
Now, to fix this:
1 - change model in ManagerTemplateSerializer to TemplateManager instead of Template.
2 - change serializer = serializers.ManagerSerializer(managers, many=True) to serializer = serializers.ManagerTemplateSerializer(managers, many=True)
I have the following models
class Film(models.Model):
crew = models.ManyToManyField('Person', through='Role', blank=True)
class Role(models.Model):
person = models.ForeignKey('Person')
film = models.ForeignKey('Film')
person_role = models.ForeignKey(RoleType)
credit = models.CharField(max_length=200)
credited_as = models.CharField(max_length=100)
class RoleType(models.Model):
"""Actor, director, makeup artist..."""
name = models.CharField(max_length=50)
class Person(models.Model):
slug = models.SlugField(max_length=30, unique=True, null=True)
full_name = models.CharField(max_length=255)
A Film("Star Wars: The Clone Wars") has several Person("Christopher Lee"), each one of them can have one or more Role("Voice of Count Dooku") and every Role has a RoleType("Voice actor").
I'm using a DetailView to display the Film
class FilmDetail(DetailView):
model = Film
In my template i'm showing all the Persons, so each time I show a Film 609 queries are being executed. To reduce this I want to use prefetch_related so I changed the view to:
class FilmDetail(DetailView):
model = Film
def get_queryset(self):
return super(FilmDetail, self).get_queryset().prefetch_related('crew')
But this didn't reduce the number of queries(610), I tried the following parameters to prefetch related and it didn't work:
def get_queryset(self):
return super(FilmDetail, self).get_queryset().prefetch_related('crew__person_role')
I got an Cannot find 'person_role' on Person object, 'crew__person_role' is an invalid parameter to prefetch_related()error
What can I do to prefetch the Person.full_name and slug and all Role fields from Film.crew?
You can construct your queryset like this:
from django.db.models import Prefetch
def get_queryset(self):
return super(FilmDetail, self).get_queryset().prefetch_related(
Prefetch(
'crew',
queryset=Role.objects.select_related(
'person',
'person_role',
),
),
)
Only Film->Role is a backwards relation loadable with prefetch_related. Role->RoleType and Role->Person are forwards relations that you load with select_related.
i have these models:
#model.py
class Subject(models.Model):
name = models.CharField("Name",max_length=50, blank=True)
...
...
class Activity(models.Model):
label = models.CharField("Act. name",max_length=150)
price = models.DecimalField("price", max_digits=10, decimal_places=2,default=0)
count = models.IntegerField("Count", default=0)
def __unicode__(self):
return u"%s" % (self.label)
class Meta:
verbose_name_plural = "Activities"
class Invoice(models.Model):
subject = models.ForeignKey(Subject)
date = models.DateField(default=date.today())
activities = models.ManyToManyField(Activity)
....
....
while creating a new Invoice instance on admin, i can select the many to many fields 'activities', but i'd like to have an additional counter (eg. an IntegerField) as an Invoice field to count and save the quantity of each activity added to my Invoice instance. Is this possible?
thanks,
Luke
You could have a field on the model and override the save method
class Invoice(models.Model):
subject = models.ForeignKey(Subject)
date = models.DateField(default=date.today())
activities = models.ManyToManyField(Activity)
activity_count = models.PositiveIntegerField(default=0)
def save(self):
self.activity_count = self.activities.count()
super(Invoice, self).save()