django bulk user import user django-import-export - django

i want use import export to bulk user import in django
i get a file include list of users then create users according to file rows
i try implement before_import like this
from import_export import resources
class UserResource(resources.ModelResource):
def before_import(self,dataset, dry_run, **kwargs):
#dataset is tablib.Dataset()
for i in dataset:
i[1]=make_password(i[1])
return super(UserResource, self).before_import(dataset, dry_run, **kwargs)
but it return tuple' object does not support item assignment

For Passwords you could write your own password widget, which turns the plain password into a hash. Like this (untested):
class PassWidget(Widget):
def clean(self, value):
if self.is_empty(value):
return None
return make_password(value)
def render(self, value):
return force_text(value)

I hope you are trying to hash your password before importing.
it helps you:
from import_export import resources, fields
from import_export.admin import ImportExportModelAdmin
from django.contrib.auth.hashers import make_password
class UserResource(resources.ModelResource):
groups = fields.Field(
column_name='group_name',
attribute='groups',
widget=ManyToManyWidget(Group, ',','name')
)
def before_import_row(self,row, **kwargs):
value = row['password']
row['password'] = make_password(value)
class Meta:
model = User

Related

flask-admin "AdminIndexView" not working to restrict the /admin page

this is my first question in stackoverflow.
i need to change flask_admin's default page but it's not working, i want to make it inaccessible for non-admin users...
admin file:
from flask import redirect, url_for
from flask_admin import AdminIndexView
from flask_admin.contrib.sqla import ModelView
from flask_login import current_user
from wtforms.fields import FileField
from wtforms.validators import DataRequired
from . import adm, db
from .models import User, Product
def configure():
adm.index_view = IndexAdmin()
adm.add_view(UserAdmin(User, db.session))
adm.add_view(ProductsAdmin(Product, db.session))
class IndexAdmin(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("views.home_page"))
class UserAdmin(ModelView):
form_excluded_columns = ["created_date", "updated_date", "products", "adresses"]
column_exclude_list = ["password", "phone", "money"]
column_searchable_list = ["email"]
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("admin.index"))
class ProductsAdmin(ModelView):
form_excluded_columns = ["created_date", "updated_date", "user_products"]
column_exclude_list = ["image"]
column_type_formatters = {"image": FileField(label="Image", validators=[DataRequired()])}
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("admin.index"))
I tried to do this to put the page restrict, but this isn't working...
class IndexAdmin(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("views.home_page"))
I'm not certain this is the gap, but the official docs do not suggest setting this as you are with adm.index_view =. Instead https://flask-admin.readthedocs.io/en/latest/api/mod_base/#default-view suggests:
admin = Admin(index_view=MyHomeView())
So, one possibility is that the init process for Admin() does something with the index_view that doesn't happen when you set it directly.
The docs (https://flask-admin.readthedocs.io/en/latest/api/mod_base/#flask_admin.base.Admin.init_app) also indicate that you can delay this by using init_app, which is the way I've used it before. Something like:
admin.init_app(app, index_view= MyHomeView())

Unable to get image data in an API along with json data for registration

I want to create a register API in which I have username,email, password input along with an image field.I am unable to receive and process the data properly.The default user class is extended to store image field.
I have this extended user model:-
from django.contrib.auth.models import User
import os
def get_upload_path(instance, filename):
fileName, fileExtension = os.path.splitext(filename)
return os.path.join("user_%s" % instance.user.username,"user_{0}.{1}" .format(instance.user.username,fileExtension))
# Create your models here.
class Userprofile(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE)
display_picture=models.ImageField(upload_to=get_upload_path)
has_voted=models.BooleanField(default=False)
voted_item=models.CharField(max_length=200,default='none')
def __str__(self):
return self.user.username
These are the serializers:-
from django.contrib.auth.models import User
from .models import Userprofile
class UserprofileSerializer(serializers.ModelSerializer):
class Meta:
model=Userprofile
fields=['display_picture']
class UserSerializer(serializers.ModelSerializer):
class Meta:
model=User
fields=['username','email','password1','password2']
this is the path/url:-
path('register',views.FileUploadView.as_view(),name='Register'),
this is the view:-
#csrf_exempt
class FileUploadView(APIView):
parser_classes=[MultiPartParser,FormParser]
def register(self,request):
display_picture=request.FILES["display_picture"]
data=json.loads(request.data["data"])
#saving data using serializers
return JsonResponse({'message': "Registered Successfully!"},status=200)
I am getting this issue which says:-
path('register',views.FileUploadView.as_view(),name='Register'),
AttributeError: 'function' object has no attribute 'as_view'
You are decorating a class like a function,thats why your code is breaking.
In order to use a decorator on a class, you can do either of the two approaches:
1) Decorating the class:
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
#method_decorator(csrf_exempt,name='dispatch')
class FileUploadView(APIView):
parser_classes=[MultiPartParser,FormParser]
def register(self,request):
display_picture=request.FILES["display_picture"]
data=json.loads(request.data["data"])
#saving data using serializers
return JsonResponse({'message': "Registered Successfully!"},status=200)
2) Decorating in URL only:
from django.views.decorators.csrf import csrf_exempt
path('register',csrf_exempt(view.FileUploadView.as_view()))
You can read in detail here.

