Django restframework SerializerMethodField background work - sql

I am writing a project in Django with rest framework by using SerializerMethodField. This method makes queries for every row to get data, or View collects all queries and send it to DB? Django can make it as one joint query?
class SubjectSerializer(serializers.ModelSerializer):
edu_plan = serializers.SerializerMethodField(read_only=True)
academic_year_semestr = serializers.SerializerMethodField(read_only=True)
edu_form = serializers.SerializerMethodField(read_only=True)
def get_edu_plan(self, cse):
return cse.curriculum_subject.curriculum.edu_plan.name
def get_academic_year_semestr(self, cse):
semester = cse.curriculum_subject.curriculum.semester
return {'academic_year': semester.academic_year, 'semester': semester}
def get_edu_form(self, cse):
return cse.curriculum_subject.curriculum.edu_form.name
class Meta:
model = CurriculumSubjectEmployee
fields = [
'id',
'name',
'edu_plan',
'academic_year_semestr',
'edu_form'
]
class SubjectViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = SubjectSerializer
def get_queryset(self):
contract = self.request.user.employee.contract
if contract is None:
raise NotFound(detail="Contract not found", code=404)
department = contract.department
cses = CurriculumSubjectEmployee\
.objects\
.filter(curriculum_subject__department=department)
return cses

Related

Django Nested Annotate

I have 3 models
class QuestionsModel(models.Model):
created = models.DateTimeField(auto_now_add=True)
Question = models.CharField(max_length=200)
class AnswersModel(models.Model):
Question = models.ForeignKey(QuestionsModel, related_name='QuestionAnswer')
Answer = models.CharField(max_length=200)
class UsersAnswerModel(models.Model):
Answer = models.ForeignKey(AnswersModel, related_name='UsersAnswer')
RegistrationID = models.CharField(max_length=200)
I am trying to Count How many UsersAnswer the Question
what I tried :
class DashboardAdmin(admin.ModelAdmin):
class Meta:
model = QuestionsModel
change_list_template = 'admin/Dashboard_change_list.html'
date_hierarchy = 'created'
def has_add_permission(self, request):
return False
def changelist_view(self, request, extra_context=None):
response = super().changelist_view(
request,
extra_context=extra_context,
)
try:
qs = response.context_data['cl'].queryset
except (AttributeError, KeyError):
return response
metrics = {
'totalAnswers' : models.Count('QuestionAnswer'),
'totalUsersAnswer' : models.Count(UsersAnswer=OuterRef('QuestionAnswer'))
}
response.context_data['summary'] = list(
qs
.values('Question')
.annotate(**metrics)
.order_by('-totalUsersAnswer')
)
return response
admin.site.register(DashboardModel, DashboardAdmin)
I could not solve
'totalUsersAnswer' : models.Count(UsersAnswer=OuterRef('QuestionAnswer'))
how to count nested foreign key
any help please
class AnswersModel(models.Model):
Question = models.ForeignKey(QuestionsModel, related_name='QuestionAnswer')
Answer = models.CharField(max_length=200)
class UsersAnswerModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT)
Answer = models.ForeignKey(AnswersModel, related_name='UsersAnswer')
RegistrationID = models.CharField(max_length=200)
Q- How many users answer a Question?
e.g
user_answer = UsersAnswerModel.objects.filter(Answer__question__id=2).count()
You can now annotate based on your need.
Your models need to be renamed
AnswersModel to simply Answer
UsersAnswerModel to UserAnswer and there should be a user entity as a field as I have done above.
3.Fieldnames in model is better lowercased.
I have Solve it by add QuestionAnswer__UsersAnswer
metrics = {
'totalAnswers' : models.Count('QuestionAnswer', distinct=True),
'totalUsersAnswer' : models.Count('QuestionAnswer__UsersAnswer'),
}

How to check if a record already exists or not in database in DRF?

