Removing django default permissions from auth models - python

guys im trying to remove default django permissions i'll never use in my project but with no success. When I make migration it states that migration is made with success but there's no effect, like it skipped the function. I'm pretty sure code is ok because i tested it in shell. Any ideas?
Here's code for migration:
from django.db import migrations
def remove_redundant_permissions(apps, schema_editor):
Permission = apps.get_model('auth.Permission')
app_labels = ['admin', 'reversion', 'contenttypes', 'sessions', 'sites']
Permission.objects.filter(content_type__app_label__in=app_labels).delete()
class Migration(migrations.Migration):
dependencies = [
('users', '0014_auto_20160808_0738'),
]
operations = [
migrations.RunPython(remove_redundant_permissions),
]

Django's permessions are generated with post_migrate signal. This means even if you delete them in migration they will be regenerated after migration completes.
Here is code from django
# django/contrib/auth/apps.py
from django.apps import AppConfig
from django.contrib.auth.checks import check_user_model
from django.core import checks
from django.db.models.signals import post_migrate
from django.utils.translation import ugettext_lazy as _
from .management import create_permissions
class AuthConfig(AppConfig):
name = 'django.contrib.auth'
verbose_name = _("Authentication and Authorization")
def ready(self):
post_migrate.connect(create_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions")
checks.register(check_user_model, checks.Tags.models)
As you see auth app has this AppConfig which regenerates permissions with create_permissions function.
Why do you want to delete default django permissions? Do they block you from doing something?

Related

Django Guardian with Data Migration (adding Anonymous user to public group)

I'm trying to perform a data migration in an app. I would like to add the anonymous user (the django-guardian AnonymousUser) to a public group. Somehow the user does not exist when i'm running test (test database migrations fail with user matching query does not exist). It does work with my development database. Thanks in advance.
As it seems that the anonymous user is created on management init, I tried to import the module in apply_migration without success.
# Generated by Django 4.1 on 2022-10-19 12:11
from django.db import migrations
from guardian.utils import get_anonymous_user
from recipebook.settings import PUBLIC_GROUP_NAME
from django.contrib.auth.models import Group
def apply_migration(apps, schema_editor):
import guardian.management.__init__
public_group = Group.objects.get(
name=PUBLIC_GROUP_NAME
)
user = get_anonymous_user()
user.groups.add(public_group)
def revert_migration(apps, schema_editor):
public_group = Group.objects.get(
name=PUBLIC_GROUP_NAME
)
user = get_anonymous_user()
user.groups.remove(public_group)
class Migration(migrations.Migration):
dependencies = [
('recipebook', '0031_recipenutrition'),
('guardian', '0001_initial'),
]
operations = [
migrations.RunPython(apply_migration, revert_migration)
]

Migration references dynamic storage inconsistent

I want specific field in model to use either S3 storage (if settings has AWS_ACCESS_KEY_ID) or fallback to default_storage. I'm using django-storages.
To implement this, in models.py:
from django.db import models
from django.conf import settings
from .storage_backends import variativeStorage
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
photo = models.ImageField(upload_to='/public', default='dummy-img.png', storage=variativeStorage())
storage_backends.py:
from storages.backends.s3boto3 import S3Boto3Storage
from django.core.files.storage import default_storage
from django.conf import settings
def variativeStorage():
"""Return S3Boto3Storage if access key is defined.
Fallback to default storage.
"""
if hasattr(settings, 'AWS_ACCESS_KEY_ID') and settings.AWS_ACCESS_KEY_ID:
return S3Boto3Storage()
return default_storage
It works great, but the problem is in migrations - it evaluates field storage on which django settings it currently has. So in case we don't have AWS_ACCESS_KEY_ID, makemigrations will do:
operations = [
migrations.AlterField(
model_name='profile',
name='photo',
field=models.ImageField(default='dummy-img.png', upload_to='/public'),
),
]
and in case it has:
operations = [
migrations.AlterField(
model_name='profile',
name='photo',
field=models.ImageField(default='dummy-img.png', storage=storages.backends.s3boto3.S3Boto3Storage(), upload_to='/public'),
),
]
So running server on production will trigger warning for missing migrations:
remote: Running migrations:
remote: No migrations to apply.
remote: Your models have changes that are not yet reflected in a migration, and so won't be applied.
remote: Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
Is there a consistent way of doing dynamic storage for field? How can I make lazy-evaluation of variativeStorage or maybe remove migration generation for that particular field?

Using Django signals to identify a present user session

i want to use django signals to identify if a user is logged-in twice and if so, revoke his first session so that only one user session can be present at once.
i used the following example but it seems that my signals.py does not even gets reconcnized and i dont know why.
Example:
How to prevent multiple login in Django
accounts/signals.py
from django.contrib.auth import user_logged_in
from django.dispatch.dispatcher import receiver
from django.contrib.sessions.models import Session
from .models import UserSession
#receiver(user_logged_in)
def remove_other_sessions(sender, user, request, **kwargs):
# remove other sessions
Session.objects.filter(usersession__user=user).delete()
# save current session
request.session.save()
# create a link from the user to the current session (for later removal)
UserSession.objects.get_or_create(
user=user,
session=Session.objects.get(pk=request.session.session_key)
)
accounts/models.py
# Model to store the list of logged in users
class UserSession(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
session = models.OneToOneField(Session, on_delete=models.CASCADE)
accounts/apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'Accounts'
def ready(self):
import Accounts.signals
but for some reason nothing gets written onto the database for that table.
do i maybe miss something here, this is the very first time i get in touch with signals so i might missed something at the configuration.
Try this,
default_app_config = 'Accounts.apps.AccountsConfig'
Add this line in __init__.py file of your apps.py file directory.

Where in Django can I run startup code that requires models?

On Django startup I need to run some code that requires access to the database. I prefer to do this via models.
Here's what I currently have in apps.py:
from django.apps import AppConfig
from .models import KnowledgeBase
class Pqawv1Config(AppConfig):
name = 'pqawV1'
def ready(self):
to_load = KnowledgeBase.objects.order_by('-timestamp').first()
# Here should go the file loading code
However, this gives the following exception:
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
So is there a place in Django to run some startup code after the models are initialized?
The problem is that you import .models at the top of your file. This means that, when the file app.py file is loaded, Python will load the models.py file when it evalutes that line. But that is too early. You should let Django do the loading properly.
You can move the import in the def ready(self) method, such that the models.py file is imported when ready() is called by the Django framework, like:
from django.apps import AppConfig
class Pqawv1Config(AppConfig):
name = 'pqawV1'
def ready(self):
from .models import KnowledgeBase
to_load = KnowledgeBase.objects.order_by('-timestamp').first()
# Here should go the file loading code

How to avoid dependency injection in Django?

I'm trying to figure out how to avoid dependency injection in my project. There is a file notifications.py in app directory.
File notifications.py contains methods for sending emails to admin and users. To get admins email, I need to check object of SystemData model. But in models, I use notifications.
models
class SystemData(models.Model):
admin_alerts_email = models.EmailField(verbose_name=u'Emailová adresa admina')
contact_us_email = models.EmailField(verbose_name=u'Adresa kontaktujte nás')
waiting_threshold = models.PositiveSmallIntegerField(verbose_name=u'Maximálny počet minút čakania')
class SomeModel(models.Model):
....
def save(...):
notifications.send_message_to_admin('message')
notifications.py
from django.core.mail import EmailMessage
from models import SystemData
def send_message_to_admin(message):
mail = EmailMessage(subject, message, to=[SystemData.objects.all().first().admin_email])
mail.send()
Django returns that it can't import SystemData.
Do you know what to do?
EDIT:
stacktrace
You can solve circular dependencies in functions by using inline imports:
class SomeModel(models.Model):
....
def save(...):
from .notifications import send_message_to_admin
send_message_to_admin('message')
This will delay the import statement until the function is actually executed, so the models module has already been loaded. The notifications module can then safely import the models module.
Apart from using circular imports you can either do it like that:
from django.core.mail import EmailMessage
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import SystemData, SomeModel
#receiver(post_save, sender=SomeModel)
def send_message_to_admin(sender, instance, created, **kwargs):
message = 'message'
mail = EmailMessage(
subject,
message,
to=[SystemData.objects.all().first().admin_email]
)
mail.send()
and at the end of models.py put
from .notifications import *
or use newest approach with AppConfig to register signals (that's what your notifications actually do)
see: https://chriskief.com/2014/02/28/django-1-7-signals-appconfig/
that way it will load when app registry is ready and you'll avoid circular imports, so that line:
from .notifications import *
can be dropped from models.py
AppConfig can be used in a more generic way as well allowing you to import models like that:
from django.apps import apps
Model = apps.get_model('app_name', 'Model')

Categories

Resources