Adding custom functionality to django router methods

I'm trying to add custom functionality to django router methods.
This is my router that exposes the standard methods on an user.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [BasePermission]
I'm validating the user using serializer validation methods.
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
MOBILE_ERROR = 'Mobile number should be 10 digits long and only contain numbers.'
EMAIL_ERROR = 'Incorrect email format'
USERNAME_ERROR = 'Username must be at least 6 characters long and contain only letters and numbers.'
class Meta:
model = User
fields = '__all__'
def validate_mobile(self, value):
regexp = re.compile(r'^[0-9]{10}$')
if regexp.search(value):
return value
raise serializers.ValidationError(self.MOBILE_ERROR)
def validate_email(self, value):
if validate_email(value):
return value
raise serializers.ValidationError(self.EMAIL_ERROR)
def validate_username(self, value):
regexp = re.compile(r'^[a-zA-Z0-9]{6,}$')
if regexp.search(value):
return value
raise serializers.ValidationError(self.USERNAME_ERROR)
And this is my route.
router = DefaultRouter(trailing_slash=False)
router.register(r'user', UserViewSet),
urlpatterns = router.urls
I want to add a method send_activation_code if the user is created successfully. How do I do this?
For such purpose you can use signals. Every time when your app creates new User instance - some action should be performed. In your case you should connect build-in signal post_save and your existed send_activation_code function
Example for your case:
yourapp/signals.py:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def send_activation_code_signal(sender, instance, created, **kwargs):
if created:
send_activation_code(instance.phone_number)
Also, you need to import signals in your app config file
yourapp/app.py:
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class YourAppConfig(AppConfig):
name = 'yourproject.yourapp'
verbose_name = _('yourapp')
def ready(self):
import yourproject.yourapp.signals
yourapp/__init__.py:
default_app_config = 'yourproject.yourapp.apps.YourAppConfig'
If you dont need to send code every time User instance created - you can specify more statements, for example:
if created and instance.validated:
send_activation_code(instance.phone_number)
There are some more useful built-in signals in Django, check docs
Django signals docs: https://docs.djangoproject.com/en/3.0/ref/signals/

Django: change admin FileField output?

I've made a model with file that is uploaded to custom path (not in MEDIA_ROOT). So it's some kind like protected file.
Now I need to change it's representation in admin details. It shows a path relative to MEDIA_URL. I need to change that, to show a URL to an application view which generates a proper URL.
So, what is the best way to display link, and only in objects details in admin?
Here is the way I did it:
models.py
class SecureFile(models.Model):
upload_storage = FileSystemStorage(
location=settings.ABS_DIR('secure_file/files/'))
secure_file = models.FileField(verbose_name=_(u'file'),
upload_to='images', storage=upload_storage)
widgets.py
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
class AdminFileWidget(forms.FileInput):
"""A FileField Widget that shows secure file link"""
def __init__(self, attrs={}):
super(AdminFileWidget, self).__init__(attrs)
def render(self, name, value, attrs=None):
output = []
if value and hasattr(value, "url"):
url = reverse('secure_file:get_secure_file',
args=(value.instance.slug, ))
out = u'{}<br />{} '
output.append(out.format(url, _(u'Download'), _(u'Change:')))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
admin.py
class SecureFileAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SecureFileAdminForm, self).__init__(*args, **kwargs)
self.fields['secure_file'].widget = AdminFileWidget()
class Meta:
model = SecureFile
class SecureFileAdmin(admin.ModelAdmin):
form = SecureFileAdminForm

Django Admin linking to related objects

