How to pass a value from model to view in django? - python

How to pass codeval variable from models.py to views.py:
in models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
import random
from django.core.mail import send_mail
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
city = models.CharField(max_length=100, default='')
website = models.URLField(default='')
mobile = models.IntegerField(default=0)
code = models.IntegerField(default=0)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
codeval = random.randint(111111,999999)
user_profile.code = codeval
user_profile.save()
receiver = User.objects.get(id=user_profile.user_id).email
send_mail(' Confirm your account on Abolombon',
'Thanks for signing up with Abolombon! Your Abolombon verification code is:\n %s\n\n Thank you\nAbolombon.com'%(codeval),
'testpurpose2040#gmail.com',
[receiver])
post_save.connect(create_profile, sender=User)
in views.py
def verification(request, args=codeval):
return render(request,'website/verification.html',{'args':args})
I am making an e-commerce site in django where I need user registration option. For this purpose I am using django's build in user registration form. But I need to store some additional info about user like contact number, city etc. I also want to verify user sending a 6 digit code to their corresponding email address.
But in django's build in form their is no field to store verification code. So I have created UserProfile model to serve this purpose. And have created code field to store 6 digit random number.
I want to store this random number into code field and also send it to the user email address. And when user will enter the code a function will verify it with the stored one. For this I need key to retrieve the code from the db. So I want to pass this key to the views.py.
Thank you

If I am interpreting your question correctly, you want UserProfile.objects.get(code=codeval). This will give you the actual profile, so if you want the id, just do UserProfile.objects.get(...).id.
Note that your current code could give multiple profiles the same code, so you should either prevent that or get all profiles that match using .filter instead of .get.

Related

Wagtail Customising User Account Settings Form With One-to-One Model

