Django How to bulk update on all child objects? - python-3.x

I am building help desk system on django. Where anyone can open ticket for customer support.
Assume I have an parent object #001 and every child object of this parent have same ticket id. See the screenshot for better understand:
child1 and child2 have same ticket id like their parent object. How to apply bulk update on all objects if they have same ticket id?. Assume if I change ticket status of child2 then I want it will also apply bulk update of child1 and parent object. any idea how to do that on django?
here is my code:
models.py
class Contact(models.Model):
choice = (("pending","pending"),("solved","solved"),("closed","closed"))
ticket_status = models.CharField(choices=choice,max_length=100,default="pending")
parent =models.ForeignKey('self', on_delete=models.CASCADE,
null=True, blank=True, related_name='contact_parent')
sno = models.AutoField(primary_key=True,)
def save(self,*args,**kwargs):
if not self.parent and not self.support_ticket:
self.support_ticket= str(rand_support_ticket())
if not self.support_ticket:
self.support_ticket = self.parent.support_ticket
super(Contact,self).save(*args,**kwargs)
forms.py
class SupportAgentFrom(forms.ModelForm):
class Meta:
model = Contact
fields = ['support_message','ticket_status']
views.py
def AddReplySupport(request,slug):
# fetch the object related to passed id
obj = get_object_or_404(Contact, slug = slug)
# pass the object as instance in form
form = SupportAgentFrom(request.POST or None, instance = obj)
if form.is_valid():
form.instance.support_agent = request.user
form.save()
now I can update only single object once at a time. I want to apply bulk update on multiple objects at a time if they have same ticket id.
#Update1
Finally my problem is solved after following Dan Yishai solution. Here I want to try little bit explain his code so people can understand and solve this type of similar problems which I was facing.
Contact.objects.filter(
Q(support_ticket=form.instance.support_ticket)
).update( ticket_status="closed")
Above line of code searching and updating only those objects whose have exactly same ticket id.

You can update the item and all of it's children in a single query, just replace your code inside the if with something like:
count = Contact.objects.filter(
Q(pk=form.instance.pk) | Q(parent_id=form.instance.pk)
).update(support_agent=request.user)
You can use count to verify at least 1 object has been updated, and display to the user how many objects were modified.

Below I'm assuming sno is the Ticket Id
To grab the queryset:
queryset = Contact.objects.filter(sno=form.instance.sno)
Now you can use .update() or .bulk_update().
Update every object to have the same support agent:
queryset.update(support_agent=request.user)
Update every object to have a different support agent:
for contact in queryset:
contact.support_agent = value
queryset.bulk_update['support_agent']

Related

How to automatically update model field if there are changes to the previous field?

I am trying to find a way to update the latest field in a model if there are changes in the earlier field.
for example: say I have a Cash Balance model
If I change the sale inv 134 debits to 50. how do I make this change reflect on the other cash balance coming after it automatically?
Edit 1 :
class AccountsModel(models.Model):
Date = models.DateField(auto_now=True)
INV_No = models.IntegerField(null=True,blank=True)
Discription = models.CharField(max_length=500,blank=True)
Debit = models.DecimalField(max_digits=8,decimal_places=2,default=0.0)
Credit = models.DecimalField(max_digits=8,decimal_places=2,default=0.0)
CashBalance = models.DecimalField(max_digits=8,decimal_places=2,default=0.0)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
#property
def GetLastCB(self):
return AccountsModel.objects.last().CashBalance
def get_bookno(self):
if not self.INV_No:
return ''
return self.INV_No
This is a simple model that I made. I made API views to GET, POST AND DELETE
What you probably want to use is a signal
https://docs.djangoproject.com/en/4.0/topics/signals/
from django.dispatch import receiver
#receiver(post_save, sender=CashBalance)
def update_cash_balance(sender, instance, **kwargs):
if instance.balance != instance.calculate_balance()
instance.set_balance()
Be wary of using .save() within the signal because you can start a recursive loop, put an if-statement check to prevent this from happening

Is there a way to override ClockedSchedule model from Django Celery Beat?

