Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes Required for Compatibility with Django 2.0 #154

Merged
merged 8 commits into from
Jan 2, 2018

Conversation

rodmanning
Copy link
Contributor

Changes as noted in #153 for compatibility with django v2.0. All tox tests I can run are passing (but py27-django-111 is refusing to run for me due to a dependancy problem as functools apparently doesn't like me today ...)

Still have to add in the migrations — let me know if you want them sequential or squashed.

Made the following changes to ensure compatibility with django 2.0:

1. Replaced function calls to `is_authenticated()` with reference to
   property `is_authenticated`.

2. Added try/except call to import `django.core.urlresolvers` (now
   called `django.urls`.

   Also added an `... as ...` statement to ensure that references in the
   code to `urlresolvers` don't need to be changed.

3. Fixed calls statement of `on_delete` arg to all ForeignKey
   fields.

   Note that previously a kwarg was acceptable, but this is now a
   positional arg, and the selected `on_delete` method has been
   retained.

Signed-off-by: Rod Manning <[email protected]>
Updated tox.ini to also test django 2.0 on python 3+. Some changes made
to previous commits required to ensure all tests passed:

- Added `compat.py` to have a `is_authenticated()` function to check
  authentication.

  This was necessary as the property/method call for `is_authenticated`
  is no compatible between django 1.8 (LTS) and 2.0.

  Changed AuditLogMiddleware to call this compatibility function instead
  of the django built-ins as a result.

- Changes made to `auditlog/models.py` to apply kwargs to both `to=` and
  `on_delete=` for consistency of handling in all version tested.

Signed-off-by: Rod Manning <[email protected]>
Incorrect django version specified for tox.ini. Now fixed.

Signed-off-by: Rod Manning <[email protected]>
@codecov-io
Copy link

codecov-io commented Dec 6, 2017

Codecov Report

Merging #154 into master will decrease coverage by 0.32%.
The diff coverage is 60%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #154      +/-   ##
==========================================
- Coverage   69.15%   68.82%   -0.33%     
==========================================
  Files          18       19       +1     
  Lines         483      494      +11     
==========================================
+ Hits          334      340       +6     
- Misses        149      154       +5
Impacted Files Coverage Δ
src/auditlog/migrations/0001_initial.py 100% <ø> (ø) ⬆️
src/auditlog/mixins.py 0% <0%> (ø) ⬆️
src/auditlog/middleware.py 71.42% <100%> (+0.69%) ⬆️
src/auditlog/models.py 81.21% <100%> (ø) ⬆️
src/auditlog/compat.py 71.42% <71.42%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e33aef8...e56fe55. Read the comment docs.

Added and re-arranged 'on_delete' and 'to' kwargs in initial migration
to ensure compatbility with later versions of Django.

Also included updated manifest with changes required due to django 2.0
work.

Signed-off-by: Rod Manning <[email protected]>
Added simple test case for compat.py file.

Signed-off-by: Rod Manning <[email protected]>
@audiolion
Copy link
Contributor

hey, been on vacation, looks like everything here is done in a sane way and how I would do it. Gonna ping @jjkester for a review

Copy link
Collaborator

@jjkester jjkester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks! I spotted one minor think I would like to have fixed, plus there are some questions that don't necessarily require a change.


Function provides compatibility following deprecation of method call to
is_authenticated() in Django 2.0.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superfluous new line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the end of the block? Fixed/removed.


"""

if django.VERSION < (1, 10):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works perfectly, however, checking if user.is_authenticated is callable might work too.

No need to change this (obviously) unless you'd like to, kind of a personal preference I guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem to change it (tested change and all OK).

Thought behind the original version was to make it clear why the code existed — that way when you drop support for <1.10 in the future it's more obvious what code can be removed from compat.py.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personally id prefer the if django.VERSION < (1, 10) code for the reason stated, it lets you know when you can drop it in the compat, whereas looking at the new code I have no idea why it was added or what versions of django it makes compatible without added comments.

@@ -41,7 +42,7 @@ def process_request(self, request):
threadlocal.auditlog['remote_addr'] = request.META.get('HTTP_X_FORWARDED_FOR').split(',')[0]

# Connect signal for automatic logging
if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated') and request.user.is_authenticated():
if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated') and is_authenticated(request.user):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the attribute check can be combined with the compat function (and just return False if we don't know)? Just an idea, not sure if this would be practical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, have changed as suggested and all tested OK.

Consideration was to avoid adding logic to compat.py so that it can eventually be removed when <1.10 isn't supported.

@@ -24,8 +24,8 @@ class Migration(migrations.Migration):
('action', models.PositiveSmallIntegerField(verbose_name='action', choices=[(0, 'create'), (1, 'update'), (2, 'delete')])),
('changes', models.TextField(verbose_name='change message', blank=True)),
('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='timestamp')),
('actor', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='actor', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
('content_type', models.ForeignKey(related_name='+', verbose_name='content type', to='contenttypes.ContentType')),
('actor', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, related_name='+', verbose_name='actor', blank=True, null=True)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this change come from? It kind of makes no sense to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below.

('actor', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='actor', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
('content_type', models.ForeignKey(related_name='+', verbose_name='content type', to='contenttypes.ContentType')),
('actor', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, related_name='+', verbose_name='actor', blank=True, null=True)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', related_name='+', verbose_name='content type')),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this migration is edited?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. content_type requires on_delete kwargs in django 2.0 (see Django 2.0 changelog)
File "/home/rod/src/git/django-auditlog.git/src/auditlog/migrations/0001_initial.py", line 30, in Migration
    ('content_type', models.ForeignKey(related_name='+', verbose_name='content type', to='contenttypes.ContentType')),
TypeError: __init__() missing 1 required positional argument: 'on_delete'
⋮
ERROR:   py34-django-20: commands failed
ERROR:   py35-django-20: commands failed
ERROR:   py36-django-20: commands failed
  1. actor changes not intentional, so have reverted that line (think that might've been how it was auto generated by manage.py makemigrations, which I copied-pasted =)

Django 2.0 changelog suggests squashing migrations to manage this, and I'd support that approach.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. I'm also for squashing migrations, however, I'm not sure about the implications of squashing for existing installs. Should be a separate issue anyways I guess.

if django.VERSION < (1, 10):
if not hasattr(user, 'is_authenticated'):
return False
if hasattr(user.is_authenticated, "__call__"):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to use callable() for this check: https://bugs.python.org/issue10518#msg122584

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, no problem. Am away for a few days but will either see if I can edit it through github or do it when I’m back.

(You’re sure you want to check callable() instead of the version?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't hear back, so changed as suggested.

('actor', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='actor', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
('content_type', models.ForeignKey(related_name='+', verbose_name='content type', to='contenttypes.ContentType')),
('actor', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, related_name='+', verbose_name='actor', blank=True, null=True)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', related_name='+', verbose_name='content type')),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. I'm also for squashing migrations, however, I'm not sure about the implications of squashing for existing installs. Should be a separate issue anyways I guess.

@@ -6,10 +6,10 @@ def is_authenticated(user):

Function provides compatibility following deprecation of method call to
is_authenticated() in Django 2.0.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per your comment, maybe add info here that this is only required for Django 1.10 and older.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Added detail to both comment and in-line in the code as well.

Note that this is only needed for 1.9 and earlier (django 1.10 accepts is_authenticated as a property (1.10 release notes)).

@@ -25,7 +25,8 @@ class Migration(migrations.Migration):
('changes', models.TextField(verbose_name='change message', blank=True)),
('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='timestamp')),
('actor', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='actor', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
('content_type', models.ForeignKey(related_name='+', verbose_name='content type', to='contenttypes.ContentType')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, related_name='+', verbose_name='content type', to='contenttypes.ContentType')),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rodmanning There should be the same deletion mode (CASCADE, I guess) as in the model itself, otherwise it leads to an additional redundant migration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 👍 Didn't notice that — now fixed.

1. Added detailed commentary to `compat.py` to ensure reason why
   `is_authenticated()` compatibility function is needed

2. Changed `hasattr` to `callable` in compat.is_authenticated()

3. Fixed typo in migration 0001 to use correct `on_delete` function

Signed-off-by: Rod Manning <[email protected]>

This is *only* required to support Django < v1.10 (i.e. v1.9 and earlier),
as `is_authenticated` was introduced as a property in v1.10.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another one of those newlines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

@@ -25,7 +25,8 @@ class Migration(migrations.Migration):
('changes', models.TextField(verbose_name='change message', blank=True)),
('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='timestamp')),
('actor', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='actor', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
('content_type', models.ForeignKey(related_name='+', verbose_name='content type', to='contenttypes.ContentType')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', verbose_name='content type', to='contenttypes.ContentType')),

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superfluous newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

@audiolion audiolion dismissed jjkester’s stale review January 2, 2018 18:44

all review comments have been addressed

@lamby
Copy link

lamby commented Jan 2, 2018

Thanks :)

@robguttman
Copy link
Contributor

Thank you for this! When can we expect a 0.4.5 with these changes?

@jjkester
Copy link
Collaborator

jjkester commented Jan 8, 2018

I'll try to get it released this week.

@robguttman
Copy link
Contributor

Ping - any chance that a 0.4.5 can still happen this week?

@jjkester
Copy link
Collaborator

Thanks for the ping. I had not forgotten about it. I'm just having a bit of a overwhelming week. I have just pushed 0.4.5 to PyPI, it should appear shortly on GitHub as well. Thanks for your patience!

@robguttman
Copy link
Contributor

Thanks, Jan-Jelle! This allows us to upgrade to Django 2.0 fully now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants