Django bulk create with foreign key to another field - django

I want to bulk create objects, when they have a foreign key and their foreign key is not id field. (When to_field value is id you can reference it with model_id in creation but I haven't found a way to do id with another field.)
I have a model named Credit:
class Credit(models.Model):
account = models.ForeignKey('finance.Account', to_field='account_id', on_delete=models.PROTECT)
amount = models.PositiveBigIntegerField()
and a model named Account:
class Account(models.Model):
account_id = models.UUIDField(
verbose_name=_("account id"),
db_index=True,
null=True,
unique=True,
)
and I tried to create objects with:
accounts = [] # list of uuids
credits = [
Credit(
account__account_id=a,
amount=amount,
) for a in accounts]
created_objects = Credit.objects.bulk_create(
credits, ignore_conflicts=True
)
and I get the following error:
TypeError: Credit() got an unexpected keyword argument 'account__account_id'

That's not possible because you are touching two tables: Credit and Account. So you need at least two INSERTs anyways.
accounts_uuids = []
amount = 0
accounts = [Account(account_id=uuid) for uuid in accounts_uuids]
Account.objects.bulk_create(objs=accounts)
credits = [Credit(account=account, amount=amount) for account in accounts]
Credit.objects.bulk_create(objs=credits, ignore_conflicts=True)

Related

get foreign key related data in django using filter

This is the model :
class Requirement(models.Model):
name = models.CharField(max_length=100)
user = models.ForeignKey(
User,on_delete=models.CASCADE, related_name = 'user'
)
assigned_user = models.ForeignKey(
User,related_name = "assigned",on_delete=models.CASCADE,
)
I am running this query:
requirementsOb = Requirement.objects.filter(user = currentUser)
Where currentUser is logged in user. The result returns multiple requriements. I also want to get all user related data. How can i get user related data only for assigned_user
You can try like this:
current_user = request.user
requirements = current_user.user.all() | current_user.assigned.all()
Or you can try this approach:
requirementsOb = Requirement.objects.filter(Q(user = currentUser) | Q(assigned_user=currentUser))
If you want to get user data from requirements, you can try:
for r in requirementsOb:
r.user
r.assigned_user
If you want to get only the first requirement from the requirementsOb, then try like this:
requirement = requirementsOb.first() # or .last() for last object
requirement.user
requirement.assigned_user
More information can be found in documentation.

Filter objects that have a foreign key from another object - Django

I want to filter Employee, only those that have a ForeignKey, how to do it? My solution does not returned any results.
Models.py
class Employee(models.Model):
name = models.CharField(max_length=200)
class ExperienceCategory(models.Model):
name = models.CharField(max_length=100, unique=True)
class Experience(models.Model):
user = models.ForeignKey(Employee, on_delete=models.CASCADE)
category = models.ForeignKey(ExperienceCategory, on_delete=models.CASCADE)
Views.py
experience_category = *ExperienceCategory object (1)*
#solution - final query
employee_query = Employee.objects.filter(experience__category = experience_category)
How to get employees who have a foreign key from Experience?
What you have should work just fine, as an example to reproduce that
first_employee = Employee.objects.create(name='First')
second_employee = Employee.objects.create(name='Second')
experience_category = ExperienceCategory.objects.create(name='sample_category')
Experience.objects.create(user=first_employee, category=experience_category)
Experience.objects.create(user=second_employee, category=experience_category)
employee_query = Employee.objects.filter(experience__category = experience_category)
employee_query
>>> <QuerySet [<Employee: Employee object (1)>, <Employee: Employee object (2)>]>
If you get an empty queryset it's because either there is no Experience instance with related category equal to experience_category in your database. To get the count of how many Experience instances matching this filter exist in your database you can run
Experience.objects.filter(category=experience_category).count()
In the case I provided it would return 2. Check first that this method returns a number greater than 0. If it returns 0 you should create some Experience instances first with the corresponding category.

Assigning value to foreign key field

I'm having difficulty assigning a title to the UserService model, which is a foreign key to another model.
models.py
class IndustryService(models.Model):
industryname = models.ForeignKey(Industry, on_delete=models.CASCADE)
title = models.CharField(max_length=120)
class UserService(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
title = models.ForeignKey(IndustryService, on_delete=models.CASCADE)
Here is the portion of code within the view that is failing:
industryservices = IndustryService.objects.filter(industryname=industry)
for service in industryservices:
try:
qs = UserService.objects.get(user=user, title=service.title)
except:
userserv = UserService.objects.create(user=request.user)
userserv.title = service
userserv.save()
The error that I'm getting is as follows:
NOT NULL constraint failed: accounts_userservice.title_id
Based on my testing, the way in which I'm assigning the value to the 'title' foreign key field is wrong (i.e. these 2 lines of code).
service2 = IndustryService.objects.get(title=service.title)
userserv.title = service2
Any thoughts on how I can fix this? Thanks!
You're doing two updates, unnecessarily. Either create the item in one go:
userserv = UserService.objects.create(user=request.user, title=service)
or instantiate without saving and then save at the end:
userserv = UserService(user=request.user)
userserv.title = service
userserv.save()

django querset filter foreign key select first record

I have a History model like below
class History(models.Model):
class Meta:
app_label = 'subscription'
ordering = ['-start_datetime']
subscription = models.ForeignKey(Subscription, related_name='history')
FREE = 'free'
Premium = 'premium'
SUBSCRIPTION_TYPE_CHOICES = ((FREE, 'Free'), (Premium, 'Premium'),)
name = models.CharField(max_length=32, choices=SUBSCRIPTION_TYPE_CHOICES, default=FREE)
start_datetime = models.DateTimeField(db_index=True)
end_datetime = models.DateTimeField(db_index=True, blank=True, null=True)
cancelled_datetime = models.DateTimeField(blank=True, null=True)
Now i have a queryset filtering like below
users = get_user_model().objects.all()
queryset = users.exclude(subscription__history__end_datetime__lt=timezone.now())
The issue is that in the exclude above it is checking end_datetime for all the rows for a particular history object. But i only want to compare it with first row of history object.
Below is how a particular history object looks like. So i want to write a queryset filter which can do datetime comparison on first row only.
You could use a Model Manager method for this. The documentation isn't all that descriptive, but you could do something along the lines of:
class SubscriptionManager(models.Manager):
def my_filter(self):
# You'd want to make this a smaller query most likely
subscriptions = Subscription.objects.all()
results = []
for subscription in subscriptions:
sub_history = subscription.history_set.first()
if sub_history.end_datetime > timezone.now:
results.append(subscription)
return results
class History(models.Model):
subscription = models.ForeignKey(Subscription)
end_datetime = models.DateTimeField(db_index=True, blank=True, null=True)
objects = SubscriptionManager()
Then: queryset = Subscription.objects().my_filter()
Not a copy-pastable answer, but shows the use of Managers. Given the specificity of what you're looking for, I don't think there's a way to get it just via the plain filter() and exclude().
Without knowing what your end goal here is, it's hard to say whether this is feasible, but have you considered adding a property to the subscription model that indicates whatever you're looking for? For example, if you're trying to get everyone who has a subscription that's ending:
class Subscription(models.Model):
#property
def ending(self):
if self.end_datetime > timezone.now:
return True
else:
return False
Then in your code: queryset = users.filter(subscription_ending=True)
I have tried django's all king of expressions(aggregate, query, conditional) but was unable to solve the problem so i went with RawSQL and it solved the problem.
I have used the below SQL to select the first row and then compare the end_datetime
SELECT (end_datetime > %s OR end_datetime IS NULL) AS result
FROM subscription_history
ORDER BY start_datetime DESC
LIMIT 1;
I will select my answer as accepted if not found a solution with queryset filter chaining in next 2 days.

Django - Database query with condition in group_by

I've the following models:
class UsersRoles(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
user = models.ForeignKey(User, db_column='USER_ID')
role = models.ForeignKey(Roles, db_column='ROLE_ID')
room= models.ForeignKey(Rooms, db_column='ROOM_ID')
d_begin = models.DateTimeField(db_column='D_BEGIN')
d_end = models.DateTimeField(db_column='D_END')
,
class Roles(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
name = models.CharField(db_column='NAME', max_length=45)
and also the django User model.
So, I want to retrieve the UsersRoles for the Room 3 being the Role id equal to 5.
Since there are multiple UsersRoles that fulfil this conditions, I want to group the UsersRoles by the User id, returning only the one that has the lastest d_begin date, but if exists one in which d_begin is NULL that's the one to return.
After these conditions, I would like to group_by the User name.
To get the UsersRoles of the room 3 with role 5, I would do:
users_roles = UsersRoles.objects.filter(room__id=3, role__id=5)
My problem is to group them by User id, getting for each user the UserRole with d_begin equal to NULL if there is one, and if not, it would be the one with the latest date.
To order them, I would do users_roles.order_by('user__name').