django - creating users making their fullname unique - python

i need small help in the logic of creating user making his name unique:
i have a django user profile. i am creating users in this way:
fullname = request.POST.get('fullname')
random_username = ''.join(random.sample(string.ascii_lowercase, 8))
new_user = User.objects.create_user(random_username, email, passwort)
##update siteprofile of this new user
userprofile = new_user.get_profile()
"""
i need to make this fullname unique with this logic:
for example john is the fullname of new user. i need to check if there are
other johns in db, if there is another user with this name, i will name the
user with 'john1'. if there are 2, the new user will get the name 'john3'
how can I check this in db in some efficient way?
"""
userprofile.name = fullname
userprofile.save()

You want to check for the IntegrityError on save and update accordingly. Doing a query to check for the names existence creates a race condition where you can search then two separate threads try to create the same fullname at the same time.
from django.db import transaction
#transaction.commit_manually
def set_fullname(userprofile, fullname, i=0):
new_fullname = u"{}{}".format(fullname, str(i) if i else '')
try:
userprofile.fullname = new_fullname
userprofile.save()
transaction.commit()
return userprofile
except IntegrityError:
transaction.rollback()
i += 1
# Just recursively try until we a valid name. This could be problematic if you
# have a TON of users, but in that case you could just the filter before then to see
# what number to start from.
return set_fullname(userprofile, fullname, i)
userprofile = set_fullname(userprofile, fullname)

For this purpose it would be better to use form https://docs.djangoproject.com/en/dev/topics/forms/. But if you won't to use forms, you can do it that way:
i = 0
orig_fullname = fullname
created = False
while not created:
profile, created = UserProfile.objects.get_or_create(name=fullname)
if not created:
i+=1
fullname = orig_fullname + str(i)
# there you have new user's profile
Note, that field 'name' in UserProfile model must have unique=True parameter https://docs.djangoproject.com/en/dev/ref/models/fields/#unique

Related

how to populate user specific data in django