I am working on DRF. I am creating an API of POST request that overriding its features. I want to add one functionality if a particular field value already exists in DB then, user cannot create post request and instead of it getting a message that he couldn't do it.
views.py
class PizzaOrderViewSet(viewsets.ModelViewSet):
http_method_names = ['get', 'put', 'patch', 'post']
def create(self, request, *args, **kwargs):
data = request.data
order = PizzaOrder.objects.create(
name=data['name'], flavours=data['flavours'],
number=data['number'], size=data['size'],
customer_name=data['customer_name'],
customer_address=data['customer_address']
)
order.save()
serializer = PizzaOrderSerializer(order)
return Response(serializer.data)
serializers.py
class PizzaOrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
validators = [
UniqueTogetherValidator(
queryset=PizzaOrder.objects.all(),
fields=['name', 'flavours', 'size', 'customer_name', 'customer_address'],
message='This field should be unique'
)
]
models.py
from django.db import models
from datetime import datetime
FLAVOURS_CHOICE = (
('Margarita', 'Margarita'),
('Marinara', 'Marinara'),
('Salami', 'Salami'),
)
SIZE_CHOICE = (
('Small', 'Small'),
('Medium', 'Medium'),
('Large', 'Large'),
)
STATUS_CHOICE = (
('Open', 'Open'),
('Accepted', 'Accepted'),
('Preparing', 'Preparing'),
('OnWay', 'OnWay'),
('Delivered', 'Delivered'),
)
class PizzaOrder(models.Model):
name = models.CharField(max_length=50, blank=False)
flavours = models.CharField(max_length=20, choices=FLAVOURS_CHOICE)
quantity = models.IntegerField()
size = models.CharField(max_length=10, choices=SIZE_CHOICE)
customer_name = models.CharField(max_length=30, blank=False)
customer_address = models.TextField(blank=False)
ordered_time = models.DateTimeField(default=datetime.now, editable=False)
status = models.CharField(max_length=20, choices=STATUS_CHOICE, default='Open')
def __str__(self):
return self.name
class Meta:
ordering = ['-ordered_time']
unique_together = ('name', 'flavours', 'quantity', 'size')
How could I achieve this?

SQL Query logic to Django ORM Query logic

I have tried to think about how the following SQL query would be structured as a Django ORM query but I have had no luck in my multiple attempts. Can anyone help?
SELECT targets_genetarget.gene, count(targets_targetprediction.gene) as total
FROM targets_genetarget
LEFT OUTER JOIN targets_targetprediction on targets_targetprediction.gene =
targets_genetarget.gene
WHERE list_name LIKE %s
GROUP BY targets_genetarget.gene
class GeneTarget(models.Model):
list_name = models.CharField(max_length=100)
gene = models.CharField(max_length=50)
date_added = models.DateField(auto_now=True)
class Meta:
unique_together = (('list_name', 'gene'),)
def __str__(self):
return self.list_name
class TargetPrediction(models.Model):
specimen_id = models.CharField(max_length=100)
patient_peptide = models.ForeignKey(Peptide, on_delete=models.CASCADE, verbose_name="Peptide", related_name="predictions")
allele = models.ForeignKey(Allele, on_delete=models.CASCADE, verbose_name="Allele", related_name="predictions")
gene = models.CharField(max_length=50)
class Meta:
unique_together = (('specimen_id', 'patient_peptide', 'allele', 'gene'),)
def get_absolute_url(self):
return f'/samples/specid-{self.specimen_id}'
def __str__(self):
return (f'Specimen: {self.specimen_id} Peptide: {self.patient_peptide} Allele: {self.allele} Gene: {self.gene} ')
There's nothing stopping you declaring the TargetPrediction.gene field as a foreign key using the to_field attribute, so you wouldn't need to change the data at all:
class TargetPrediction(models.Model):
...
gene = models.ForeignKey("GeneTarget", to_field="gene")
Now your query simply becomes:
GeneTarget.objects.filter(list_name="whatever").values("gene").annotate(total=Count("targetprediction"))

Grails query to filter on association and only return matching entities

