django-pghistory icon indicating copy to clipboard operation
django-pghistory copied to clipboard

Upgrading to version 2

Open wesleykendall opened this issue 2 years ago • 7 comments

django-pghistory tracks history with triggers that are installed by django-pgtrigger. django-pgtrigger is now integrated with the migration system, so triggers will appear in migrations from now on.

Instructions for upgrading

After upgrading to version 2 of django-pghistory, the majority of people can simply run python manage.py makemigrations to make the migrations for the triggers. If, however, you are tracking third-party models, you will need to register trackers on proxy models. Otherwise trigger migrations will be created outside of your project.

Important - Please be sure you have django-pgtrigger>=4.5 installed, otherwise django-pghistory might be susceptible to some migration-related bugs

For example, this is how you can track changes to Django's user model:

  # Track the user model, excluding the password field
  @pghistory.track(
      pghistory.Snapshot('user.snapshot'),
      exclude=['password'],
  )
  class UserProxy(User):
      class Meta:
          proxy = True

The same syntax is also used for default many-to-many "through" models. For example, this is how one tracks changes to group add/remove events on the user model:

  from django.contrib.auth.models import User

  import pghistory


  # Track add and remove events to user groups
  @pghistory.track(
      pghistory.AfterInsert('group.add'),
      pghistory.BeforeDelete('group.remove'),
      obj_fk=None,
  )
  class UserGroups(User.groups.through):
      class Meta:
          proxy = True

Maintaining legacy behavior

If you want to disable django-pgtrigger integration with migrations entirely, set settings.PGTRIGGER_MIGRATIONS to False. Setting this along with settings.PGTRIGGER_INSTALL_ON_MIGRATE to True will preserve the legacy behavior of how triggers were installed. It is not recommend to do this

Other changes

Along with this, there is no longer a dependency on django-pgconnection. You no longer have to wrap settings.DATABASES with django-pgconnection after upgrading

Issues?

If you have any issues with the upgrade, please comment here and I will try to assist

wesleykendall avatar Aug 05 '22 15:08 wesleykendall

Thanks for offering the documentation. I did NOT upgrade to version 2 ( currently on 1.5.0 with Django 3.2). However, the migration failed recently, perhaps it still pull the latest pgtrigger 4. Thanks again for providing PGTRIGGER_MIGRATIONS for backward compatibility before I migrate to v2.

ValueError: Could not automatically serialize Trigger <class 'pghistory.trigger.Event'> for migrations. Implement "get_init_vals()" on the trigger class. See the FAQ in the django-pgtrigger docs for more information.

xjlin0 avatar Aug 20 '22 00:08 xjlin0

@xjlin0 yea that error will happen if you remain on pghistory<2 and pull in an upgraded pgtrigger. As you mentioned, the PGTRIGGER_MIGRATIONS=False should alleviate that issue if you want to get some of the latest bugfixes of pgtrigger and remain on pghistory<2 without using migrations to install triggers.

Thanks for reporting!

wesleykendall avatar Aug 26 '22 14:08 wesleykendall

Arrh, I just found that running 1.5.1 with PGTRIGGER_MIGRATIONS=False will get no errors but also no records in history table. Time to update....

xjlin0 avatar Sep 10 '22 19:09 xjlin0

@xjlin0 you need to set PGTRIGGER_MIGRATIONS to False and PGTRIGGER_INSTALL_ON_MIGRATE to True to preserve old behavior. My comment was missing a step

I'd still recommend upgrading to use the migration system, but the old behavior is there if you need it

wesleykendall avatar Sep 10 '22 20:09 wesleykendall

Thanks, I can confirm the above combination of both PGTRIGGER_MIGRATIONS False + PGTRIGGER_INSTALL_ON_MIGRATE True in settings can restore pghistory version 1 behavior of storing events.

Now I've successfully upgraded to pghistory version 2, it's nice to see trigger additions in the migrations. Everything works beautifully, except I still have some difficulties to show certain django_celery_beat models in Django Admin UI. Also, if anyone happened to use shell_plus, you may notice the proxy model loading error message upon shell plus start up. To suppress such error messages, you can skip proxy model loading for shell plus by adding settings something like:

SHELL_PLUS_DONT_LOAD = [
    'users.GroupProxy',
    'users.PermissionProxy',
    'users.UserGroupProxy',
    'users.UserPermissionProxy',
]

xjlin0 avatar Sep 20 '22 14:09 xjlin0

@xjlin0 thanks for letting us know! What loading error messages do you receive for those proxy models? If it's an error related to pghistory I can open up an issue

wesleykendall avatar Sep 20 '22 14:09 wesleykendall

Ha! proxy model loading error messages may not be related to pghistory, perhaps related to that Proxy model is still loaded by shell_plus by default. it's like:

$ python manage.py shell_plus

# Shell Plus Model Imports
Failed to import 'GroupProxy' from 'project.users.apps' reason: Module "project.users.apps" does not define a "GroupProxy" attribute/class
from django.contrib.auth.models import Group, Permission
.....

Regarding PeriodicTask & IntervalSchedule showing no events in Django Admin UI, I have no clues, since all other models shows events in Django Admin UI correctly with similar way.

from django_celery_beat.models import PeriodicTask
from django_celery_beat.admin import PeriodicTaskAdmin
admin.site.unregister(PeriodicTask)
@admin.register(PeriodicTask)       # Somehow Admin UI shows no events
class PeriodicTaskAdmin(PeriodicTaskAdmin):
    object_history_template = 'pghistory_template.html'
    def history_view(self, request, object_id, extra_context=None):   # same method from the doc
    .....

xjlin0 avatar Sep 20 '22 14:09 xjlin0