Hey guys I am a bit new in Django. What I want to achieve is a URL which I can access with a GET request from my app, passing some values along with it.
I have a UserProfile model in Django which has a oneToOneField relationship to User. I want to pass email with my GET request and find a Userinstance with this email, then I want to pass two more values which I want to compare with this Users UserProfile attributes. But I don't quite understand how to achieve this. Here is what I have:
in my views.py
def check(request):
try:
email = request.GET.get('email', '')
osusername = request.GET.get('osusername', '')
computername = request.GET.get('computername','')
except TypeError:
return HttpResponseBadRequest()
user = get_object_or_404(User.objects.filter(user__email=email)[0])
in my urls.py
urlpatterns = patterns('',
url(r'^check/$', 'myapp.views.check'),)
But how do I compare for instance computername with User.UserProfile.computername of that user? No matter how I write it its wrong.
My UserProfile model as requested #comments:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
computername = models.CharField("Computername", max_length=150, blank=False)
osusername = models.CharField("Osusername", max_length=150, blank=False)
So your syntax for get_object_or_404 is wrong. You don't pass it an object: it gets the object for you. So:
user = get_object_or_404(User, email=email)
Now you've got a User instance, and you want to get the relevant profile, so you can just do:
profile = user.userprofile
Alternatively it might be easier to grab the profile directly, if you don't need the actual user instance for anything else:
profile = get_object_or_404(UserProfile, user__email=email)
Now you can check the relevant attributes:
osusername == profile.osusername
computername == profile.computername
You need to retrieve the User instance first by:
try:
a_user = User.objects.get(email=email)
except User.DoesNotExist:
# error handling if the user does not exist
Then, get the corresponding UserProfile object by:
profile = a_user.userprofile
Then, you can get osusername and computername from the UserProfile object:
profile.osusername
profile.computername
As an addition to #daniel-roseman answer.
If checking the relevant attributes is a common task on multiple views it could also be worth creating a method in your UserProfile model which can perform the required validation check.
class UserProfile(object):
# various attributes ...
def check_machine_attributes(self, os_username, computer_name):
if os_username == self.osusername and computername == self.computername:
return True
return False
In your view you can then do:
if profile.check_machine_attributes(osusername, computername):
# ...
else:
# ...
Related
How do I obtain the field data from a User auth query within a class View. It's on the django 2.2.x framework using Python3
This code works just fine...
from django.contrib.auth.models import User
class PaymentsReportView(ListView):
template_name = 'payments/Payment_list.html'
userid = 'James'
queryset = Payment.objects.filter(Landlord_FK__User_id=userid)
but this doesn't...
class PaymentsReportView(ListView):
template_name = 'payments/Payment_list.html'
userid = User.username # where the username is James
queryset = Payment.objects.filter(Landlord_FK__User_id=userid)
How can I check the output of User.username to see if it's valid? What am I missing to get the data? The code doaen't break. It just returns empty.
You can't do that at class level. What you need to do is to define a get_queryset method and do the filtering there:
class PaymentsReportView(ListView):
template_name = 'payments/Payment_list.html'
def get_queryset(self):
userid = self.request.user.username
return Payment.objects.filter(Landlord_FK__User_id=userid)
Although I must note that this implementation is odd; why is the userid the username, rather than the ID? Usually I would expect the filter to be (Landlord_FK=request.user). You should show your models.
I am trying to extend the user model using a one to one relationship to a UserProfile model. I added some boolean fields and in the view I am trying to use those fields as permissions.
Here is my model:
class UserProfile(models.Model):
user = models.OneToOneField(User)
FirstName = models.CharField(max_length=25)
LastName = models.CharField(max_length=25)
ProximityAccess = models.BooleanField(default=True)
NewProxAccess = models.BooleanField(default=False)
def __unicode__(self):
return self.user.username
and here is the view I am trying to use:
#login_required
def NewProx(request):
if UserProfile.NewProxAccess:
if request.method == 'POST':
form = ProxForm(request.POST)
if form.is_valid():
ProxPart_instance = form.save(commit=True)
ProxPart_instance.save()
return HttpResponseRedirect('/proximity')
else:
form = ProxForm()
return render(request, 'app/NewProx.html', {'form': form})
else:
raise PermissionDenied
I don't get any error messages but it does not work as intended. I was hoping that if the user profile had NewProxAccess set to False it would raise the PermissionDenied but it doesn't. I have the admin module wired up and I can select or deselect the checkbox for that field but it has no effect. If I comment out the rest I can get it to show the Permission Denied error so it has to be in the view (I think). I think I am missing a line the establishes the logged in user as the user instance so we can check to see if the user has the permission or not. I know there are a ton of ways to do this and there is probably a better way but for the sake of learning, what is it that I am missing for this to work?
Thanks
Scott
As you want to check access for particular profile but not UserProfile model you need to do:
if request.user.userprofile.NewProxAccess:
# your code
As a note: according to PEP8 best practices you should use camelCase only for naming Classes. For attrs, functions use underscore: my_function
with django 1.5.1 I try to use the django form for one of my models.
I dont want to add the "user" field (Foreignkey) somewhere in the code instead of letting the user deceide whoes new character it is.
My Code:
Model:
class Character(models.Model):
user = models.ForeignKey(User)
creation = models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')
name = models.CharField(max_length=32)
portrait = models.ForeignKey(Portrait)
faction = models.ForeignKey(Faction)
origin = models.ForeignKey(Origin)
The form:
class CreateCharacterForm(forms.ModelForm):
class Meta:
model = Character
fields = ['name', 'portrait', 'faction', 'origin']
The view:
def create_character(request, user_id):
user = User.objects.get(id=user_id)
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
new_char_form.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
return render_to_response('create.html',
{'user': user, 'create_char':new_char_form},
context_instance=RequestContext(request))
else:
create_char = CreateCharacterForm
return render_to_response('create.html',
{'user': user, 'create_char': create_char},
context_instance=RequestContext(request))
I have tried to use a instance to incluse the userid already. i've tried to save the userid to the form before saving it, or changing the save() from my form.
I keep getting the error that character.user cant be null
I have to tell that im pretty new to django and im sure one way or another it should be possible
Can someone please help me out?
Its explained well in document model form selecting fields to use
You have to do something like this in your view
...
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
#save form with commit=False
new_char_obj = new_char_form.save(commit=False)
#set user and save
new_char_obj.user = user
new_char_obj.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
...
I've already defined a custom user account that utilizes several built in's from the auth User model and, using the user link, links these with some additional fields that I needed to register a user on the database.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
relevant from my models.py
# additional model to incorporate our custom fields to the auth user model
class Account(models.Model):
user = models.OneToOneField(User) #link (pointer) to the users other information in User model
birthdate = models.DateField(blank = True, ) # True makes this field optional
gender = models.CharField(max_length = 1, choices = GENDER_CHOICE, null = True, blank = True)
def __unicode__(self): # define a unicode for the user to access
return u'%s %s' % (self.user.first_name, self.user.last_name) # return first and last name in shell
# custom form to gather information from the user for a new account
class UserRegistration(UserCreationForm):
#class RegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2",)
# ensures uniqueness of user email addresses when registering
def clean_email(self):
print "In custom creation"
email = self.cleaned_data.get(email = 'email')
username = self.cleaned_data.get(username = 'username')
# checks if email address already exists
if User.objects.filter(email__iexact = self.cleaned_data['email']):
print "Email exists"
# if email and User.objects.filter(email__iexact = email).exclude(username=username).exists():
raise forms.ValidationError(u'Email Address is currently used by another user.')
return email
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
relevant from views.py
def Main(request):
if request.user.is_authenticated():
latest_events = Event.objects.all().order_by('-created')[:10] # Returns latest 10 events
my_events = Event.objects.filter(creator=request.user)[:10] # Returns up to 10 events created by current User
my_calendars = Calendar.objects.filter(creator=request.user) # Returns all calendars created by the user
authForm = None
loginForm = None
headerType = "header.html"
else:
latest_events = None
my_events = None
my_calendars = None
headerType = "header_main.html"
authForm = UserRegistration(request.POST or None)
print "Creating account UserRegistration" # TESTING PRINT
print "User email = %s " %(User._meta.get_field('email'))
if request.method == 'POST':
if authForm.is_valid():
newUser = authForm.save(commit=False)
newUser.save()
newUser = authenticate(username=request.POST['username'], password=request.POST['password1'])
login(request, newUser)
return HttpResponseRedirect('/signup/')
....
....
more code on success redirection
....
....
~~~~~~~~~~~~~~~~~~~~~~~~~~~
(I hope I didn't post too much code, just wanted to be thorough)
As you can see there are a few commented out attempts I've made recently. I tried using thee built in RegistrationFormUniqueForm() by downloading 'registration' but I don't actually want to make a new registration form since I already have a working one.
I moved on to trying another suggestion, the code under the comment
# custom form to display additional sign up information
When I tried registering a new user with an already registered email it did not throw any error and allowed the registration. I also tried changing the users email and it allowed the change to an already taken email with no objection.
Can anyone suggest a method for making user registration maintain a unique lock on each individual attempting to register with an email address that may already be taken? As well as preventing them from changing their email to one that is taken by a current user?
Thanks in advance.
EDIT: I made changes to the Models registration form def clean_email() and the def in views to reflect what I currently have that still does not work.
The indentation of your clean_email methods is wrong for both forms. At the moment, they are methods of the Meta class, so will never be called. For example, the registration form should be:
class RegistrationForm(UserCreationForm):
#class RegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2",)
def clean_email(self):
"""ensures uniqueness of user email addresses when registering"""
email = self.cleaned_data.get('email')
This might not be the real problem -- it's easy to get the indentation wrong when pasting code into stack overflow. If that's the case, I'll delete the answer.
The site I'm working on involves teachers creating student objects. The teacher can choose to make it possible for a student to log into the site (to check calendars, etc) OR the teacher can choose to use the student object only for record keeping and not allow the student to log in. In the student creation form, if the teacher supplies a username and a password, it should create an object of the first kind - one that can log in, i.e. a regular User object. If the teacher does not supply a username/password, it should create the second type. The other requirement is that the teacher should be able to go in later and change a non-logging-in student to the other kind. What's the best way to design for this scenario? Subclass User and make username and password not required? What else would this affect?
Edit:
I ended up using User.set_unusable_password(). Here's the code - I've left out other forms, etc, that I'm also using in my view:
Form
class StudentForm(forms.ModelForm):
username = forms.RegexField(regex=r'^\w+$',
required=False,
max_length=30,
label=("Username"),
error_messages={ 'invalid': ("This value must contain only letters, numbers and underscores.") })
password = forms.CharField(widget=forms.PasswordInput(),
label="Password", required=False)
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email', 'password')
Note that username and password are not required in the form.
View
def create_student(request):
if request.method == "POST":
student_form = StudentForm(request.POST)
if student_form.is_valid():
user = student_form.save(commit=False)
if student_form.cleaned_data['username'] == '':
user.username = generate_random_username()
user.set_unusable_password()
else:
user.set_password(user.password)
user.save()
return HttpResponseRedirect(reverse('student_list', args=['active']))
#GET an empty form
else:
student_form = StudentForm()
return render_to_response('priviostudio/create_student.html', {
'student_form': student_form,
})
And in the view to edit a student (which will probably be combined with the create_student view) I have this for GET:
student_form_initial = {
'username': user_instance.username if user_instance.has_usable_password() else '',
'password': user_instance.password if user_instance.has_usable_password() else '',
}
student_form = StudentForm(instance=user_instance, initial=student_form_initial)
And in POST, if the teacher submits a new username and valid password, I'll just set those on the User instance.
Thanks for the ideas everyone.
The auth app's User model has a set_unusable_password method; this probably does what you want without requiring the model to be extended.
The Django default User model has an is_active field.
http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.is_active
you probably want to use that.
That way when a teacher decides they want the user to be able to log in, your code would just set the student's user to is_active=True and vice versa.
Also according to the documentation link above Django's default authentication form and permission methods check the is_active flag, so that's some of the work already done for you.
You'd probably need to generate a username for the student as well, but you can easily do that using a slug from the name if that is provided.
The most obvious way for me to differentiate students from teachers would be groups really and Django provides mechanisms for that as well.
You might consider making all the students one kind of object - not User - and then supplementing that model with user objects where the teacher has enabled the student to log in. The composition of these two model objects would solve you want fairly cleanly.
I woud avoid subclassing User. Instead, you might want to create a custom authenticator that allows you to check group membership for login capability.
"""
DummyBackend.py
"""
from django.contrib.auth.models import User, check_password
from django.contrib.auth.backends import RemoteUserBackend
from lecture_feedback.daily.models import Student
class DummyBackend(RemoteUserBackend):
"""
Dummy authentication module that takes a username and password. The password must match the username.
"""
def authenticate(self, username=None, password=None):
"""
The username passed as ``remote_user`` is considered trusted. This
method simply returns the ``User`` object with the given username,
creating a new ``User`` object if ``create_unknown_user`` is ``True``.
Returns None if ``create_unknown_user`` is ``False`` and a ``User``
object with the given username is not found in the database.
"""
try:
student = Student.objects.get(globalid=username)
except Student.DoesNotExist:
return None
if username != password:
return
user = None
# Note that this could be accomplished in one try-except clause, but
# instead we use get_or_create when creating unknown users since it has
# built-in safeguards for multiple threads.
if self.create_unknown_user:
user, created = User.objects.get_or_create(username=username)
if created:
user = self.configure_user(user)
else:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
pass
return user
def configure_user(self, user):
"""
Configures a user after creation and returns the updated user.
By default, returns the user unmodified.
"""
student = Student.objects.get(globalid=user.username)
user.first_name = student.first_name
user.last_name = student.last_name
return user
The Student model could contain a field that indicates if the student is allowed to log in.
Also take a look at http://docs.djangoproject.com/en/dev/howto/auth-remote-user/#attributes.