I have the following 1 - M (one way) relationship:
Customer (1) -> (M) Address
I am trying to filter the addresses for a specific customer that contain certain text e.g.
def results = Customer.withCriteria {
eq "id", 995L
addresses {
ilike 'description', '%text%'
}
}
The problem is that this returns the Customer and when I in turn access the "addresses" it gives me the full list of addresses rather than the filtered list of addresses.
It's not possible for me to use Address.withCriteria as I can't access the association table from the criteria query.
I'm hoping to avoid reverting to a raw SQL query as this would mean not being able to use a lot functionality that's in place to build up criteria queries in a flexible and reusable manner.
Would love to hear any thoughts ...
I believe the reason for the different behavior in 2.1 is documented here
Specifically this point:
The previous default of LEFT JOIN for criteria queries across associations is now INNER JOIN.
IIRC, Hibernate doesn't eagerly load associations when you use an inner join.
Looks like you can use createAlias to specify an outer join example here:
My experience with this particular issue is from experience with NHibernate, so I can't really shed more light on getting it working correctly than that. I'll happily delete this answer if it turns out to be incorrect.
Try this:
def results = Customer.createCriteria().listDistinct() {
eq('id', 995L)
addresses {
ilike('description', '%Z%')
}
}
This gives you the Customer object that has the correct id and any matching addresses, and only those addresses than match.
You could also use this query (slightly modified) to get all customers that have a matching address:
def results = Customer.createCriteria().listDistinct() {
addresses {
ilike('description', '%Z%')
}
}
results.each {c->
println "Customer " + c.name
c.addresses.each {address->
println "Address " + address.description
}
}
EDIT
Here are the domain classes and the way I added the addresses:
class Customer {
String name
static hasMany = [addresses: PostalAddress]
static constraints = {
}
}
class PostalAddress {
String description
static belongsTo = [customer: Customer]
static constraints = {
}
}
//added via Bootstrap for testing
def init = { servletContext ->
def custA = new Customer(name: 'A').save(failOnError: true)
def custB = new Customer(name: 'B').save(failOnError: true)
def custC = new Customer(name: 'C').save(failOnError: true)
def add1 = new PostalAddress(description: 'Z1', customer: custA).save(failOnError: true)
def add2 = new PostalAddress(description: 'Z2', customer: custA).save(failOnError: true)
def add3 = new PostalAddress(description: 'Z3', customer: custA).save(failOnError: true)
def add4 = new PostalAddress(description: 'W4', customer: custA).save(failOnError: true)
def add5 = new PostalAddress(description: 'W5', customer: custA).save(failOnError: true)
def add6 = new PostalAddress(description: 'W6', customer: custA).save(failOnError: true)
}
When I run this I get the following output:
Customer A
Address Z3
Address Z1
Address Z2

Django ORM equivalent

I have the following code in a view to get some of the information on the account to display. I tried for hours to get this to work via ORM but couldn't make it work. I ended up doing it in raw SQL but what I want isn't very complex. I'm certain it's possible to do with ORM.
In the end, I just want to populate the dictionary accountDetails from a couple of tables.
cursor.execute("SELECT a.hostname, a.distro, b.location FROM xenpanel_subscription a, xenpanel_hardwarenode b WHERE a.node_id = b.id AND customer_id = %s", [request.user.id])
accountDetails = {
'username': request.user.username,
'hostname': [],
'distro': [],
'location': [],
}
for row in cursor.fetchall():
accountDetails['hostname'].append(row[0])
accountDetails['distro'].append(row[1])
accountDetails['location'].append(row[2])
return render_to_response('account.html', accountDetails, context_instance=RequestContext(request))
It would be easier if you post models. But from SQL I'm assuming the models are like this:
class XenPanelSubscription(models.Model):
hostname = models.CharField()
distro = models.CharField()
node = models.ForeignKey(XenPanelHardwareNode)
customer_id = models.IntegerField()
class Meta:
db_table = u'xenpanel_subscription'
class XenPanelHardwareNode(models.Model):
location = models.CharField()
class Meta:
db_table = u'xenpanel_hardwarenode'
Based on these models:
accountDetails = XenPanelSubscription.objects.filter(customer_id = request.user.id)
for accountDetail in accountDetails:
print accountDetail.hostname, accountDetail.distro, accountDetail.node.location