Django Rest join models on multiple fields - django

I have two models as below.
These models store budget sales data and actual sales data for each project by each month.
# To test join on multiple keys
class ActualSales(models.Model):
time_id = models.CharField(max_length=8)
project = models.CharField(max_length=100)
actual_sales = models.DecimalField(max_digits=20, decimal_places=3)
adjustment = models.DecimalField(max_digits=20, decimal_places=3)
class BudgetSales(models.Model):
time_id = models.CharField(max_length=8)
project = models.CharField(max_length=100)
budget_sales = models.DecimalField(max_digits=20, decimal_places=3)
And the data will somewhat looks like this.
Model A
| time_id | project | sales | adjustment |
+---------+-----------+-------+------------+
| 2019JAN | Project A | 1000 | 10 |
| 2019JAN | Project B | 2500 | 5 |
| 2019FEB | Project A | 1100 | 0 |
| 2019FEB | Project B | 2400 | -10 |
+---------+-----------+-------+------------+
Model B
| time_id | project | budget |
+---------+-----------+--------+
| 2019JAN | Project A | 1100 |
| 2019JAN | Project B | 2400 |
| 2019FEB | Project A | 1000 |
| 2019FEB | Project B | 2500 |
+---------+-----------+--------+
And I'm looking to produce an array of objects with each object represent each project's result each month, similarly to the way we join 2 tables with sql. However, I'm unsure how to write the serialiser and API Viewset for this.
[
{
time_id: "2019JAN",
project: "Project A",
sales: "1000",
adjustment: "10",
budget: "1100"
},
{
time_id: "2019JAN",
project: "Project B",
sales: "2500",
adjustment: "5",
budget: "2400"
},
{
time_id: "2019FEB",
project: "Project A",
sales: "1100",
adjustment: "0",
budget: "1000"
},
{
time_id: "2019FEB",
project: "Project B",
sales: "2400",
adjustment: "-10",
budget: "2500"
}
]

You can try this
Models.py
class ActualSales(models.Model):
time_id = models.CharField(max_length=8)
project = models.CharField(max_length=100)
actual_sales = models.DecimalField(max_digits=20, decimal_places=3)
adjustment = models.DecimalField(max_digits=20, decimal_places=3)
def get_budget(self):
bugdesale = BudgetSales.objects.filter(time_id=self.time_id)
if bugdesale.exists():
return bugdesale.first().budget_sales
else:
return None
Serializers.py
class ActualSalesSerializer(serializers.ModelSerializer):
class Meta:
model = ActualSales
fields = ('time_id','project', 'actual_sales', 'adjustment', 'get_budget')

Related

Django - Annotate field

I have 3 models:
1.
class Calendar(models.Model):
...
supplier = models.CharField(...)
subassort = models.CharField(..., null=True)
Data example:
supplier | subassort
----------------------
12345 | subassort1
67890 | subassort2
class SupplierProductAssortments(models.Model):
subassort = models.CharField(...)
supplier = models.CharField(...)
ui2_code = models.CharField(...)
Data example:
supplier | subassort | ui2_code
---------------------------------
12345 | subassort1 | ui-1
12345 | subassort1 | ui-2
67890 | subassort2 | ui-3
class UI2(models.Model):
code = models.CharField(...)
name = models.CharField(...)
Data example:
code | name
-------------
ui-1 | milk
ui-2 | cheese
ui-3 | meat
I need to annotate ui2 field to queryset of Calendar. For better understanding below I wrote a function that demonstrates it:
def get_calendars_with_ui2s():
calendars = Calendar.objects.all() # need to annotate ui2 names
for calendar in calendars:
if subassort := calendar.subassort:
ui2_codes = SupplierProductAssortments.objects\
.filter(supplier=calendar.supplier, subassort=subassort)\
.values_list('ui2_code', flat=True)
ui2 = UI2.objects.filter(code__in=ui2_codes).values_list('name', flat=True)
else:
ui2 = []
calendar.ui2 = ui2
return calendars
Expected output:
supplier | subassort | ui2
---------------------------------------
12345 | subassort1 | [milk, cheese]
67890 | subassort2 | [meat]
If when filtering ui2_codes was by one field I guess it could be solved by OuterRef. But there are filtering by two fields.
How can I annotate field ui2?
P.S. No FK

