Django Rest Framework Tokens Are Not Being Automatically Generated - python

I am (trying) to use Django Rest Framework's Token-based authentication. I have the following in my app's models.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from django.conf import settings
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
Whenever I create a new account (either through 'createsuperuser' or by using my registration form), the user is correctly added to the 'auth_user' table. However, although the 'authtoken_token' table is created, there is nothing added to it. This leads me to believe that my #reciever may not be working properly.
I can however manually create tokens using the Django shell. Those tokens will be properly added to the authtoken_token table.
Any help on this would be greatly appreciated,
Thanks

Things to check:
Is the receiver even running? Add a print or log inside to check that it is called in the first place
If AUTH_USER_MODEL is not defined, you may need to use get_user_model() instead
Make sure that this code is inside the models.py file of an app that is in settings.INSTALLED_APPS
I've used DRF for several years and never had this problem. One of the above is likely your culprit.

Related

Django signals duplicate with unique dispatch id

I have a problem with duplicate signals. I have looked-up the relevant part of Django docs and a similar question on Stackoverflow but I still can't get it working right - i.e. the action that I have planned (creation on an ActivityLog entry) is actually happening 4 times :/
I have added the dispatch_uid and the problem still persists, so I guess I'm doing something wrong. Can you please hint me to the error?
Here's my code:
signals.py
from patient.models import Patient
from .models import ActivityLog
#receiver(pre_save, sender=Patient)
def create_new_patient(sender, instance, **kwargs):
ActivityLog.objects.create(
user=instance.created_by_user,
event='created a new patient',
patient_id=instance.patient_id
)
and this is it's usage in the patient.apps module:
from django.apps import AppConfig
from django.db.models.signals import pre_save
app_name = "patient"
class PatientConfig(AppConfig):
name = 'patient'
verbose_name = "Patients"
def ready(self):
from activity_logger.signals import create_new_patient
print('Patient APP is ready!')
pre_save.connect(create_new_patient, sender='patient.Patient', dispatch_uid='patient')
The print Patient APP is ready! does appear twice, and the object gets created 4 times, despite setting the dispatch_uid. What have I misunderstood?
The #receiver(Signal,...) decorator is a shortcut for Signal.connect(...), so you indeed register your create_new_patient handler twice (once thru #receiver when importing your signals module, the second time with pre_save.connect().
Solution : in your App.ready() method, you should just import your app's signal.py module. This will trigger the registration of the handlers decorated with #receiver.

adding custom permission through django-admin, while server is running

In Django-admin, Is it possible to make feature so that admin can create/edit/delete certain permission through django-admin while the server is running?
In django-admin I want the permission can be listed, with edit create and delete feature
Using permission in Meta subclass of models class will create custom permission through migrate script.
taken from https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#custom-permissions
class Task(models.Model):
...
class Meta:
permissions = (
("view_task", "Can see available tasks"),
("change_task_status", "Can change the status of tasks"),
("close_task", "Can remove a task by setting its status as closed"),
)
This will insert values on auth_permission (and django_content_type)
But that requires database migrations, which means unlikely be done by user (Admin) but by the developer instead. And I believe it is necessary for application to be able to manage permission, creating, editing, deleting while the server is running.
So what is the best practice to make this functionality with Django? Should I keep using migrate & create them all in each model and to reload server everytime we implement new permission or feature in general? thankyou
You can register the Permission model to admin view:
from django.contrib.auth.models import Permission
from django.contrib import admin
admin.site.register(Permission)
The code can be anywhere where it gets executed, but admin.py of your application could be an intuitive place to stick it in. After this, you will be able to view, edit and remove the permissions.
You also need to select_related because it will result in a bunch of SQL queries
from django.contrib import admin
from django.contrib.auth.models import Permission
#admin.register(Permission)
class PermissionAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('content_type')

Django 1.8: Function not called on Signal

