Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
A small library implementing PostgreSQL ability to return rows in DML statements for Django
A small library implementing PostgreSQL ability to return rows in DML statements for Django.
Link to PostgreSQL docs
Install via pip:
pip install django-pg-returning
or via setup.py:
python setup.py install
The easiest way to integrate, is to inherit your model from UpdateReturningModel
instead of django.db.models.Model
.
It already has redeclared Manager, supporting returning operations.
from django.db import models
from django_pg_returning import UpdateReturningModel
class MyModel(UpdateReturningModel):
field = models.IntegerField()
If you already have custom manager, you can implement get_queryset()
method in it:
from django.db import models
from django_pg_returning import UpdateReturningQuerySet, UpdateReturningModel
class MyManager(models.Manager):
def get_queryset(self):
return UpdateReturningQuerySet(using=self.db, model=self.model)
class MyModel(UpdateReturningModel):
objects = MyManager()
field = models.IntegerField()
And if you have custom manager you can use a mixin:
from django.db import models
from django_pg_returning import UpdateReturningMixin, UpdateReturningModel
class MyQuerySet(models.QuerySet, UpdateReturningMixin):
pass
class MyManager(models.Manager):
def get_queryset(self):
return MyQuerySet(using=self.db, model=self.model)
class MyModel(UpdateReturningModel):
objects = MyManager()
field = models.IntegerField()
After QuerySet mixin is integrated with your model, your QuerySet-s will have 3 additional methods:
from django.db.models import Value
# Any django queryset you like
qs = MyModel.objects.all()
# Update and return a ReturningQuerySet, described below
result = qs.update_returning(field=1)
# Delete data and return a ReturningQuerySet, described below
result = qs.delete_returning()
# Acts like django's QuerySet.create() method, but updates all model fields to values stored in database
# Can be used to retrieve values, saved by database default/triggers etc.
result = MyModel.objects.create_returning(field=Value(1) + Value(2))
print(result.field) # prints: "3" instead of "Value(1) + Value(2)"
# Acts like django's QuerySet.bulk_create() method, but updates all model fields to values stored in database
# Can be used to retrieve values, saved by database default/triggers etc.
result = MyModel.objects.bulk_create_returning([MyModel(field=Value(1) + Value(2))])
print(result[0].field) # prints: "3" instead of "Value(1) + Value(2)"
By default methods get all fields, fetched by the model.
To limit fields returned, you can use standard
QuerySet.only()
and
QuerySet.defer() methods.
create_returning
doesn't support these methods.
bulk_create_returning
doesn't support these methods for django before 1.10.
If model instance is created, basic save()
method is called.
If model is updated, database record is updated, and saved fields are refreshed with database values.
This may be useful, if you update fields with F() expressions.
By default all fields are saved and refreshed.
Use update_fields to specify concrete fields to save and refresh.
from django.db.models import Value, F
instance = MyModel(pk=1, field=Value(1))
instance.save_returning()
print(instance.field)
# Output: 2
# if basic save() called: F('field') + Value(1)
instance.field = F('field') + 1
# Basic save method will not change field and you don't know, what value is in database
instance.save()
print(instance.field)
# Output: F('field') + Value(1)
# Library method gives ability to fetch updated result
instance.save_returning()
print(instance.field)
# Output: 2
Important notes:
The result of returning functions is django_pg_returning.ReturningQuerySet. It is based on django's RawQuerySet, but adds some extra methods to be used easier. The main difference is that ReturningQuerySet caches query results, while RawQuerySet executes query each time it is iterated. All ReturningQuerySet methods are not executed on database side, they are executed in python on cached result. The only way, ReturningQuerySet makes extra database query - is deferred field loading, described above. Implemented methods:
# UPDATE ... RETURNING query is executed here once. The result is cached.
result = MyModel.objects.all().update_returning(field=1)
# Get number of values fetched
print(result.count(), len(result))
# Output: 1, 1
# Index and slicing. Note that the order of result is not guaranteed by the database.
print(result[1], result[0:2])
# Output: MyModel(...), [MyModel(...), MyModel(...), MyModel(...)]
# Sintax sugar for indexing
print(result.first(), result.last())
# Output: MyModel(...), MyModel(...)
# Fetching values and values_list. Both methods use cache and return lists, not ValuesQuerySet like django does.
# values() method cakked without fields will return all fields, fetched in returning method.
# values_list() method called without fields will raise exception, as order or fields in result tuple is not obvious.
print(result.values())
# Output: [{'id': 1, 'field': 1}, {'id': 2, 'field': 2}]
print(result.values('field'))
# Output: [{'field': 1}, {'field': 2}]
print(result.values_list('field', flat=True))
# Output: [1, 2]
print(result.values_list('field', 'id', named=True))
# Output: [Row(field=1, id=1), Row(field=2, id=2)]
FAQs
A small library implementing PostgreSQL ability to return rows in DML statements for Django
We found that django-pg-returning demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.