django query datetime filed issue

i have tried to apply filter datetime filed in django query,but i got result zero
class Customers(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30, null=True)
customer_code = models.CharField(max_length=30)
reference = models.CharField(max_length=30, null=True)
phone_office = models.CharField(max_length=250, null=True)
phone_residential = models.CharField(max_length=250, null=True)
contact_person_first_name = models.CharField(max_length=30)
mobile = models.BigIntegerField()
email = models.EmailField(null=True)
fax = models.CharField(max_length=15, null=True)
cr_limit = models.DecimalField(max_digits=10, decimal_places=2, null=True)
gstin = models.CharField(max_length=10, null=True)
state_code = models.CharField(max_length=10, null=True)
country = models.CharField(max_length=250, null=True)
opening_balance = models.DecimalField(max_digits=10, decimal_places=2, null=True)
opening_balance_date = models.DateTimeField(null=True)
payments_terms = models.ForeignKey(PaymentTerms, related_name='customer_terms', null=True, blank=True)
address_flag = models.BooleanField(default=False)
created_by = models.ForeignKey(SAUser, related_name='+')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
the below code i have tried:
Customers.objects.filter(created_at__month=1).count()
but i have look at the query also
Customers.objects.filter(created_at__month=1).query
it seems like that
SELECT `customer_customers`.`id`, `customer_customers`.`first_name`, `customer_customers`.`last_name`, `customer_customers`.`customer_code`, `customer_customers`.`reference`, `customer_customers`.`phone_office`, `customer_customers`.`phone_residential`, `customer_customers`.`contact_person_first_name`, `customer_customers`.`mobile`, `customer_customers`.`email`, `customer_customers`.`fax`, `customer_customers`.`cr_limit`, `customer_customers`.`gstin`, `customer_customers`.`state_code`, `customer_customers`.`country`, `customer_customers`.`opening_balance`, `customer_customers`.`opening_balance_date`, `customer_customers`.`payments_terms_id`, `customer_customers`.`address_flag`, `customer_customers`.`created_by_id`, `customer_customers`.`created_at`, `customer_customers`.`updated_at` FROM `customer_customers` WHERE EXTRACT(MONTH FROM CONVERT_TZ(`customer_customers`.`created_at`, 'UTC', IST)) = 1
The manual query in mysql
select id,created_at from customer_customers;
+----+----------------------------+
| id | created_at |
+----+----------------------------+
| 1 | 2017-12-24 06:54:41.264756 |
| 2 | 2017-12-24 07:05:37.317395 |
| 3 | 2017-12-24 10:05:29.957158 |
| 4 | 2017-12-29 13:30:21.572926 |
| 5 | 2017-12-29 13:58:59.137774 |
| 6 | 2017-12-31 08:46:13.239080 |
| 7 | 2017-12-31 09:04:34.695830 |
| 8 | 2017-12-31 12:27:05.253016 |
| 9 | 2018-01-27 12:28:16.809840 |
| 10 | 2018-02-14 07:27:18.847884 |
| 11 | 2018-02-14 10:45:33.323448
Expected result should be 2
"When USE_TZ is True, datetime fields are converted to the current
time zone before filtering. This requires time zone definitions in the
database."
Add this to your settings file.
USE_TZ = False

How to filter in many to many relation

I want to get all Post which are realated whith tags:
#models.py
class Post(models.Model):
tags = models.ManyToManyField('blogUserPlane.Tag')
title = models.CharField(max_length=200)
class Tag(models.Model):
name = models.CharField(max_length=200)
#views.py
def get_list_of_posts_by_tag_order_by_date(request):
# this works
list_of_posts = Post.objects.all().filter(tags__in=[1, 2])
# I want to use tags as name, not as id. Samething like this
# list_of_posts = Post.objects.all().filter(tags__in=["Tag1", "Tag2"])
html = ["title=%s<br> tags=%s<br>" % (p.title, p.tags.__dict__) for p in
list_of_posts]
return HttpResponse(html)
The second problem is that filter return wrong result:
Post:
| id | title |
| 1 | post1 |
| 2 | post2 |
tags:
| id | post_id | tag_id |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
Tag:
| id | name |
| 1 | Tag1 |
| 2 | Tag2 |
list_of_posts = Post.objects.all().filter(tags__in=[1,2]) returns:
post1, post1, post2, but should return post1, post2

