Hi Dan, Thanks for the suggestion, it's a web scraper (run as a django management command) which then saves the data to the database via the Django ORM. Given it's a scraper rather than a form (or view) is the above suggested function an ok way to proceed or would you suggest something else is more appropriate/best practice?
On Friday, 6 November 2015 14:40:59 UTC, Dan Tagg wrote: > > Hi Yunti, > > > You could go up a level in the structure of your application and apply the > logic there, where there is more support. > > Are you using Django forms? The ModelForm class pretty much does what you > want, it examines form data, validating it against its type and any > validation rules you have set in the form or your model, compares it to the > instance's data in the database and only saves if there has been some kind > of change. > > Dan > > On 6 November 2015 at 13:47, Yunti <[email protected] <javascript:>> wrote: > >> Jani, >> >> Thanks for your reply - you explained it much more concisely than I did. >> :) >> >> Good to have it confirmed that update_or_create() doesn't quite do what I >> needed - I was confused as to whether it would or not. >> >> Thanks for taking the time to do that function, that looks ideal. I'll >> test it out. >> >> >> On Friday, 6 November 2015 12:52:11 UTC, Jani Tiainen wrote: >> >>> Your problem lies on the way Django actually carries out create or >>> update. >>> >>> As name suggest, create or update does either one. But that's what you >>> don't want - you want conditional update. >>> >>> Only update if certain fields have been changed. Well this can be done >>> few ways. >>> >>> So you want to do >>> "update_only_if_at_least_one_of_default_fields_changed_or_create" >>> >>> Operation is simple, if object is not found, create new one using >>> defaults if found, pull values as a dict, compare against >>> default values and if at least one differs do an update. Otherwise don't >>> do anything. >>> >>> So basically code would look something like this: >>> >>> update_if_changed_or_create(**kwargs): >>> defaults = kwargs.pop('defaults', None) >>> >>> qs = MyModel.objects.filter(**kwargs) >>> >>> if not qs: >>> obj = MyModel(**kwargs).save() >>> return obj, True # Created object >>> else if len(qs) == 1: >>> obj = qs[0] >>> changed = False >>> for k, v in defaults: >>> if getattr(obj, k) != v: >>> changed = True >>> setattr(obj, k, v) >>> if changed: >>> obj.save() >>> return obj, False # Updated object >>> else: >>> # Multiple objects... >>> >>> return obj, None # No change. >>> >>> >>> On 06.11.2015 14:08, Yunti wrote: >>> >>> Carsten , >>> >>> Thanks for your reply, >>> >>> A note about the last statement: If a Supplier object has the same >>> unique_id, and all >>> other fields (in `defaults`) are the same as well, logically there is no >>> difference >>> between updating and not updating – the result is the same. >>> >>> The entry in the database is the same - apart from the last_updated flag >>> if it's not rewritten over the top of it. This means I can check for new >>> data often and be alerted when there is an actual update (i.e. a change to >>> the data). If it rewrites the data everytime it checks then I have no idea >>> when data was actually updated. >>> >>> Have you checked? How? >>> In your create_or_update_if_diff() you seem to try to re-invent >>> update_or_create(), but >>> have you actually examined the results of the >>> >>> supplier, created = Supplier.objects.update_or_create(...) >>> >>> call? >>> >>> I checked by seeing that the last_updated field in the database was >>> updated everytime. (I suppose the issue could be with how that field gets >>> reset to the next time it's run- I didn't eliminate that possibility.) >>> >>> Yes I was worried that I might be recreating (a poor version) of >>> update_or_create() but it didn't seem to have the option where it wouldn't >>> write to the database if there was no change to the data. >>> Can it do this? And how would I verify when an item has been updated or >>> created (or neither) - could I output to the console? >>> >>> If it can how do I call it so it checks against all fields (unique_id >>> and defaults) and updates using the defaults if it finds a difference (and >>> creates if it doesn't find a unique_id)? >>> >>> I'm still not sure if this is possible and how to call the function, >>> particular how to pass in the remaining defaults to check against - >>> **kwargs = defaults isn't right but not sure what it should be. >>> >>> supplier, created = >>> Supplier.objects.update_or_create(unique_id=product_detail['supplierId'], >>> **kwargs=defaults, >>> defaults={ >>> 'name': >>> product_detail['supplierName'], >>> 'entity_name_1': >>> entity_name_1, >>> 'entity_name_2': >>> entity_name_1, >>> 'rating': >>> product_detail['supplierRating']}) >>> >>> On Thursday, 5 November 2015 20:05:39 UTC, Carsten Fuchs wrote: >>>> >>>> Hi Yunti, Am 05.11.2015 um 18:19 schrieb Yunti: > I have tried to use >>>> the update_or_create() method assuming that it would either, create > a >>>> new >>>> entry in the db if it found none or update an existing one if it found one >>>> and had > differences to the defaults passed in - or wouldn't update if >>>> there was no difference. A note about the last statement: If a Supplier >>>> object has the same unique_id, and all other fields (in `defaults`) are >>>> the >>>> same as well, logically there is no difference between updating and not >>>> updating – the result is the same. > However it just seemed to recreate >>>> entries each time even if there were no changes. Have you checked? How? In >>>> your create_or_update_if_diff() you seem to try to re-invent >>>> update_or_create(), but have you actually examined the results of the >>>> supplier, created = Supplier.objects.update_or_create(...) call? > I >>>> think >>>> the issue was that I wanted to: > 1) get an entry if all fields were the >>>> same, update_or_create() updates an object with the given kwargs, the >>>> match >>>> is not made against *all* fields (i.e. for the match the fields in >>>> `defaults` are not accounted for). > 2) or create a new entry if it didn't >>>> find an existing entry with the unique_id > 3) or if there was an entry >>>> with the same unique_id, update that entry with remaining > fields. >>>> update_or_create() should achieve this. It's hard to tell more without >>>> additional information, but >>>> https://docs.djangoproject.com/en/1.8/ref/models/querysets/#update-or-create >>>> >>>> explains the function well, including how it works. If you work through >>>> this in small steps, check examples and their (intermediate) results, you >>>> should be able to find what the original problem was. Best regards, >>>> Carsten >>> >>> -- You received this message because you are subscribed to the Google >>> Groups "Django users" group. To unsubscribe from this group and stop >>> receiving emails from it, send an email to >>> [email protected]. To post to this group, send email to >>> [email protected]. Visit this group at >>> http://groups.google.com/group/django-users. To view this discussion on >>> the web visit >>> https://groups.google.com/d/msgid/django-users/9b529e2d-7e2b-4194-a77c-8434efe6205d%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/django-users/9b529e2d-7e2b-4194-a77c-8434efe6205d%40googlegroups.com?utm_medium=email&utm_source=footer>. >>> >>> For more options, visit https://groups.google.com/d/optout. >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "Django users" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected] <javascript:>. >> To post to this group, send email to [email protected] >> <javascript:>. >> Visit this group at http://groups.google.com/group/django-users. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/django-users/889c6480-98b3-415d-af92-490d11de5695%40googlegroups.com >> >> <https://groups.google.com/d/msgid/django-users/889c6480-98b3-415d-af92-490d11de5695%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> >> For more options, visit https://groups.google.com/d/optout. >> > > > -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/3cea33db-f2e7-4739-a202-99a717bda092%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.