I'm picking up on a code which should send a signal every time a user logs in. Thats not happening though. The function get_create_stripe() isnt getting called when the user logs in.
Anyone can tell whats wrong?
I'm working in Django 1.8 and the whole code is here.
Gist about the code: This code is part of an e-commerce site which users stripe as its payment gateway. Intent is, every time user logs in, we create a new stripe id or return an existing one.
Is it because this function is not in models.py? This is written to a file 'signals.py' and I'm not quite sure how Django should understand to call get_create_stripe() from a signal call in this file. Is it so?
import stripe
from django.conf import settings
from django.contrib.auth.signals import user_logged_in
from .models import UserStripe
stripe.api_key = settings.STRIPE_SECRET_KEY
def get_create_stripe(sender, user, *args, **kwargs):
new_user_stripe, created = UserStripe.objects.get_or_create(user=user)
print "hello"
if created:
customer = stripe.Customer.create(
email = str(user.email)
)
print customer
new_user_stripe.stripe_id = customer.id
new_user_stripe.save()
user_logged_in(get_create_stripe)
You need to connect your signal method to the signal.
Something like
from django.dispatch import receiver
from django.contrib.auth.signals import user_logged_in
#receiver(user_logged_in, sender=UserStripe)
def get_create_stripe(sender, user, *args, **kwargs):
EDIT: Also, what is this:
user_logged_in(get_create_stripe)
That is not how signals work. Either you do what I wrote above, or do this:
user_logged_in.connect(get_create_stripe)

How do I set a default group with django-authopenid?

I have a django app that uses django-authopenid as the sole registration method. I have registration in my installed apps, which django-authopenid uses. An ideal solution would allow me to run arbitrary code on the user object when they register. I can't directly modify the code for django-authopenis or registration.
Let me know if I need to add any more details.
On models.py you could bind the post_save signal:
from django.contrib.auth.models import User, Group
from django.db.models.signals import post_save
def default_group(sender, instance, created, **kwargs):
if created:
instance.groups.add(Group.objects.get(name='your default group name'))
post_save.connect(default_group, sender=User)
If in doubt, read the signals documentation.

Remove (or hide) default Permissions from Django