Django queryset for many-to-many field with intermediate table

Here's my setup
Models
class League(models.Model):
league_name = models.CharField(max_length=60)
class Team(models.Model):
league = models.ForeignKey('League')
team_name = models.CharField(max_length=60)
class Game(models.Model):
league = models.ForeignKey('League')
teams = models.ManyToManyField(Team, through="GameTeams")
game_heading = models.CharField(max_length=40, null=True, blank=True)
class GameTeams(models.Model):
game = models.ForeignKey(Game)
team = models.ForeignKey(Team, null=True, blank=True)
How do I get all the (game, team) pairs associated with a particular league? This is what I tried:
league = League.objects.get(pk=1) #This obviously works
league.game_set.gameteams_set.all() #This doesn't work
The resultant set should be something something along these lines:
league_id | game_id | team_id
1 | 1 | 1
1 | 1 | 2
1 | 1 | 3
1 | 2 | 2
1 | 2 | NULL
you can do it like:
league = League.objects.get(pk=1)
gameteams = GameTeams.objects.filter(game__league=league, team__league=league)

Django : Get specific columns from multiple tables

I need to fetch columns from multiple tables, how do I achieve this?
UserLog
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| log_id | int(11) | NO | PRI | NULL | auto_increment |
| time | datetime | NO | | NULL | |
| ip_address | char(15) | YES | | NULL | |
| event_id | int(11) | NO | MUL | NULL | |
| user_id | int(11) | NO | MUL | NULL | |
+------------+----------+------+-----+---------+----------------+
Events
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| event_id | int(11) | NO | PRI | NULL | auto_increment |
| description | varchar(200) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
This is my models.py
class Events(models.Model):
event_id = models.AutoField(primary_key=True,verbose_name="Event id")
description = models.CharField(max_length=200,verbose_name="Description")
def __unicode__(self):
return u"%d : %s" % (self.event_id, self.description)
class UserLog(models.Model):
log_id = models.AutoField(primary_key = True)
user = models.ForeignKey(User)
event = models.ForeignKey(Events,verbose_name = "event")
time = models.DateTimeField(default=datetime.now,blank=True)
ip_address = models.IPAddressField(null=True)
def __unicode__(self):
return u"%s (%s): %s" % (self.log_id, self.user, self.event)
Spcifically I want to do
SELECT log_id,time,user_id,event_id,description from UserLog,Events where UserLog.event_id = Events.event_id
I tried UserLog.objects.filter(event_id__event_id).values('log_id','time','user_id','event_id','description') . But it says no such fields.
Is there something I need to change in my models class?
Try this:
UserLog.objects.filter(event_id=1).values('log_id',
'time',
'user_id',
'event_id',
'event__description')
Alternately, you could use select_related:
UserLog.objects.filter(event__id=1).select_related('event')
then you'll get UserLog objects, with the event pre-fetched, so you can access the event without triggering another query.
(Also, standard naming convention would be to call the model Event, not Events)
use select_related() like this:
UserLog.objects.filter(event_id__event_id=1).select_related('event').values('log_id','time','user_id','event_id', 'event__description')
dataStudent = Studentinfo.objects.select_related().values(
'country__countryname',
'state__statename',
'city__cityname',
'id','studentname',
'rollno',
'email',
'phoneno')
in the country__countryname country is the name of field when u define the relationship like follow
city = models.ForeignKey(City, on_delete=models.CASCADE)
state = models.ForeignKey(State, on_delete=models.CASCADE)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
and countryname is the table field inside the country table and
same as state__statename and city__cityname
and other fields are from Studentinfo model
so that will give me the following result