Best way to automatic change update_time in mongoengine only under some conditions - mongoengine

Say I defined a model Story, and in my save method I automatically update the update_time field:
class Article(Document):
...
content = StringField()
likes = IntField(default=0)
some_mark = BooleanField()
update_time = DateTimeField(default=datetime.datetime.now)
def save(...)
self.updated_at = datetime.datetime.now()
...
But I would NOT like to only update the update_time when only the likes count or some_mark are changed. Or, if I only want to update the update_time when some fields like the content is changed. What will be the best way to do this?

You can check the ._changed_fields attribute on your Document class to check the fields that were changed
class Person(Document):
name = StringField()
enter code here
p = Person(name='John').save()
print(p._changed_fields) # []
p.name = 'Bob'
print(p._changed_fields) # ['name']

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

How to INSERT into a database using JOIN

I'm currently using PeeWee together with Python and I have managed to create a cool application
CREATE TABLE stores (
id SERIAL PRIMARY KEY,
store_name TEXT
);
CREATE TABLE products (
id SERIAL,
store_id INTEGER NOT NULL,
title TEXT,
image TEXT,
url TEXT UNIQUE,
added_date timestamp without time zone NOT NULL DEFAULT NOW(),
PRIMARY KEY(id, store_id)
);
ALTER TABLE products
ADD CONSTRAINT "FK_products_stores" FOREIGN KEY ("store_id")
REFERENCES stores (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT;
which has been converted to peewee by following code:
# ------------------------------------------------------------------------------- #
class Stores(Model):
id = IntegerField(column_name='id')
store_name = TextField(column_name='store_name')
class Meta:
database = postgres_pool
db_table = "stores"
#classmethod
def get_all(cls):
try:
return cls.select(cls.id, cls.store_name).order_by(cls.store)
except Stores.IntegrityError:
return None
# ------------------------------------------------------------------------------- #
class Products(Model):
id = IntegerField(column_name='id')
title = TextField(column_name='title')
url = TextField(column_name='url')
image = TextField(column_name='image')
store = ForeignKeyField(Stores, backref='products')
class Meta:
database = postgres_pool
db_table = "products"
#classmethod
def add_product(cls, pageData, store_name):
"""
INSERT
INTO
public.products(store_id, title, image, url)
VALUES((SELECT id FROM stores WHERE store_name = 'footish'), 'Teva Flatform Universal Pride',
'https://www.footish.se/sneakers/teva-flatform-universal-pride-t1116376',
'https://www.footish.se/pub_images/large/teva-flatform-universal-pride-t1116376-p77148.jpg?timestamp=1623417840')
"""
try:
return cls.insert(
store_id=cls.select(cls.store.id).join(Stores).where(cls.store.store_name == store_name).get().store.id,
title=pageData.title,
url=pageData.url,
image=pageData.image,
).execute()
except Products.DoesNotExist:
return None
However I have realized that working with id's is quite faster than working with text and I have an issue where I am trying to figure out what would be the best way to insert the ID. I did get a comment regarding my code as for today:
your insert isn't' referencing "stores" at all so not sure what your hoping to get from that since you have a sub query there
I am a bit confused what that means however my question is that I would like to know which approach is the correct way to insert
Is it better on start of application, to store the id as a variable and pass the variable into a insert function (argument)
Or to call store_id=cls.select(cls.store.id).join(Stores).where(cls.store.store_name == store_name).get().store.id where I instead pass the store_name and then it would return the correct id?
My first thought is that by doing the number 2, that is like doing 2 queries instead of one? but I might be wrong. Looking forward to know!
This is quite incorrect:
# Wrong
store_id=cls.select(cls.store.id).join(Stores).where(cls.store.store_name == store_name).get().store.id,
Correct:
try:
store = Stores.select().where(Stores.name == store_name).get()
except Stores.DoesNotExist:
# the store name does not exist. do whatever?
return
Products.insert(store=store, ...rest-of-fields...).execute()

Odoo: on create save current ID in a many2one field of another model

what I'm trying to do is I'm creating a custom.modify.price model for products, where I'm able to choose a certain criteria to result in a selection of products, then I fill in a percentage that affects the prices of all the previous selection. I want it to create a new record, for each product in the selection, in a another model custom.sale.price and each record should be holding the ID of the custom.modify.price record that created it in a many2one field. The thing is I can create a new record of this custom.sale.price by overriding the custom.modify.price create method and feeding it the values to do so, but I am not able to feed it the current ID of "not yet created" custom.modify.price record
class CustomModifyPrice(models.Model):
date = fields.Datetime(string='Date', required=True, default=fields.Datetime.now())
brand_id = fields.Many2many(comodel_name="custom.brand", string="Brand", required=False, )
origin_id = fields.Many2many(comodel_name="custom.country", string="Origin", required=False, )
percentage = fields.Float(string="Percentage")
product_ids = fields.Many2many(comodel_name="custom.product", string="Products", readonly=True, )
#api.model
def create(self, vals):
values = {'product_id': product.id, 'date': vals['date'], 'sell_price': mod_sell_price, 'modification_id': self.id}###self.id returns nothing here
price = self.env['custom.sale.price'].create(values)
result = super(CustomModifyPrice, self).create(vals)
return result
class CustomSalePrice(models.Model):
product_id = fields.Many2one(comodel_name="custom.product", string="Product", required=False, )
date = fields.Datetime(string="Date", default=fields.Datetime.now())
sell_price = fields.Float(string="Selling Price")
sale_id = fields.Many2one(comodel_name="custom.sale", string="Sales Order", required=False, )
You need to to create custom.modify.price and update values with the result id then create custom.sale.price
#api.model
def create(self, vals):
result = super(CustomModifyPrice, self).create(vals)
values = {'modification_id': result.id, ...}
self.env['custom.sale.price'].create(values)
return result

Either field is required for validation - MongoEngine

I've created a class for an RSS feed:
from mongoengine import *
class RSS(Document):
time_added = DateTimeField(default=datetime.datetime.utcnow)
link = StringField(required=True)
title = StringField(required=True)
last_entry_id = StringField(required=True)
last_etag = StringField()
last_modified = DateTimeField()
subscribed = ListField(IntField(), required=True)
meta = {
'collection': 'rss',
'indexes': ['$title']
}
As per my requirements, I want to make it so that either one or both of last_etag and last_modified fields are present (i.e. required). Would that be possible within MongoEngine?
For multi-field validation, you can override Document.clean method, e.g.
from mongoengine import *
import datetime as dt
class RSS(Document):
etag = StringField()
last_modified = DateTimeField()
def clean(self):
if not self.etag and not self.last_modified:
raise ValidationError('etag and or last_modified are required')
RSS().save() # Fails with ValidationError (etag and/or last_modified are required)
RSS(etag='123456789').save() # passes
RSS(etag='123456789', last_modified=dt.datetime.utcnow()).save() # passes
You can see the docs for more info.

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