Is there a way to override ClockedSchedule model from Django Celery Beat? - python-3.x

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!

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

Can you make sure only one object related to another object has a certain field set?

I have a model called Video, and it has related objects on another model called Label. Example here:
class Video(models.Model):
pass
class Label(models.Model):
video = models.ForeignKey(Video, related_name="labels")
current = models.NullBooleanField()
I need to be able to find the current label on a video by doing something like my_video.labels.filter(current=True), and this query should only ever return one label, so only one label on the video should have that field set to True.
Is there a way of ensuring this on the model/db?
Thanks
EDIT: The answer given below has achieved exactly this. Adding some django tests below for anyone else reading as some proof:
class TestLabelIntegrity(TestCase):
def test_a_video_can_have_only_one_current_label(self):
video = Video.objects.create()
label_1 = Label.objects.create(
video=video,
current=True
)
with self.assertRaises(IntegrityError):
label_2 = Label.objects.create(
video=video,
current=True
)
def test_two_different_videos_can_each_have_current_layers(self):
""" No assertions needed, just need to make sure no integrity errors are raised"""
video_1 = Video.objects.create()
label_1 = Label.objects.create(
video=video_1,
current=True
)
video_2 = Video.objects.create()
label_2 = Label.objects.create(
video=video_2,
current=True
)
I believe you can solve this using UniqueConstraint.
Using this, you can restrict that a Video only have a single label that current == True
You can define the UniqueConstraint in the models Meta.
You’ll get a database integrity error on save() if the condition fails.
See the documentation for this here:
https://docs.djangoproject.com/en/4.0/ref/models/constraints/
class Label(models.Model):
...
class Meta:
constraints = [
models.UniqueConstraint(
fields=["current", "video"],
condition=Q(current=True),
name="unique_current_label",
),
]

Django How to bulk update on all child objects?

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']

Django: Abstract base class for managing db_table

I'm trying to build my second django (and python for that matter, my first project being the django tutorial :)) project. since this is supposed to be something real i'd like to be thorough and build a good code structure before i go into the meat of the project.
I have a couple of simple models like this
class Task(models.Model):
name = models.CharField(max_length=50, null=False)
description = models.CharField(max_length=255, null=True)
dueDate = models.DateTimeField()
I'm using PostgreSQL and i set up my models to use the app label as a database schema by defining the meta class of each model like this
class Meta:
managed = True
db_table = 'app_name\".\"modelname'
This works well. But i have to do this for every single model.
I want to keep it DRY though. So what i'm trying to do now is to have an abstract base class that does this automatically
so i tried the following:
class SchemaModel(models.Model):
class Meta():
abstract = True
managed = True
db_table = AppConfig.label+'\".\"'+self.__class__.lower()+'s'
(the base class was then inherited of course and i took the nested Meta class out of the normal models)
this didn't work though because self isn't accessible in Meta
after consulting the documentation i tried this:
class SchemaModel(models.Model):
class Meta():
abstract = True
managed = True
db_table = '%(app_label)\".\"%(class)s'
which lead to the property db_table of every model being "%(app_label)\".\"%(class)s"
>>> t = Task()
>>> t._meta.db_table
'%(app_label)"."%(class)s'
>>>
I didn't find anything similar on the internet. Am i trying to do something impossible or "forbidden"?
Solution
The solution is as shown in elyas answer to set the db_table property at the end of models.py by looping through all __subclasses__()
for model in SchemaModel.__subclasses__():
db_table = '{}s'.format(model._meta.label_lower.replace('.','\".\"'))
model._meta.original_attrs['db_table'] = db_table
model._meta.db_table = db_table
I wouldn't say it's forbidden. But I can't think of any way to do this declaratively. There is a way to do it however.
Firstly, on your existing attempts:
Accessing 'self'
db_table = AppConfig.label+'\".\"'+self.__class__.lower()+'s'
An instance object is never created from the Meta class when models are loaded, and so there is no self to reference. But even if an instance object were created, db_table is an attribute of the class object, so it is evaluated when the class object is created, which is before any instance object is created, so self cannot be accessed when defining a class attribute in this way.
Edit: And as you mentioned, the app_label cannot be accessed through AppConfig.label.
String formatting
db_table = '%(app_label)\".\"%(class)s'
These placeholders are only used in a very specific situation when defining the related_name and related_query_name attributes of ForeignKey or OneToOneField's fields in an abstract base class.
A solution
As I said, I can't think of any declarative way to achieve this. For example, trying to use __qualname__ won't work because you would just end up with SchemaModel.Meta every time.
But you could put a for loop at the bottom of your models.py like this:
for model in SchemaModel.__subclasses__():
# Name your db_table here
db_table = model._meta.app_label + '\".\"' + model._meta.model_name.lower() + 's'
# Set db_table here
model._meta.original_attrs['db_table'] = db_table
model._meta.db_table = db_table
All of SchemaModel's children can be found using the built-in __subclasses__() method.
The db_table attribute needs to be updated in two places. Firstly in _meta, which is (partly) created by copying attributes from the Meta class, and secondly in _meta.original_attrs where the original Meta attributes are stored and are read by Django during migrations.
Alternative solution
Personally I would define the db_table names manually and simply have a unit test that checks that all models adhere to whatever naming convention I've come up. I prefer this so if another developer eyeballs a model they have never seen before they can get the full picture based on the declarations in the model (and the abstract base class) and don't get confused about an operation modifying them elsewhere.

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!

Resources