Flask-admin with mongoengine show roles as 'Role object' instead of the respective role name - mongoengine

I am using flask-security and is now adding flask-admin.
I have my user view and my roles view.
I can create users and roles.
But the roles don't show as the respective role names in the user dropdown menu. All roles just shows as "Role object".
I am using Mongoengine.
models:
class Role(db.Document, RoleMixin):
name = db.StringField(max_length=80, unique=True)
description = db.StringField(max_length=255)
permissions = db.StringField(max_length=255)
class User(db.Document, UserMixin):
username = db.StringField(max_length=255)
password = db.StringField(max_length=255)
active = db.BooleanField(default=True)
fs_uniquifier = db.StringField(max_length=64, unique=True)
confirmed_at = db.DateTimeField()
current_login_at = db.DateTimeField()
last_login_at = db.DateTimeField()
current_login_ip = db.StringField(max_length=255)
last_login_ip = db.StringField(max_length=255)
login_count = db.IntField(max_length=255)
roles = db.ListField(db.ReferenceField(Role), default=[])
user_datastore = MongoEngineUserDatastore(db, User, Role)
flask admin views:
admin = Admin(app, name='ADMIN', template_mode='bootstrap3')
admin.add_view(ModelView(User))
admin.add_view(ModelView(Role))
As you see in the below screenshots, the first one is the created roles "Admin" and "test".
But when I try to assign the roles to a user in flask-admin the roles only shows as "Role object".
Roles created:
Assign roles:

Try adding:
def str(self):
return self.name
to your Role model
You might also need to add str to your User model as well.

Related

Django Pass Extra Information To ManyToMany Model Signal

i have a manytomany django related models which needs an entry created automatically when one model is created using signals. my challenge is passing extra information to the signal for the intermediate Team model table?
class Listing(models.Model):
"""
The Listing Model
"""
# model fields --> [name, description, email, phone]
team = models.ManyToManyField(User, through = 'Team')
class Team(models.Model):
"""
A Group Of Users To Manage A Listing
"""
AUTHOR = 'Author'
EDITOR = 'Editor'
ROLE_CHOICES = [(AUTHOR, 'Author'), (EDITOR, 'Editor')]
listing = models.ForeignKey(Listing, on_delete = models.RESTRICT, related_name = 'businesses')
author = models.ForeignKey(User, on_delete = models.RESTRICT, related_name = 'buddies')
role = models.CharField(max_length = 10, choices = ROLE_CHOICES, default = EDITOR)
#receiver(post_save, sender = Listing)
def create_team(sender, instance, created, **kwargs):
if created:
Team.objects.create(listing = instance, author = instance.author, role = 'Author') # <-- How To Pass User Instance To Signal?!
How do i pass the user instance to the signal to create author for the listing?
for example Listing.objects.create(..., author = user) to create the Listing and it's Author(User)?
Edit
A Listing is created by a User, who is assigned the role of 'Author' and is part of the Team to manage the Listing. so whenever i call Listing.objects.create(), how can i pass the user to the model to create the Team as well using the signal create_team, else the listing will be without a User i.e Author

Custom User Model with multiple Unique id - Django RestFramework