I want to add unique=True attribute to clocked_time field of ClockedSchedule model. Current Scenario is, when multiple threads try to get_or_create schedule, it creates more than one of similar records given schedule is not found, and when next time some thread tries to get the schedule it throws MultipleObjectsReturned exception. So, I was thinking adding a DB constraint might work here. Attaching the code for reference:
schedule, created = ClockedSchedule.objects.get_or_create(**clocked_options)
return schedule
And the model looks like:
class ClockedSchedule(models.Model):
"""clocked schedule."""
clocked_time = models.DateTimeField(
verbose_name=_('Clock Time'),
help_text=_('Run the task at clocked time'),
)
class Meta:
"""Table information."""
verbose_name = _('clocked')
verbose_name_plural = _('clocked')
ordering = ['clocked_time']
def __str__(self):
return '{}'.format(self.clocked_time)
Let me know your thoughts, thanks!

Object doesn't exist in DB after consequential api calls

I have the following flow for object creation:
A user wants to create an object on a webservice. In order to do it - I check if the user is eligible to pay a fee for it.
We make a request to know how much the user should pay. If 0 - user will see the regular Create button, if >0 he will see the PayPal button.
User fills in data and in the second case presses the PayPal button.
We make 2 consequential API requests:
Create an object with the parameter is_draft=True. Return its id.
Create an order object and use the id from the previous step.
Sometimes we cannot create an order, because the object doesn't exist in DB yet.
Django setting:
DATABASES["default"]["ATOMIC_REQUESTS"] = True
Django models:
class Object1(models.Model):
name = models.CharField()
...
class Object2(models.Model):
name = models.CharField()
...
class Order(models.Model):
user = models.ForeignKey(User)
amount = models.DecimalField()
#naive polymorphism
object1 = models.ForeignKey(Object1)
object2 = models.ForeignKey(Object2)
# An object will be created after PayPal's call to the webhook endpoint
class OrderPayment(models.Model):
...
order = models.ForeignKey(Order)
The problem is that when I try to create an order to want to assign object1 or object2 as FK it doesn't exist yet. Also I cannot call transaction.commit() after any object creation (Object1 or Object2) because I use atomic request and it leads to an error:
django.db.transaction.TransactionManagementError: This is forbidden when an 'atomic' block is active.
How can I ensure objects existence in DB?
:::::::::::::::::::::::::::::UPDATE:::::::::::::::::::::::::::::
I am sorry, I gave a lot of irrelevant info.
Basically the flow is:
Make an API request to create an Object1. Return its id.
Behind the the API is simple CreateAPIView from DRF.
Make an API request to create an Order with the ID from previous step.
In the second step, I try to create an object and create a relation with Object1 which might not exist sometimes.
UPDATE2
views.py
class CreateObject1APIView(generics.CreateAPIView):
serializer = Object1Serializer
class CreateOrderAPIView(generics.GenericAPIView):
serializer = OrderSerializer
def post(self, request, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
# Everything fails after calling save method, as Object1 sometimes doesn't exist.
serializer.save()
OrderService.call()
settings.py
DATABASES = {"default": env.db("DATABASE_URL")}
DATABASES["default"]["ATOMIC_REQUESTS"] = True

How do I read the parameter of the GET request in a RESTful Flask/SQLAlchemy/Marshmallow environment

I was working my way through a couple of tutorials before xmas and I'm now trying to pick up where I left of.
Trying to teach myself REST by building some simple API end points. My confusion is coming from the fact that I cant find the tutorials I was using and there seems to be several different ways to solve the problem. So now I'm not sure what is the correct way to do it.
The code is working for returning all customers in the DB, now I want to return a specific customer based on their Id
Ok this is what I have...
I have an app.py that defines the resource like this:
api.add_resource(CustomerResource, '/Customer')
I have a models.py that defines the customer class like this:
ma = Marshmallow()
db = SQLAlchemy()
class Customer(db.Model):
__tablename__ = 'customers'
__table_args__ = {"schema":"business"}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
status = db.Column(db.Integer, nullable=False)
class CustomerSchema(ma.Schema):
id = fields.Integer()
name = fields.String(required=True)
status = fields.Integer(required=True)
I have customer.py that defines the customer class as this:
customers_schema = CustomerSchema(many=True)
customer_schema = CustomerSchema()
class CustomerResource(Resource):
def get(self):
customers = Customer.query.all()
customers = customers_schema.dump(customers)
return {'status': 'success', 'data': customers}, 200
I have tried using request.args, but I dont believe that is the correct way to go due to the fact it will become unspported.
So the above all works with the GET successfully returning all customers. But now I want to be able to use GET http://127.0.0.1:5000/api/Customer/10 and to just return the details for customer id = 10
I'm not sure whether I need to define a new resource or whether the existing CustomerResource can be modified to test for the presence of a parameter.
Any guidance appreciated...
Yes you're correct don't use the request.args method, rather create another resource. Remember api.add_resource is essentially just mapping a handler to a RESTFUL endpoint. If you had a lot of duplicate business logic code shared between endpoints I would suggest that you abstract out that business logic into a helper function and utilize this helper function within your resource definitions, but in this particular case this isn't necessary. I would consider doing the following:
app.py:
api.add_resource(CustomerList, '/Customer')
api.add_resource(Customer, '/Customer/<int:id>')
I would rename customer.py to something like routes.py and it would contain the following:
class CustomerList(Resource):
def get(self):
customers = Customer.query.all()
customers = customers_schema.dump(customers)
return {'status': 'success', 'data': customers}, 200
class Customer(Resource):
def get(self, id):
customer = Customer.query.filter_by(id=id).first()
customer, errors = customers_schema.dump(customer)
if errors:
return jsonify(errors), 422
return customer, 200
Keep your models.py file as is, and I would consider utilizing the jsonify method that flask provides for returning your data within your RESTFUL endpoints. I have shown an example of this in the specific customer endpoint.
Hopefully that helps!

Mongoengine Link to Existing Collection

I'm working with Flask/Mongoengine-MongoDB for my latest web application.
I'm familiar with Pymongo, but I'm new to object-document mappers like Mongoengine.
I have a database and collection set up already, and I basically just want to query it and return the corresponding object. Here's a look at my models.py...
from app import db
# ----------------------------------------
# Taking steps towards a working backend.
# ----------------------------------------
class Property(db.Document):
# Document variables.
total_annual_rates = db.IntField()
land_value = db.IntField()
land_area = db.IntField()
assessment_number = db.StringField(max_length=255, required=True)
address = db.StringField(max_length=255, required=True)
current_capital_value = db.IntField
valuation_as_at_date = db.StringField(max_length=255, required=True)
legal_description = db.StringField(max_length=255, required=True)
capital_value = db.IntField()
annual_value = db.StringField(max_length=255, required=True)
certificate_of_title_number = db.StringField(max_length=255, required=True)
def __repr__(self):
return address
def get_property_from_db(self, query_string):
if not query_string:
raise ValueError()
# Ultra-simple search for the moment.
properties_found = Property.objects(address=query_string)
return properties_found[0]
The error I get is as follows: IndexError: no such item for Cursor instance
This makes complete sense, since the object isn't pointing at any collection. Despite trolling through the docs for a while, I still have no idea how to do this.
Do any of you know how I could appropriately link up my Property class to my already extant database and collection?
The way to link a class to an existing collection can be accomplished as such, using meta:
class Person(db.DynamicDocument):
# Meta variables.
meta = {
'collection': 'properties'
}
# Document variables.
name = db.StringField()
age = db.IntField()
Then, when using the class object, one can actually make use of this functionality as might be expected with MongoEngine:
desired_documents = Person.objects(name="John Smith")
john = desired_documents[0]
Or something similar :) Hope this helps!
I was googling this same question and i noticed the answer has changed since the previous answer:
According to the latest Mongoengine guide:
If you need to change the name of the collection (e.g. to use MongoEngine with an existing
database), then create a class dictionary attribute called meta on your document, and set collection to the
name of the collection that you want your document class to use:
class Page(Document):
meta = {'collection': 'cmsPage'}
The code on the grey did the trick and i could use my data instantly.

Resources