I have 2 models employee and leave, where Employee is the foreign key in Leave. I want to display the leave requests by a specific employee on a page when they log in.
i'm not able to get the leave data populated on, and if there are more than 2 leaves applied by a single employee i get an error saying 2 items found
here is my code
models.py
class Employee(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
no_of_leaves=models.IntegerField(
null=False,
validators=[
MinValueValidator(1),
MaxValueValidator(24)
],
default=24
)
def __str__(self):
return self.user.username
class Leave(models.Model):
employee=models.ForeignKey(Employee,on_delete=models.CASCADE,default="")
start_date=models.DateField(auto_now_add=False)
end_date=models.DateField(auto_now_add=False)
req_date=models.DateTimeField(default=datetime.datetime.now())
STATUS_OPTIONS = (
("Approve","Approve"),
("Pending","Pending"),
("Decline","Decline"),
)
approved=models.CharField(max_length=10,choices=STATUS_OPTIONS,default='Pending')
def __str__(self):
return self.employee.user.username
#property
def date_diff(self):
return (self.start_date - self.end_date).days
views.py
def home(request):
user = request.user
u = User.objects.get(username=user)
e = Employee.objects.get(user=user.id)
leave = Leave.objects.get_or_create(employee=e)
print(leave)
nofleaves=None
if user.is_superuser:
pass
else:
nofleaves=u.employee.no_of_leaves
context={'nofleaves':nofleaves,'leave':leave,}
return render(request,"leaveApp/home.html",context)
Just like #Jao said get is to fetch only one data while there is a many to one relationship between Leave and Employee that means there can be multiple Leave for one employee thus get will throw an error.
You should use filter:
Change this line
leave = Leave.objects.get_or_create(employee=e) to something like
leave = Leave.objects.filter(employee=e.id)
if not leave.exists():
leave = Leave.objects.create(employee=e)
This other question might help.
The thing is you should use get for only one data. You shouldn't use get on a many-to-one relathionship. The logic is, there can be multiple Leave by Employee so you can't have a consistent use of get.
What you can use is filter but I'd use related names/related fields which will allow you to use employee.leaves if you define it correctly.

Store multiple Values in one session variable in django

I want to store college IDs in a session variable that each ID should get stored in same session. i want it when user click on ADD button. so whenever the ADD button would be clicked that ID Should get stored in choice session variable.
here is what i have tried.
views.py
def my_choices(request, cid): # when user is making the choices
clg = college.objects.all()
title = "Choice Filling"
page = "Choice Filling"
stud = student.objects.get(id=request.session['id'])
clgid = college.objects.get(id=cid)
choice_list = []
if stud.isactive != 1:
messages.error(request, "Your registration process is incomplete.")
else:
choice_list.insert(len(choice_list), clgid.name)
print(choice_list)
request.session['choices'] = choice_list
return render(request, 'college_list.html', {'cid': cid, 'clg': clg, 'title': title,
'choice':choice_list})
models.py
class college(models.Model):
name = models.CharField(max_length=50)
password = models.CharField(max_length=10)
institute_code = models.IntegerField(unique=True)
class student(models.Model):
fullname = models.CharField(max_length=50)
password = models.CharField(max_length=10)
email = models.EmailField(unique=True)
I want to store cid for every click in choice_list but it's not storing multiple values, instead it overrides the previous value and store new every time. i tried choice_list.insert(..) also but nothing happens.
You're initiating the choice_list as an empty list, instead of loading it from the session
choice_list = []
Replace it with:
choice_list = request.session.get('choices', [])
Your new function should now be
def my_choices(request, cid): # when user is making the choices
clg = college.objects.all()
title = "Choice Filling"
page = "Choice Filling"
stud = student.objects.get(id=request.session['id'])
clgid = college.objects.get(id=cid)
# get choice list from your session
choice_list = request.session.get('choices', [])
if stud.isactive != 1:
messages.error(request, "Your registration process is incomplete.")
else:
choice_list.insert(len(choice_list), clgid.name)
print(choice_list)
request.session['choices'] = choice_list
# the next line shouldn't be required, but if the code still doesnt work, uncomment it
# request.session.modified = True
return render(request, 'college_list.html', {'cid': cid, 'clg': clg, 'title': title,
'choice':choice_list})
Also, if you might have to tell django that the session has been changed. Put this code before returning your view (or after the session edit)
request.session.modified = True

How to access its object query properties I know it have 5 properties in it

I wanna access <QuerySet [<User: xyz>]> this object properties it have multiple properties but i dont know how to access each property and update its value
u = User.objects.filter(username=username)
u.first_name=(str(first_name))
u.save(`
You need to either iterate through the instances in the queryset, and interact with them accordingly:
for u in User.objects.filter(username=username):
print(u.first_name) # Access & print `first_name`
u.first_name=first_name # Update `first_name`
u.save() # Need to save the changes
or, you can use update to change all the instances in the queryset at once:
User.objects.filter(username=username).update(first_name=first_name)
You could also get first_name as a list if all you want is the first names for some reason:
User.objects.filter(username=username).values_list('first_name', flat=True)
User.objects.filter() returns list of results. In your example, "u" is a list of users. Can be list with one user.
To be able to modify user's properties, you have to take a QuerySet.
filter
list_of_users = User.objects.filter(username='username')
if list_of_users:
# lets say I will take first one.
user = list_of_users[0]
user.username = "new name"
user.level = "new level"
# etc.
user.save()
get
import logging
logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__)
name = "username"
try:
user = User.objects.get(username=name)
user.username = "new username"
user.level = "new level"
# etc
user.save()
except User.DoesNotExist:
LOGGER.info("User with given name %s does not exist", name)

django 'null value in column'

I try to save user's birth date, but get "null value in column "dob" violates not-null constraint" error.
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, unique=True)
nickname = models.CharField(max_length=32)
dob = models.DateField(null=False)
sex = models.BooleanField(null=False)
Here i try to generate random users:
def create_random_users(userCount=1000):
random.seed()
for i in range(0, userCount):
sex = random.randint(0, 1)
name = random.choice(names[sex])
email = "{0}{1}#mail.com".format(name, i)
user = soc_models.User.objects.create_user(email, email, password='password')
user.save()
userProfile = soc_models.Profile.objects.create()
userProfile.user = user
_year = random.randrange(1962, 1995)
_month = random.randrange(1, 12)
_day = random.randrange(1, calendar.monthrange(_year, _month)[1])
userProfile.dob = datetime.datetime(_year, _month, _day)
userProfile.sex = random.randrange(0, 1)
userProfile.city = random.randrange(4000000)
userProfile.country = random.randrange(230)
userProfile.save()
Thank you.
The create method is documented as "a convenience method for creating an object and saving it all in one step". So when the following statement in your sample data creation script runs:
userProfile = soc_models.Profile.objects.create()
It attempts to save an empty Profile object to the database. Since you haven't set the dob attribute at this point, you trigger the NOT NULL constraint.
Two ways to avoid this are:
create the object via the constructor so that it isn't immediately saved to the database.
provide values for all the fields via keyword arguments to create.
When using create, you must pass all required values to it, if you want to call save() later, use model constructor instead, i.e.:
userProfile = soc_models.Profile()
I'm not sure whether it fixes your error or not, but regarding to docs, DateField should be used for storing datetime.date instance, and DateTimeField to store datetime.datetime.
P.S. Really, it looks like you trying to "migrate" DB scheme (to change already created columns). Django doesn't support such feature, but you can use external applications, like South.

Flask and WTForms - how to get wtforms to refresh select data

I am using the latest version of flask, wtforms and Flask-WTForms.
I have a page that displays a form and one is a select box with option option called "A".
When the app starts all is well. In a another form I add a record called "B".
Now, the form I want should have the select box wth options A and B bot only option A is available. I have to kill uWSGI and restart to get wtforms to refresh the data.
So, what am I missing? How to I get wtforms to refresh data?
Here s how I create the form where getAgencyList returns a list of options to add to the select box. In another dialogue I add an agency and the agency list should be updated without having to restart the app:
class createUser(Form):
"""
Users are given a default password
"""
first_name = TextField()
last_name = TextField()
email = TextField('Email', [validators.Length(min=6, max=120), validators.Email()])
user_role = SelectField(u'User Role', choices=[('1', 'User'), ('2', 'Admin')])
org_role = SelectField(u'User Role', choices=[('1', 'Agency'), ('2', 'Advertiser'),('3', 'Admin')])
agency = SelectField(u'Agency', choices=getAgencyList())
The problem is that getAgencyList() is called upon definition of the class. So whatever that function returns at that time will be it's data. In order to update the list information you have to somehow run getAgencyList during instantiation. In order to do this you can use a not very obvious fact about wtforms that allows you to add choices to a particular field. The documentation is here just look for the subsection that is titled "Select fields with dynamic choice values". Here's a sample of code that should work.
class CreateUserForm(Form):
first_name = TextField()
last_name = TextField()
email = TextField('Email',
[validators.Length(min=6, max=120), validators.Email()])
user_role = SelectField(u'User Role',
choices=[('1', 'User'), ('2', 'Admin')])
org_role = SelectField(u'User Role',
choices=[('1', 'Agency'), ('2', 'Advertiser'),('3', 'Admin')])
agency = SelectField(u'Agency')
#classmethod
def new(cls):
# Instantiate the form
form = cls()
# Update the choices for the agency field
form.agency.choices = getAgencyList()
return form
# So in order to use you do this ...
#app.route('/someendpoint')
def some_flask_endpoint():
# ... some code ...
form = CreateUserForm.new()
# That should give you a working CreateUserForm with updated values.
# ... some more code to validate form probably...
A simple solution would be to fetch the options to be displayed from the database and then overwrite the Form Class with those:
eg:
def get_agencies():
agency_list = []
# get the Agencies from the database - syntax here would be SQLAlchemy
agencies = Agency.query.all()
for a in agencies:
# generate a new list of tuples
agency_list.append((a.id,a.name))
return agency_list
#app.route('/somewhere',methods=['POST'])
def somewhere():
form = createUser()
# overwrite the choices of the Form Class
form.agency.choices = get_agencies()
# here goes the rest of code - like form.validate_on_submit()
...
return render_template('create_user.html', form=form)

Categories