Hi StackOverFlow buddies,
I have created a custom User model for my project and would like to register the Users with Restframework.
I want Custom User model to have 2 unique fields together, for which I followed "Official doc" for unique_together property. It seems to be only taking only 1 field (ie email for my case), as a unique one.
Relevant piece my code until this point looks like this:
PS: Let me know if more info is required.
models.py
class MasterUser(AbstractBaseUser):
email = models.EmailField(verbose_name='email address',max_length=255,unique=True,)
firstname = models.CharField(max_length=100,blank=True)
contact = models.CharField(max_length=100, blank=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['firstname']
class Meta:
unique_together = (('email', 'contact'),)
serializer.py
class RegisterUserSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type': 'password'}, write_only= True)
class Meta:
model = MasterUser
fields = ('firstname', 'password', 'password2', 'email','contact')
extra_kwargs = {
'password': {'write_only': True},
}
def save(self):
account = MasterUser(
email = self.validated_data['email'],
firstname = self.validated_data['firstname'],
contact = self.validated_data['contact'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Password doesnt matches'})
account.set_password(password)
account.save()
return account
views.py
#api_view(['POST'])
def registration_view(request):
if request.method == "POST":
serializer = RegisterUserSerializer(data= request.data)
data = {}
if serializer.is_valid():
account = serializer.save()
data['response'] = "Successfully registered new user!"
else:
data = serializer.errors
return Response(data)
Where am I missing to implement thing?
unique_together means the set of fields you defined should be unique for all Users. If you also want contact to be a unique field when stored in db, you should pass the unique parameter like so:
class MasterUser(AbstractBaseUser):
...
contact = models.CharField(max_length=100, blank=True, unique=True)
...

How do I update a user created from another model though that model edits?

My question is based on this here. Now that User.objects.update_user() does not work, how would I update a user if the the teacher whose details created the user are updated.
Below is the view that created the user.
class NewTeacherView(LoginRequiredMixin,CreateView):
model = TeacherData
form_class = TeachersForm
template_name = 'new_teacher.html'
success_url = reverse_lazy('teachers')
def form_valid(self, form):
context = super().form_valid(form)
teacher_data = self.object
username = (teacher_data.first_name + teacher_data.last_name).lower()
password = (teacher_data.first_name + str(teacher_data.code)).lower()
user = User.objects.create_user(
username=username,
password=password,
school_id=self.request.user.school.id,
is_teacher=True)
return context
HHow would I create the view that edits the user when the teacher is edited????

How to list all user groups in Django?

I am trying to list users and at the same time with the groups added to each one of them.
How can I do this?
Below is an example I'm trying to do.
Thank you.
Serializer
class serializerUser(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(read_only=True)
first_name = serializers.CharField()
last_name = serializers.CharField()
groups = serializers.CharField()
password = serializers.CharField(write_only=True)
username = serializers.CharField(write_only=True)
views
class UserList(ListAPIView):
pagination_class = LimitOffsetPagination
serializer_class = serializerUser
queryset = User.objects.all()
def get_queryset(self):
users = User.objects.select_related('group').all()
return users
Error:
django.core.exceptions.FieldError: Invalid field name(s) given in
select_related: 'gsroup'. Choices are: (none)
You already got them in user.groups. If you want to show them along with the user, add the groups field to the Meta class fields list, for example:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
"username",
"first_name",
"last_name",
"email",
"groups",
)

Edit user profiles form without using django admin

I am developing a simple LMS system where I have 3 stakeholders Administrator, Faculty Members and Students. Administrator can create, edit, delete, block and list user accounts, with my developement so far I am able to create and list all users.
Now I am stuck at editing user profile, my requirement is when I click on any listed users it should open my extended/customized user profile in a form and I should have the ability to edit any opened user profile.
Below are my code snippets:
MODELS.PY:
from django.contrib.auth.models import User
class UserInformation(models.Model):
user = models.ForeignKey(User, unique=True)
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
def __str__(self):
return self.user.username
VIEWS.PY (to create user):
def ad_create_user(request):
if request.method == 'POST':
firstname = request.POST['firstname']
lastname = request.POST['lastname']
username = request.POST['username']
password = request.POST['password']
email = request.POST['email']
group = request.POST['group']
degree = request.POST['degree']
cell_no = request.POST['cell_no']
new_user = User.objects.create_user(username, email, password)
new_user.first_name = firstname
new_user.last_name = lastname
new_user.save()
if group == 'option_one':
set_group = 3
new_user.groups.add(3)
userinfo = UserInformation(user=User.objects.get(username=username), degree=Degree.objects.get(pk=degree),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_two':
set_group = 2
new_user.groups.add(2)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_three':
set_group = 1
new_user.groups.add(1)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
return HttpResponseRedirect('/administrator/user_management/')
return render(request, 'MobiApp/create_user.html', {'form': CreateUserForm()})
FORMS.PY (to create user):
class CreateUserForm(forms.Form):
firstname = forms.CharField(max_length=64)
lastname = forms.CharField(max_length=64)
username = forms.CharField(max_length=16)
password = forms.CharField(
widget=forms.PasswordInput(),
)
email = forms.EmailField()
group = forms.ChoiceField(
choices=(
('option_one', "Student"),
('option_two', "Faculty Member"),
('option_three', "Administrator"),
),
widget = forms.RadioSelect,
initial = 'option_one',
)
degree = forms.ModelChoiceField(queryset=Degree.objects.all())
cell_no = forms.CharField()
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.layout = Layout(
Field('firstname', css_class='input-xlarge'),
Field('lastname', css_class='input-xlarge'),
Field('username', css_class='input-xlarge'),
Field('password', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
'group',
'degree',
Field('cell_no', css_class='input-xlarge'),
FormActions(
Submit('create', 'Create!', css_class="btn-primary"),
)
)
I found many questions similar to this but none of them helped me and my requirement is also little different as user is not editing his/her profile but administrator is editing profile of any user.
Just for your information:
I am using Django-Crispy-Forms
When I click on any user of edit profile, its URL will be something like this http://myapp.com/administrator/edit_user/11
where 11 is the user id
Thanks in advance, let me know if you need any further information.
EDIT:Here's my final proposed solution (charlesliam also made a reference to this in his comment)
We will subclass AbstractUser to add extra fields to the user. Obviously, there's other ways of doing this, but using AbstractUser should suffice your requirements. You'd have to syncdb for model changes to propagate.
SETTINGS.PY
AUTH_USER_MODEL = 'app.UserInformation' # Points to our custom User model which we will define in models.py
MODELS.PY
from django.contrib.auth.models import AbstractUser
class UserInformation(AbstractUser):
# user = models.ForeignKey(User, unique=True) <---- Remove this field
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
FORMS.PY
class EditUserForm(forms.ModelForm): #fixed typo. It's forms.ModelForm, not models.ModelForm
class Meta:
model = UserInformation
VIEWS.PY
from forms.py import EditUserForm
def edit_user (request, id):
user = User.objects.get(id=11)
if request.method == 'POST': #If form has been submitted
form = EditUserForm(request.POST, instance=user)
if form.is_valid(): #All good. Validation passed
form.save()
return HttpResponseRedirect('/your-view/') # Redirect after POST
else:
form = EditUserForm(instance=user) # Unbound form
return render(request, 'MobiApp/edit_user.html', {'form': form})
edit_user.html
{% load crispy_forms_tags %}
{% crispy form %}
will give you a pre-populated form with the user instance, which you can edit and POST back.
Now with regards to user authentication, you can check if the currently logged in user is superuser (administrator), and proceed with the form editing logic.
So in your VIEWS.PY:
def edit_user (request, id):
current_user = request.user
if current_user.is_superuser:
...
Alternatively, you can assign the currently logged-in user to any group and then check if the user is member of that group, then proceed with form editing.
I hope that helps.
REFERENCES:
https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/
https://github.com/django/django/blob/master/django/contrib/auth/models.py#L353
https://docs.djangoproject.com/en/dev/topics/auth/customizing/
When to use the Custom User Model in Django 1.5

Resources