I am trying to update three models in django with a task function and link them together using a foreign key. Event, Market & Runner
I would like to be able to query the data in my views and display the data.
A single event has multiple markets and in each market there's multiple runners.
I'm getting an error when I try to use foreign keys to link the three models together.
django.db.utils.ProgrammingError: relation "apimb_event" does not exist
STATEMENT: SELECT "apimb_event"."event_id", "apimb_event"."event_name", "apimb_event"."start_time", "apimb_event"."status" FROM "apimb_event" ORDER BY "apimb_event"."event_id" DESC LIMIT 21
Update:
After nuking the db and starting over I have a similar error.
apimb.models.DoesNotExist: Market matching query does not exist.
psycopg2.errors.NotNullViolation: null value in column "event_id"
violates not-null constraint DETAIL: Failing row contains
(1271204194200017, null, null, null, null).
I don't think I'm using foreign key's correctly. Each model has a id as a primary key.
I can update and create this data fine without using foreign keys but,
How can I update the model and then query the data to show as below?
Event Market Runner
event_name_1 market_name_1 runner_name_1
runner_name_2
runner_name_3
event_name_1 market_name_2 runner_name_1
runner_name_2
runner_name_3
runner_name_4
task_function
#shared_task(bind=True)
def get_events(self):
api = get_client()
events = api.market_data.get_events(sport_ids=[9],states=MarketStates.All,
per_page=200, offset=0,
include_event_participants=Boolean.T,
category_ids=None, price_depth=3,
side=Side.All, session=None)
for event in events:
event_name = event["name"]
event_id = event['id']
start_time = event['start']
status = event["status"]
ev, created = Event.objects.update_or_create(event_id=event_id)
ev.event_name = event_name
ev.start_time = start_time
ev.status = status
ev.save()
markets = event["markets"]
for market in markets:
event_id = market['event-id']
market_id = market['id']
market_name = market['name']
status = market['status']
volume = market['volume']
ma, created = Market.objects.update_or_create(market_id=market_id)
ma.market_name = market_name
ma.status = status
ma.volume = volume
ma.save()
runners = market["runners"]
for runner in runners:
runner_name = runner['name']
runner_id = runner['id']
event_id = runner['event-id']
runner, created = Runner.objects.update_or_create(runner_id=runner_id)
runner.event_id = event_id
runner.runner_name = runner_name
runner.save()
models.py
class Event(models.Model):
event_id = models.BigIntegerField(primary_key=True)
event_name = models.CharField(max_length=200, null=True)
start_time = models.DateTimeField(null=True)
status = models.CharField(null=True, max_length=13)
class Market(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
market_id = models.BigIntegerField(primary_key=True)
market_name = models.CharField(null=True, max_length=35)
status = models.CharField(null=True, max_length=10)
volume = models.FloatField(null=True, max_length=15)
class Runner(models.Model):
market = models.ForeignKey(Market, null=True, on_delete=models.SET_NULL)
runner_id = models.BigIntegerField(primary_key=True)
event_id = models.BigIntegerField(null=True)
runner_name = models.CharField(max_length=100)
Related
It'd be really nice if someone could help me with this. I've stuck here. I'm able to do this manually but how to do according to user input.
Payment.objects.filter(created_by=42, mode='cash', created_at__range=["2021-11-01", "2021-11-04"]).aggregate(Sum('amount'))
Here created_by and date_range I'm sending in url like this : http://127.0.0.1:8000/api/v1/registration/?created_by=42&start_date=2021-06-06&end_date=2021-11-18 so the id created by and date_range will always change. And according to change the sum will return.
My Model :
class Payment(TimestampedModel):
customer_visit = models.ForeignKey(
CustomerVisit, on_delete=models.CASCADE, null=True, related_name="customer_payments"
)
mode = models.CharField(choices=PAYMENTCHOICES, max_length=25)
amount = models.FloatField()
ref_no = models.TextField(null=True)
bank = models.ForeignKey(
"BankDetails", on_delete=models.CASCADE, null=True, related_name="payment_bank"
)
is_settlement = models.BooleanField(default=False)
created_by = models.ForeignKey("Employee", on_delete=models.DO_NOTHING, null=True,related_name='payment_created_by')
updated_by = models.ForeignKey("Employee", on_delete=models.DO_NOTHING, null=True,related_name='payment_updated_by')
My View :
class UserWiseCollectionView(ListAPIView):
permission_classes = [
IsAuthenticated,
]
pagination_class = CustomPagination
model = CustomerVisit
serializer_class = UserWiseCollectionSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['created_by']
def get_queryset(self):
start_date = self.request.query_params.get("start_date")
end_date = self.request.query_params.get("end_date")
emp_id = self.request.query_params.get("emp_id")
items = self.model.objects.all()
if start_date and end_date:
items = items.filter(
created_at__range=[start_date, end_date]
)
if emp_id is not None:
items = items.filter(phelebotomist_id = emp_id)
return items
If requirement is to get all the rows created by specific employee within the specific date range, below code might work.
Requirement
Payment.objects.filter(created_by=42, mode='cash', created_at__range=["2021-11-01", "2021-11-04"]).aggregate(Sum('amount'))
View code
def get_queryset(self):
start_date = self.request.query_params.get("start_date")
end_date = self.request.query_params.get("end_date")
emp_id = self.request.query_params.get("emp_id")
employee = Employee.objects.get(pk=emp_id)
payment_by_employee = employee.payment_created_by.all()
if start_date and end_date:
payment_by_employee = payment_by_employee.filter(
created_at__range=[start_date, end_date], mode='cash'
)
payment_by_employee.aggregate(Sum('amount'))
return payment_by_employee
If you want all the records related to specific employee within specific range in CustomerVisit table, you can make use of the related name that is provided to the field(foreign_key) pointing to an employee in customerVisit Table.
For example, if CustomerVisit model has "phelebotomist_id" foreign key that points to Employee Model, you can get all customerVisit records related to Employee Model by below queries
CustomerVisit(models.Model):
phelebotomist_id = models.ForeignKey(Employee, related_name="employee_customer_visit")
emp = Employee.objects.get(pk=<emp_id>)
customer_visits_related_to_emp = emp.employee_customer_visit.all()
You can filter out further depending on the date range and any other fields.
I'm having difficulty updating these three models which are linked with Foreign keys
Reason they are linked with foreign keys is Events can have multiple Markets and Markets can have multiple Runners.
I'm at my wits end with this not null error. Even If I have a field that causes the issue and I remove the field from my model. Make migrations, migrate and remove the save from my task I still get the exact same error. What is the purpose of this not null argument? Even If I have null=True or null=False on brand new models I still get the error. Not null constraint failed
django.db.utils.IntegrityError: NOT NULL constraint failed: testapp_ma.event_id
I've no idea why this is failing.
Do I need to make sure all fields have a null argument? According to django documentation default is false. For each object my task runs all fields have data. So default of false should be fine.
Could this be due to the manner I'm updating the models with my task?
full stacktrace here https://gist.github.com/Cally99/08fed46ba8039fa65d00f53e8a31b37a
class Event(models.Model):
sport_name = models.CharField(max_length=15)
event_id = models.BigIntegerField(unique=True, null=False)
event_name = models.CharField(max_length=200)
start_time = models.DateTimeField()
status = models.CharField(max_length=13)
class Market(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
market_id = models.BigIntegerField(unique=True)
market_name = models.CharField(max_length=35)
status = models.CharField(max_length=10)
volume = models.FloatField(null=True)
class Runner(models.Model):
market = models.ForeignKey(Market, null=True, default=None, on_delete=models.SET_NULL)
runner_id = models.BigIntegerField(unique=True)
event_id = models.BigIntegerField(null=True, default=0)
name = models.CharField(max_length=100)
tasks.py
#shared_task(bind=True)
def get_events(self):
api = get_client()
events = api.market_data.get_events(sport_ids=[9],states=MarketStates.All,
per_page=200, offset=0,
include_event_participants=Boolean.T,
category_ids=None, price_depth=3,
side=Side.All, session=None)
for event in events:
event_name = event["name"]
event_id = event['id']
start_time = event['start']
status = event["status"]
ev, created = Ev.objects.update_or_create(event_id=event_id)
ev.event_name = event_name
ev.start_time = start_time
ev.status = status
ev.save()
markets = event["markets"]
for market in markets:
event_id = market['event-id']
market_id = market['id']
market_name = market['name']
status = market['status']
volume = market['volume']
ma, created = Ma.objects.update_or_create(market_id=market_id)
ma.market_name = market_name
ma.status = status
ma.volume = volume
ma.save()
runners = market["runners"]
for runner in runners:
name = runner['name']
runner_id = runner['id']
event_id = runner['event-id']
runner, created = Ru.objects.update_or_create(runner_id=runner_id)
runner.event_id = event_id
runner.name = name
runner.save()
With the line
Ma.objects.update_or_create(market_id=market_id)
you haven't set the Event for your market object. And given how
event = models.ForeignKey(Event, on_delete=models.CASCADE)
doesn't have null=True, it won't accept any null values.
Models:
class CompanyList(models.Model):
company_id = models.CharField(max_length=10, unique=True)
company_name = models.CharField(max_length=100, unique=True)
class Reporting(models.Model):
company = models.ForeignKey(CompanyList, on_delete=models.CASCADE)
year_end = models.DateField()
class CompanyAccountsExtracts(models.Model):
reporting = models.ForeignKey(Reporting, on_delete=models.CASCADE)
data_type = models.CharField(max_length=30)
source = models.CharField(max_length=30)
value = models.CharField(max_length=30)
Now I have a pandas dataframe (company_accounts_extracts_upload) of data to write to CompanyAccountsExtracts. I am using the following code to do so:
for i, row in enumerate(company_accounts_extracts_upload.values):
single_row = company_accounts_extracts_upload.iloc[i].to_dict()
report = models.Reporting.objects.get(company=single_row['Company ID Number'], year_end=single_row['Year End'])
DataExtract = models.CompanyAccountsExtracts(reporting=report,
data_type=single_row['DataType'],
source=single_row['Source'],
value=single_row['Value'],
)
DataExtract.save()
I am getting the following error on the "report = models.Reporting..." line:
DoesNotExist: Reporting matching query does not exist.
However, I'm 100% sure the company and year end does exist as I can see it in the admin view.
I think the error might be related to how I am posting to a foreign key as the Reporting foreign key which again is a foreign key from CompanyList?
You need to update your company query param from:
company=['Company ID Number']
to:
company__company_id=['Company ID Number']
You are getting the error because the company param will need a Company instance and you are only using the company_id field.
I have the following Django model
class TestModel(models.Model):
company_name = models.CharField(max_length=100)
nick_name = models.CharField(max_length=100)
created_at = models.DateTimeField()
Now I want to create a query/multiple queries which will group all the TestModel objects to the particular company_name. In a nutshell it will have the following structure.
out - {
"company_name_test_1": [TestModel1, TestModel2, TestModel3],
"company_name_test_2": [TestModel4, TestModel5, TestModel6],
}
companyNames = ["a", "b", "c"]
result = {}
for name in companyNames:
result[name] = list(TestModel.objects.filter(company_name = name))
If you want to save the dictionary as JSON or something similar, the filtered models will need to be serialised first.
Also, depending on the logic of your program, it might be worth having a 'company' model, and having the TestModels as a foreign key to their respective companies.
class Company(models.Model):
name = models.CharField(max_length = 100)
# other fields and functions
class TestModel(models.Model):
company = models.ForeignKey(Company)
nick_name = models.CharField(max_length=100)
created_at = models.DateTimeField()
Then you can just filter by foreign key to get the company's testmodels:
results = {}
for company in Company.objects.all():
results[company.name] = list(company.testmodel_set.all())
models.py
My models.py
class Custom_user_model(User):
daily_target = models.IntegerField()
monthly_target = models.IntegerField()
yearly_target = models.IntegerField()
weekly_target = models.IntegerField()
call_target = models.IntegerField()
email_target = models.IntegerField()
meeting_target = models.IntegerField()
added_under = models.IntegerField()
profile_pic = models.TextField()
doj = models.DateTimeField(default='')
location_id = models.IntegerField()
locked = models.BooleanField()
default_currency = models.IntegerField()
date_change_permission = models.BooleanField()
deal_back_log = models.BooleanField()
created_date=models.DateTimeField(auto_now_add=True)
role_id=models.IntegerField()
profile_pic = models.FileField(upload_to='.')
objects = UserManager()
//This custom_user model is the extension of django's default user model.
class Deal(models.Model):
a_choices = ((0,'yes'),(1,'no'))
approved = models.IntegerField(choices=a_choices,default=1)
user_id = models.IntegerField()
company_id = models.IntegerField()
contact_id = models.IntegerField()
deal_title=models.CharField(max_length=200)
deal_value = models.CharField(max_length=20)
currency_id = models.IntegerField()
process_id = models.IntegerField()
expected_close_date = models.DateField(default='')
closed_date = models.DateField()
deal_milestone=models.IntegerField()
created=models.DateTimeField(auto_now_add=True)
last_modified=models.DateTimeField(auto_now_add=True)
s_choices = ((0,'active'),(1,'won'),(2,'junk'),(3,'lost'))
status = models.IntegerField(choices=a_choices,default=0)
type = models.CharField(max_length=50, default='deal')
source = models.CharField(max_length=50,default='O')
class user_Roles(models.Model):
code = models.CharField(max_length=20)
description = models.CharField(max_length=30)
permitted_menus = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
Using user_roles model, I have assigned permission for accessing data to the newly created user based on his/her role. I want to get the created deals which are added by the users having role_id = 2 and deals created date between the specified dates .
### views.py
st_date, end_date = week_magic(date.today())
cur = connection.cursor()
cur.execute("select *, CONCAT(au.first_name,' ',au.last_name) as full_name from myapp_custom_user_model mu left join auth_user au on mu.user_ptr_id = au.id INNER JOIN myapp_user_roles ml on ml.id= 2 and ml.id = mu.role_id LEFT JOIN (SELECT user_id,SUM( deal_value ) AS cnt FROM myapp_deal where status = 1 and DATE_FORMAT(closed_date,'%Y-%m-%d') BETWEEN " '%s' " and " '%s' " GROUP BY user_id)d ON mu.user_ptr_id = d.user_id where mu.locked !=1 and mu.role_id = 2 order by COALESCE( d.cnt, 0 ) DESC",(st_date,end_date))
users = dictfetchall(cur)
cur.close()
While executing the query it shows unsupported format error. So I used one more % symbol in the same query as follows:
cur.execute("select *, CONCAT(au.first_name,' ',au.last_name) as full_name from myapp_custom_user_model mu left join auth_user au on mu.user_ptr_id = au.id INNER JOIN myapp_user_roles ml on ml.id= 2 and ml.id = mu.role_id LEFT JOIN (SELECT user_id,SUM( deal_value ) AS cnt FROM myapp_deal where status = 1 and DATE_FORMAT(closed_date,'%%Y-%%m-%%d') BETWEEN " '%s' " and " '%s' " GROUP BY user_id)d ON mu.user_ptr_id = d.user_id where mu.locked !=1 and mu.role_id = 2 order by COALESCE( d.cnt, 0 ) DESC" %(st_date,end_date))
It doesn't give any error but the result is empty even though there is data because of this syntax: DATE_FORMAT(closed_date,'%%Y-%%m-%%d'). How to solve this?
First of all you should use ForeignKey fields for role_id in Custom_user_model and user_id in Deal. The same is probably true for some of the other _id fields in your models.
class Custom_user_model(User):
...
role = models.ForeignKey('Role')
...
class Deal(models.Model):
...
user = models.ForeignKey('Custom_user_model')
...
After that you can do your query like this:
# get deals from users with role_id=2
query = Deal.objects.filter(user__role_id=2)
# add filter for deals created by that user created between
start_date, end_date = week_magic(date.today())
query = query.filter(created__between=(start_date, end_date))