I have a model in my app called "portal", in portal/models.py:
from django.db import models
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from wagtail.snippets.models import register_snippet
from wagtail.admin.edit_handlers import FieldPanel
#register_snippet
class StaffRoles(models.Model):
role = models.CharField(max_length=154, unique=True, help_text="Create new staff roles here, these roles an be assigned to 'staff' users.")
panels = [
FieldPanel('role'),
]
def __str__(self):
return self.role
class Meta:
verbose_name = "Staff Role"
verbose_name_plural = "Staff Roles"
#register_snippet
class Staff(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=1024, blank=True)
roles = models.ManyToManyField(StaffRoles, blank=True)
def __str__(self):
return str(self.user.first_name) + " " + str(self.user.last_name)
class Meta:
verbose_name = "Staff"
verbose_name_plural = "Staff"
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created and instance.is_superuser:
Staff.objects.create(user=instance)
Any new superuser is automatically given the Staff model. Any existing (non superuser) user can also be added as Staff.
I want Staff members to be able to set a bio and a role. Roles can be added through the Snippets page in Wagtail admin.
Right now, Staff is registered as a snippet, this means any Staff member can edit another Staff member's Staff attributes.
I want to customise the Wagtail User Account Settings by adding a form to each user's respective Staff attributes. This way, I can lock out the Staff snippet so each user who has a Staff object linked to their User model can change only their own Staff fields/attributes.
Following the Wagtail documentation from here, I first created the file portal/forms.py with the content:
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
from wagtail.users.models import UserProfile
from .models import Staff
class CustomStaffSettingsForm(forms.ModelForm):
class Meta:
model = Staff
exclude = []
And another file portal/wagtail_hooks.py with the contents:
from wagtail.admin.views.account import BaseSettingsPanel
from wagtail.core import hooks
from .forms import CustomStaffSettingsForm
#hooks.register('register_account_settings_panel')
class CustomStaffSettingsPanel(BaseSettingsPanel):
name = 'custom_staff'
title = "Staff settings"
order = 500
form_class = CustomStaffSettingsForm
form_object = 'profile'
This doesn't work as intended. When accessing "Account settings" and scrolling down to the "Staff settings" I can see the CustomStaffSettingsForm as intended. Although the correct user is pre-selected in the User field, I can still select other users. Also, the stored values for bio and roles aren't being retrieved and new values aren't being saved.
Below are the Staff Roles registered in the snippets page:
Below is the Staff model for the user "sid" in the snippets page:
Below is what the Staff settings section in the "Account settings" looks like.
As you can see, although the User dropdown is selected to the right user, I can still click and select another user. The bio and roles fields aren't filled with the correct values from the snippets page and not shown in the picture, filling and saving values doesn't work.
I hope my question is as detailed as possible, how do I fix this?
After a few hours of digging, I managed to answer my own question.
A related_name needs to be added with the value of profile to Staff.user. This prevents the 'User' object has no attribute 'profile' error message
class Staff(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
...
We need to exclude the user field from the CustomStaffSettingsForm. This is to prevent users to select a different user and change another user's Staff fields.
class CustomStaffSettingsForm(forms.ModelForm):
class Meta:
model = Staff
exclude = ["user"]
The tricky part (at least for me) was to render the correct instance of the form, in other words, if a user named "sid" is accessing this form, they need to be able to see their own Staff fields which are stored and also be able to change the stored values. To achieve this, I had to override the get_form method which CustomStaffSettingsPanel inherited form Django's BaseSettingsPanel. It's easier for me to paste the entire wagtail_hooks.py contents here below.
from wagtail.admin.views.account import BaseSettingsPanel
from wagtail.core import hooks
from .forms import CustomStaffSettingsForm
#hooks.register('register_account_settings_panel')
class CustomStaffSettingsPanel(BaseSettingsPanel):
name = 'custom_staff'
title = "Staff settings"
order = 300
form_class = CustomStaffSettingsForm
form_object = 'profile'
def get_form(self):
"""
Returns an initialised form.
"""
kwargs = {
'instance': self.request.user.profile,
'prefix': self.name
}
if self.request.method == 'POST':
return self.form_class(self.request.POST, **kwargs)
else:
return self.form_class(**kwargs)
The key part of the code above is 'instance': self.request.user.profile. Passing this argument into self.form_class results in the correct user's stored Staff fields and values to be retrieved and stored correctly.
This solution allows me to make sure superusers who are also registered as Staff can edit their own Staff fields and have access to others, this is a functionality which cannot be achieved easily with Snippets.
As Staff is no longer registered as a Snippet, we lose access to change another user's Staff fields. This can be fixed by adding the following in portal/admin.py:
admin.site.register(Staff)
Only superusers who had been created via python manage.py createsuperuser or has had staff_status set to true can access the Django Admin interface at http://localhost:8000/django-admin. Unlike Snippets, this way can be used to allow only the Django superuser staff to access and modify Staff fields.
What about non-superusers who are registered as Staff? Non-superusers cannot access the Wagtail admin, therefore they cannot access the Account Settings page. In most cases, this shouldn't be a problem as the ideal use-case is where only the superusers can be set as Staff. If you want to set non-superusers as Staff you might have to create your own views and forms so the user can change their Staff fields outside of Wagtail admin.

How to make a input in Admin page as password type?

I created a model which has 3 fields: name, email, password. I want the password in the admin to not show as clear text or to not show even. Do you have
any ideas to change input type in the admin page from type='text' to type='password'?
Models.py:
class Artist(models.Model):
artist_name = models.CharField(max_length=255,null=False,blank=False)
email = models.EmailField(max_length=255, null=False,blank=False)
password = models.CharField(max_length=20, null=False,blank=False)
def __str__(self):
return self.artist_name
admin.py:
from django.contrib import admin
from home.models import Track, Artist, Region, User
admin.site.register(Artist)
are you talking about hiding the password for security purposes ? -use authentication like passport instead, or even hashing, encryption etc.
or are you talking about instead of displaying "password123" it displays "***********" ?
this can be done but the password can be discovered easily by anyone with basic knowledge of computers

Django auto Mail

I've been trying to learn django for the past couple of days, and I've made a basic bug tracking software as of now (using the admin part of django)
Ive created a table called bugs:
from django.db import models
# Create your models here.
class Bugs(models.Model):
STATUS_CHOICE = (
('Work In Progress', 'Work In Progress'),
('Incomplete', 'Incomplete'),
('Completed', 'Completed')
)
Project_Name = models.CharField(max_length=100)
Basic_Description = models.CharField(max_length=100)
Detailed_Description = models.TextField(default='The Description, here.')
Status = models.CharField(max_length=18, choices=STATUS_CHOICE)
Assigned_to = models.CharField(max_length=100)
Reported_by = models.CharField(max_length=50, blank=True, null=True)
Reporters_Mail_ID = models.CharField(max_length=50, blank=True, null=True)
Reported_Date = models.DateTimeField(null=True, blank=True)
Created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
Updated = models.DateTimeField(auto_now=True, null=True, blank=True)
Deadline_Date = models.DateTimeField(null=True, blank=True)
image = models.FileField(null=True, blank=True)
def __str__(self):
return self.Project_Name + ' [' + self.Status + '] ' + self.Basic_Description + ' [' + self.Assigned_to + ']'
class Meta:
verbose_name_plural = "Bugs"
How do I make it so that when a project name is selected, the Assigned_to is also automatically selected?
And how do I make sure that once it is assigned to the person/ Status is edited/ or any sort of edit is made by the SuperUser, a mail is sent to the person it is assigned to, and when an edit is made by the Person it is assigned to, the super user gets a mail saying an edit has been made?
Not that important but, I was also wondering if there is any way to make sure that when the Super user Assigns some work to one of the admins, Only the admin specified can view the Issue??
UPDATE:
Let me try to be more descriptive this time..
So i have 2 types of users:
1st is the Super User who decides what bugs should be placed into the list and also manages the other users as well.
2nd is the other normal users, selected by the superuser (Users can only edit the posts added by the superuser)
The database has 12 columns out of which Project_Name and Assigned_To are 2.
My question is,
How do I make it such that when the superuser enters the Project_Name, the Assigned_To Column is already filled?
take this as an example
Project_Name: Project1 ---> Assigned_To: Person1
Project_Name: Project2 ---> Assigned_To: Person2
Project_Name: Project3 ---> Assigned_To: Person3
Project_Name: Project4 ---> Assigned_To: Person4
Now if the Super User Decides that the bug is in Project 1, and Project 1 is handled by Person 1, How do i make the program such that If Project 1 is chosen, Person 1 will automatically be selected in the Assigned_To Column?
And Once the SuperUser Selects the SAVE option(taking the same case as above). How do I make the program send a mail to Person1 when ever SuperUser Updates the database? And how do I make the program send a mail to the SuperUser when the Person1 Makes changes to the Database?
Well I'm not sure what your questions really are, but as I understood, you first need to add another field for user as following :
from django.contrib.auth import get_user_model
user = models.ForeignKey(get_user_model(), blank=True, null=True)
regarding sending email when an object of the model is saved or updated, you should override the save() method of the model and put the code you want to execute.
You can use django signals,
When the SuperUser saves or edits. You can write your code to achieve whatever you want.
from django.db.models.signals import post_save
def send_email(sender, instance, created, **kwargs):
# your code goes here...
post_save.connect(send_email, sender=Bugs)
ref: https://docs.djangoproject.com/en/2.0/ref/signals/#post-save
Ok, so first off, it's common practice to use all lower case for model fields. Python has a style guide called PEP8 which documents all the best practices for writing python. So take a look here to get started; https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles
Now if your assigned_to model should reference a user for the model to relate to you should indeed do as Milad said & use a ForeignKey to the User model because there are many benefits to using relationships where it makes sense for your data.
If you want the assigned_to to be automatically filled based on the project_name then you'd have to use javascript. You'd probably send an AJAX request on selection of the project to go to the backend with the project value. Then send back the assignee for that project which would be used in the javascript to set the value of the assigned_to field.
As far as sending emails go when changes are made to your model, you should use signals in python. Signals get fired when changes are made to objects, for example;
from django.core.mail import send_mail
from django.db.models.signals import post_save
from django.dispatch import receiver
from bugs.models import Bugs
#receiver(post_save, sender=Bugs)
def bugs_post_save(sender, instance=None, created=None, update_fields=None, **kwargs):
if created or 'assigned_to' in update_fields:
# We have a new object or the assignee has changed
send_mail(
'Subject here',
'Here is the message.',
'from#example.com',
['to#example.com'],
fail_silently=False,
)
The docs on email sending are here
Your receiver functions like this can be included underneath your models or in a specific signals.py module which you'd import in the application config. That would like something like;
# bugs/apps.py
from django.apps import AppConfig
class BugsConfig(AppConfig):
name = 'bugs'
verbose_name = "Bugs"
def ready(self):
# importing signals
import signals

How to filter users depending on a models.charfield choices in django

so i currently have this as my profile model for each user.
class Profile(models.Model):
user = models.OneToOneField(User)
location = models.CharField(max_length=120, choices=LOCATIONS,null=True, blank=True)
picture = models.ImageField(upload_to=upload_location, null=True, blank=True)
how to i filer users depending on the choices given in the location field? So for example if the current user has London selected, in the template they will only see results of users/profiles with the same location.
Do i have to create an if statement or a for loop in the views.py? or do i use a q lookup? if anyone could give me some pointers or show me in the right direction that would be amazing!
thank you for any help in advance
It is recommended to filter the results in the view and based on your requirement, you can just use the native django queryset. You can create a view like this:
views.py
from django.contrib.auth.models import User
from django.shortcuts import render
def users(request):
location = request.GET.get('location', 'default_location')
users = User.objects.filter(profile__location=location)
return render(request, 'users.html', {'users': users})
So for example if you have a url /users/ for listing the users, passing the location parameter will filter your users /users/?location=london

How to use user profiles with MongoEngine (Django)?

So, I'm trying to build up a simple site with a MongoDB database and Django (using MongoEngine), but I am stuck trying to understand how the user profiles work. I can save the mongo_auth.MongoUser document to the database just fine, but when it comes down to actually saving the profile, I'm not doing the right thing. Here is the User Profile model/document I am trying to setup with the MongoUser:
from mongoengine.django.auth import User
from mongoengine import *
[...]
class UserProfile(Document):
user = EmbeddedDocumentField('User')
telephone = models.CharField(max_length=30,null=True,blank=True)
address = models.CharField(max_length=100, null=True, blank=True)
birthdate = models.DateField(null=True, blank=True)
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
In Django with relational databases, the UserProfile was a models.Model and the user field was a OneToOne relationship, but I don't know how to map that with the MongoUser, so I guessed the following lines:
class UserProfile(Document):
user = EmbeddedDocumentField('User')
But, apparently, it's not right since Django can't load the profile:
Unable to load the profile model, check AUTH_PROFILE_MODULE in your project settings
I think my settings.py is configured correctly since I can save a MongoUser just fine (without a profile), and the following line tells Django where to find the UserProfile:
AUTH_PROFILE_MODULE = 'comptes.UserProfile'
I am still new to Django and MongoDB, so all help will be greatly appreciated.
Thanks!
You must use mongoengine.fields.ReferenceField. Something like this
class UserProfile(Document):
user = ReferenceField('User')

Categories

Resources