My app has users who create pages. In the Page screen of the admin, I'd like to list the User who created the page, and in that list, I'd like the username to have a link that goes to the user page in admin (not the Page).
class PageAdmin(admin.ModelAdmin):
list_display = ('name', 'user', )
list_display_links = ('name','user',)
admin.site.register(Page, PageAdmin)
I was hoping that by making it a link in the list_display it would default to link to the actual user object, but it still goes to Page.
I'm sure I'm missing something simple here.
Modifying your model isn't necessary, and it's actually a bad practice (adding admin-specific view-logic into your models? Yuck!) It may not even be possible in some scenarios.
Luckily, it can all be achieved from the ModelAdmin class:
from django.urls import reverse
from django.utils.safestring import mark_safe
class PageAdmin(admin.ModelAdmin):
# Add it to the list view:
list_display = ('name', 'user_link', )
# Add it to the details view:
readonly_fields = ('user_link',)
def user_link(self, obj):
return mark_safe('{}'.format(
reverse("admin:auth_user_change", args=(obj.user.pk,)),
obj.user.email
))
user_link.short_description = 'user'
admin.site.register(Page, PageAdmin)
Edit 2016-01-17:
Updated answer to use make_safe, since allow_tags is now deprecated.
Edit 2019-06-14:
Updated answer to use django.urls, since as of Django 1.10 django.core.urls has been deprecated.
Add this to your model:
def user_link(self):
return '%s' % (reverse("admin:auth_user_change", args=(self.user.id,)) , escape(self.user))
user_link.allow_tags = True
user_link.short_description = "User"
You might also need to add the following to the top of models.py:
from django.template.defaultfilters import escape
from django.core.urls import reverse
In admin.py, in list_display, add user_link:
list_display = ('name', 'user_link', )
No need for list_display_links.
You need to use format_html for modern versions of django
#admin.register(models.Foo)
class FooAdmin(admin.ModelAdmin):
list_display = ('ts', 'bar_link',)
def bar_link(self, item):
from django.shortcuts import resolve_url
from django.contrib.admin.templatetags.admin_urls import admin_urlname
url = resolve_url(admin_urlname(models.Bar._meta, 'change'), item.bar.id)
return format_html(
'{name}'.format(url=url, name=str(item.bar))
)
I ended up with a simple helper:
from django.shortcuts import resolve_url
from django.utils.safestring import SafeText
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.utils.html import format_html
def model_admin_url(obj: Model, name: str = None) -> str:
url = resolve_url(admin_urlname(obj._meta, SafeText("change")), obj.pk)
return format_html('{}', url, name or str(obj))
Then you can use the helper in your model-admin:
class MyAdmin(admin.ModelAdmin):
readonly_field = ["my_link"]
def my_link(self, obj):
return model_admin_url(obj.my_foreign_key)
I needed this for a lot of my admin pages, so I created a mixin for it that handles different use cases:
pip install django-admin-relation-links
Then:
from django.contrib import admin
from django_admin_relation_links import AdminChangeLinksMixin
#admin.register(Group)
class MyModelAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
# ...
change_links = ['field_name']
See the GitHub page for more info. Try it out and let me know how it works out!
https://github.com/gitaarik/django-admin-relation-links
I decided to make a simple admin mixin that looks like this (see docstring for usage):
from django.contrib.contenttypes.models import ContentType
from django.utils.html import format_html
from rest_framework.reverse import reverse
class RelatedObjectLinkMixin(object):
"""
Generate links to related links. Add this mixin to a Django admin model. Add a 'link_fields' attribute to the admin
containing a list of related model fields and then add the attribute name with a '_link' suffix to the
list_display attribute. For Example a Student model with a 'teacher' attribute would have an Admin class like this:
class StudentAdmin(RelatedObjectLinkMixin, ...):
link_fields = ['teacher']
list_display = [
...
'teacher_link'
...
]
"""
link_fields = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.link_fields:
for field_name in self.link_fields:
func_name = field_name + '_link'
setattr(self, func_name, self._generate_link_func(field_name))
def _generate_link_func(self, field_name):
def _func(obj, *args, **kwargs):
related_obj = getattr(obj, field_name)
if related_obj:
content_type = ContentType.objects.get_for_model(related_obj.__class__)
url_name = 'admin:%s_%s_change' % (content_type.app_label, content_type.model)
url = reverse(url_name, args=[related_obj.pk])
return format_html('{}', url, str(related_obj))
else:
return None
return _func
If anyone is trying to do this with inline admin, consider a property called show_change_link since Django 1.8.
Your code could then look like this:
class QuestionInline(admin.TabularInline):
model = Question
extra = 1
show_change_link = True
class TestAdmin(admin.ModelAdmin):
inlines = (QuestionInline,)
admin.site.register(Test, TestAdmin)
This will add a change/update link for each foreign key relationship in the admin's inline section.