I'm developing a Django app that will have two administration backends. One for daily use by "normal" users and the default one for more advanced tasks and for the developers.
The application uses some custom permissions but none of the default ones. So I'm currently looking for a way to remove the default permissions, or at least a way to hide them from the "daily" admin backend without large modifications.
UPDATE: Django 1.7 supports the customization of default permissions
Original Answer
The following is valid for Django prior to version 1.7
This is standard functionality of the auth contrib application.
It handles the post_syncdb signal and creates the permissions (the standard 3: add, change, delete, plus any custom ones) for each model; they are stored in the auth_permission table in the database.
So, they will be created each time you run the syncdb management command
You have some choices. None is really elegant, but you can consider:
Dropping the auth contrib app and provide your own authentication backend.
Consequences -> you will lose the admin and other custom apps built on top of the auth User model, but if your application is highly customized that could be an option for you
Overriding the behaviour of the post_syncdb signal inside the auth app (inside \django\contrib\auth\management__init__.py file)
Consequences -> be aware that without the basic permissions the Django admin interface won't be able to work (and maybe other things as well).
Deleting the basic permissions (add, change, delete) for each model inside the auth_permission table (manually, with a script, or whatever).
Consequences -> you will lose the admin again, and you will need to delete them each time you run syncdb.
Building your own Permission application/system (with your own decorators, middlewares, etc..) or extending the existing one.
Consequences -> none, if you build it well - this is one of the cleanest solutions in my opinion.
A final consideration: changing the contrib applications or Django framework itself is never considered a good thing: you could break something and you will have hard times if you will need to upgrade to a newer version of Django.
So, if you want to be as clean as possibile, consider rolling your own permission system, or extending the standard one (django-guardian is a good example of an extension to django permissions). It won't take much effort, and you can build it the way it feels right for you, overcoming the limitations of the standard django permission system. And if you do a good work, you could also consider to open source it to enable other people using/improving your solution =)
I struggled with this same problem for a while and I think I've come up with a clean solution. Here's how you hide the permissions for Django's auth app:
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.contrib.auth.models import Permission
class MyGroupAdminForm(forms.ModelForm):
class Meta:
model = MyGroup
permissions = forms.ModelMultipleChoiceField(
Permission.objects.exclude(content_type__app_label='auth'),
widget=admin.widgets.FilteredSelectMultiple(_('permissions'), False))
class MyGroupAdmin(admin.ModelAdmin):
form = MyGroupAdminForm
search_fields = ('name',)
ordering = ('name',)
admin.site.unregister(Group)
admin.site.register(MyGroup, MyGroupAdmin)
Of course it can easily be modified to hide whatever permissions you want. Let me know if this works for you.
A new feature introduced in Django 1.7 is the ability to define the default permissions. As stated in the documentation if you set this to empty none of the default permissions will be created.
A working example would be:
class Blar1(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, unique = True, blank = False, null = False, verbose_name= "Name")
class Meta:
default_permissions = ()
ShadowCloud gave a good rundown. Here's a simple way to accomplish your goal.
Add these line in your admin.py:
from django.contrib.auth.models import Permission
admin.site.register(Permission)
You can now add/change/delete permissions in the admin. Remove the unused ones and when you have what you want, go back and remove these two lines from admin.py.
As was mentioned by others, a subsequent syncdb will put everything back.
Built on top of the solution by #pmdarrow, I've come up with a relatively clean solution to patch the Django admin views.
See: https://gist.github.com/vdboor/6280390
It extends the User and Group admin to hide certain permissions.
You can't easily delete those permissions (so that syncdb won't put them back), but you can hide them from the admin interface. The idea is, as described by others, to override the admin forms but you have to do this for both users and groups.
Here is the admin.py with the solution:
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User, Group
from django.contrib.auth.admin import GroupAdmin, UserAdmin
from django.contrib.auth.forms import UserChangeForm
#
# In the models listed below standard permissions "add_model", "change_model"
# and "delete_model" will be created by syncdb, but hidden from admin interface.
# This is convenient in case you use your own set of permissions so the list
# in the admin interface wont be confusing.
# Feel free to add your models here. The first element is the app name (this is
# the directory your app is in) and the second element is the name of your model
# from models.py module of your app (Note: both names must be lowercased).
#
MODELS_TO_HIDE_STD_PERMISSIONS = (
("myapp", "mymodel"),
)
def _get_corrected_permissions():
perms = Permission.objects.all()
for app_name, model_name in MODELS_TO_HIDE_STD_PERMISSIONS:
perms = perms.exclude(content_type__app_label=app_name, codename='add_%s' % model_name)
perms = perms.exclude(content_type__app_label=app_name, codename='change_%s' % model_name)
perms = perms.exclude(content_type__app_label=app_name, codename='delete_%s' % model_name)
return perms
class MyGroupAdminForm(forms.ModelForm):
class Meta:
model = Group
permissions = forms.ModelMultipleChoiceField(
_get_corrected_permissions(),
widget=admin.widgets.FilteredSelectMultiple(('permissions'), False),
help_text = 'Hold down "Control", or "Command" on a Mac, to select more than one.'
)
class MyGroupAdmin(GroupAdmin):
form = MyGroupAdminForm
class MyUserChangeForm(UserChangeForm):
user_permissions = forms.ModelMultipleChoiceField(
_get_corrected_permissions(),
widget=admin.widgets.FilteredSelectMultiple(('user_permissions'), False),
help_text = 'Hold down "Control", or "Command" on a Mac, to select more than one.'
)
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
admin.site.unregister(Group)
admin.site.register(Group, MyGroupAdmin)
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
If you are creating your own user management backend and only want to show your custom permissions you can filter out the default permissions by excluding permission with a name that starts with "Can".
WARNING:
You must remember not to name your permissions starting with "Can"!!!!
If they decide to change the naming convention this might not work.
With credit to pmdarrow this is how I did this in my project:
from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth.models import Permission
from django.contrib import admin
class UserEditForm(UserChangeForm):
class Meta:
model = User
exclude = (
'last_login',
'is_superuser',
'is_staff',
'date_joined',
)
user_permissions = forms.ModelMultipleChoiceField(
Permission.objects.exclude(name__startswith='Can'),
widget=admin.widgets.FilteredSelectMultiple(_('permissions'), False))
If you want to prevent Django from creating permissions, you can block the signals from being sent.
If you put this into a management/init.py in any app, it will bind to the signal handler before the auth framework has a chance (taking advantage of the dispatch_uid debouncing).
from django.db.models import signals
def do_nothing(*args, **kwargs):
pass
signals.post_syncdb.connect(do_nothing, dispatch_uid="django.contrib.auth.management.create_permissions")
signals.post_syncdb.connect(do_nothing, dispatch_uid="django.contrib.auth.management.create_superuser")

Categories

Resources