I am creating a partial pipeline to get user's phone number on signup and skip the step on subsequent logins. My partial pipeline looks like this:
#partial
def other_info(strategy, details, user=None, is_new=False, *args, **kwargs):
if is_new or not details.get('email'):
request = kwargs['request']
return redirect('require_phone')
else:
return
On the page-welcome.html there is a form. Corresponding view looks like this:
def require_phone(request):
if request.method == 'POST':
phone = request.POST.get('phone',None)
user = User.objects.get(username = request.user.username)
if phone is not None:
up = UserProfile.objects.get_or_create(user=request.user,
phone = phone)
up.save()
backend = request.session['partial_pipeline']['backend']
return redirect('social:complete', backend=backend)
else:
return render(request,'app/page-welcome.html')
The problem is, the request object is not passed correctly to the view and hence the user shows anonymous. I am not able to access user object and hence cannot save phone no.
You might be able to get the user with
user = User.objects.get(id=request.session['partial_pipeline']['kwargs']['user'])
and then update this object, instead of trying to get it from the request (which will not work during the pipeline).
Related
I am trying to show orders by customer id by i am getting this error :
TypeError at /orders
Field 'id' expected a number but got {'id': 3, 'phone_number': '01622153196', 'email': 'sakibovi#gmail.com', 'password': 'pbkdf2_sha256$216000$H2o5Do81kxI0$2tmMwSnSJHBVBTU9tQ8/tkN7h1ZQpRKrTAKkax1xp2Y=', 'coin': 1200.0}.
Actually i want to fetc only customer id but getting whole dictionary.
Here in Login Class in views.py i fetch whole customers info like this
request.session['customer'] = customer.__dict__
Here is the details :
class Login(View):
def get(self, request):
return render(request, 'signupsignin/signin.html')
def post(self, request):
phone_number = request.POST.get('phone_number')
password = request.POST.get('password')
customer = Customer.get_customer(phone_number)
error_message = None
if customer:
match = check_password(password, customer.password)
if match:
customer.__dict__.pop('_state')
request.session['customer'] = customer.__dict__
# request.session['customer'] = customer.id
#request.session['customer'] = customer.coin
#request.session['phone_number'] = customer.phone_number
return redirect('Home')
else:
error_message = 'Phone number or Password didnt match on our record'
else:
error_message = 'No Customer Found! Please Registrer First!'
print(phone_number, password)
context = {'error_message':error_message}
return render(request, 'signupsignin/signin.html', context)
I think for that reason i am getting the whole informaton of a customer
Here is my Views.py for userorders by customer id ::
class UserOrders(View):
def get(self, request):
customer = request.session.get('customer')
user_orders = Order.get_orders_by_customer(customer)
print(user_orders)
args = {'user_orders':user_orders}
return render(self.request, 'Home/all_orders.html', args)
Here i have a method named get_orders_by_customer() i made this in models.py
Here it is ::
#staticmethod
def get_orders_by_customer(customer__id):
return Order.objects.filter(customer=customer__id)
So what i am trying to do is customers can see their own orders.I have a panel called "all orders" here a customer can see their own order only.
Please Help me i got really confused here
As per my understanding, you have to pass a number, but you're passing a whole dictionary.
#staticmethod
def get_orders_by_customer(customer__id):
return Order.objects.filter(customer=customer__id)
here before return try to debug with a print or something. and you'll see what I mean.
try this and it should work, if im not wrong:
costomer__id['id'] instead of costomer__id
or change your code into this:
#staticmethod
def get_orders_by_customer(customer):
return Order.objects.filter(customer=customer['id'])
You can try using values() query to achieve your purpose.
Here is the link to the documentation - https://docs.djangoproject.com/en/3.1/ref/models/querysets/#values
In my project, the user is entering data in a settings page of the application and it should update the database with the user's settings preference. I read this answer by Alasdair and how using the __init__() will allow to access the user's details. I was wondering if it's possible to return data from __init__() so I can validate the entered data before calling the save() function in the view? This is what I tried (and did not work). I am open to going about this in a better approach so I appreciate all your suggestions!
**EDIT: ** I am deciding on moving the validation of the data entered by the user in the forms file because when I wrote it in my views, I ended up getting 5 if statements (nested). IMO, and given the situation of this application, moving it to the forms seems to be a cleaner approach. I also considered using the clean_['field'] but I need the side variable from the __init__() function to do that and I am not sure how to extract that value.
Forms.py
class t_max_form(forms.ModelForm):
side = None
def __init__(self, *args, **kwargs):
side = kwargs.pop('side', None)
super(t_max_form, self).__init__(*args,**kwargs)
if side == "ms":
self.fields['hs_max_sessions'].widget.attrs.update({'class':'form-control', 'readonly':True})
self.fields['ms_max_sessions'].widget.attrs.update({'class':'form-control mb-3'})
elif side == "hs":
self.fields['hs_max_sessions'].widget.attrs.update({'class':'form-control'})
self.fields['ms_max_sessions'].widget.attrs.update({'class':'form-control', 'readonly':True})
else:
self.fields['hs_max_sessions'].widget.attrs.update({'class':'form-control'})
self.fields['ms_max_sessions'].widget.attrs.update({'class':'form-control'})
#Trying to validate the data here
valid_session_count = settings.objects.first()
if(side == "ms"):
input_sessions = self.fields['ms_max_sessions'].widget.attrs['readonly']
if(input_sessions > valid_session_count.max_sessions):
self.add_error("ms_max_sessions", "You have entered more than the limit set by the TC. Try again")
elif(side == "hs"):
input_sessions = self.cleaned_data['hs_max_sessions']
if(input_sessions > valid_session_count.max_sessions):
self.add_error("hs_max_sessions", "You have entered more than the limit set by the TC. Try again")
else:
input_sessions = self.cleaned_data['ms_max_sessions'] + self.cleaned_data['hs_max_sessions']
if(input_sessions > valid_session_count.max_sessions):
self.add_error("hs_max_sessions", "You have entered more than the limit set by the TC. Try again")
return input_sessions
And this is what I was trying in my views
views.py
def t_time_slots(request):
name = request.user.username
t = t_info.objects.get(student__user__username = name)
timeSlots = tutor_time_slot.objects.filter(tutor = tutor).order_by('time')
side = decide_side(request.user)
if request.method == 'POST':
form = t_time_slot_form(request.POST)
if form.is_valid():
if check_unique_time_slot(request.user, form.cleaned_data['day'], form.cleaned_data['time']):
timeSlots = form.save(commit=False)
timeSlots.t = t
timeSlots.save()
messages.success(request, "Added Successfully")
return redirect('TTimeSlot')
else:
print("Overlap")
messages.error(request, "The time slot overlaps with a Current one. Please Change the time and try again.")
return redirect('TTimeSlot')
else:
form = t_time_slot_form()
context = {'timeSlots': timeSlots, 'form': form, 'side':side}
return render(request, 't/t_time_slot.html', context)
Set self.side in the __init__ method, then you can access it in the clean() or clean_<field> methods.
I would avoid putting validation code in the __init__ method.
class MyForm(forms.Form):
my_field = forms.CharField()
def __init__(self, *args, **kwargs):
self.side = kwargs.pop('side', None)
super(t_max_form, self).__init__(*args,**kwargs)
...
def clean_my_field(self):
my_field = self.cleaned_data['my_field']
# Use self.side to validate data
if my_field = self.side:
raise forms.ValidationError("Invalid")
return my_field
Im using django 1.10 + Apache in Linux.
I've created a small webapp to upload documents (with dropzone.js) and want to implement the ability for a user to specify who can view/modify/delete a specific file but i can't figure out a way how. I attempted using a ManyToManyField but maybe im not understading the Field itself correctly.
The "Document" model is this:
Model
class Document(models.Model):
file = models.FileField(upload_to = 'files/')
#validators=[validate_file_type])
uploaded_at = models.DateTimeField(auto_now_add = True)
extension = models.CharField(max_length = 30, blank = True)
thumbnail = models.ImageField(blank = True, null = True)
is_public = models.BooleanField(default = False)
accesible_by = models.ManyToManyField(User) #This is my attempt at doing this task.
def clean(self):
self.extension = self.file.name.split('/')[-1].split('.')[-1]
if self.extension == 'xlsx' or self.extension == 'xls':
self.thumbnail = 'xlsx.png'
elif self.extension == 'pptx' or self.extension == 'ppt':
self.thumbnail = 'pptx.png'
elif self.extension == 'docx' or self.extension == 'doc':
self.thumbnail = 'docx.png'
def delete(self, *args, **kwargs):
#delete file from /media/files
self.file.delete(save = False)
#call parent delete method.
super().delete(*args, **kwargs)
#Redirect to file list page.
def get_absolute_url(self):
return reverse('dashby-files:files')
def __str__(self):
return self.file.name.split('/')[-1]
class Meta():
ordering = ['-uploaded_at']
My View to handle the creation of documents:
View
class DocumentCreate(CreateView):
model = Document
fields = ['file', 'is_public']
def form_valid(self, form):
self.object = form.save(commit = False)
## I guess here i would Add the (self.request.user) to the accesible_by Field.
self.object.save()
data = {'status': 'success'}
response = JSONResponse(data, mimetype =
response_mimetype(self.request))
return response
Thanks in advance to anyone for any ideas or suggestions...
You have a model and a view that hopefully works for adding new documents, you still have a number of steps to go.
You'll need a place to assign users that can view/modify/delete your files. If you need to store access levels (view/delete...), your accessible_by will not suffice and you'll do well with a through table to add more information like access level.
You need to write views for various actions like view, delete... that users will request and here you ensure users have the right privileges. An implementation would be to get the request.user and the document id, look up if the user has the permission for what she's doing, return an http unauthorized exception or allow the action to proceed.
Edit: My question is about how can I assign user-permissions to each
individual file
If we're keeping this to access control from the django level, using the document model you already have, and you've taken some steps and for every document, you can assign users (accessible_by). Something like this can get you started:
from django.core.exceptions import PermissionDenied
def view_document(request, doc_pk):
doc = get_object_or_404(Document, pk=doc_pk)
if not doc.accessible_by.filter(username=request.user.username):
raise PermissionDenied
#perform rest of action
Or do you mean to use the permissions framework itself?
I currently have a model form that submits an entered domain to the db.
The problem I'm encountering is, I need to save the currently logged in user's ID (PK from the django.auth table) when a domain is submitted to satisfy a PK-FK relationship on the db end.
I currently have:
class SubmitDomain(ModelForm):
domainNm = forms.CharField(initial=u'Enter your domain', label='')
FKtoClient = User.<something>
class Meta:
model = Tld #Create form based off Model for Tld
fields = ['domainNm']
def clean_domainNm(self):
cleanedDomainName = self.cleaned_data.get('domainNm')
if Tld.objects.filter(domainNm=cleanedDomainName).exists():
errorMsg = u"Sorry that domain is not available."
raise ValidationError(errorMsg)
else:
return cleanedDomainName
and views.py
def AccountHome(request):
if request.user.is_anonymous():
return HttpResponseRedirect('/Login/')
form = SubmitDomain(request.POST or None) # A form bound to the POST data
if request.method == 'POST': # If the form has been submitted...
if form.is_valid(): # If form input passes initial validation...
domainNmCleaned = form.cleaned_data['domainNm'] ## clean data in dictionary
clientFKId = request.user.id
form.save() #save cleaned data to the db from dictionary`
try:
return HttpResponseRedirect('/Processscan/?domainNm=' + domainNmCleaned)
except:
raise ValidationError(('Invalid request'), code='300') ## [ TODO ]: add a custom error page here.
else:
form = SubmitDomain()
tld_set = request.user.tld_set.all()
return render(request, 'VA/account/accounthome.html', {
'tld_set':tld_set, 'form' : form
})
The problem is it gives me an error of: (1048, "Column 'FKtoClient_id' cannot be null"), very odd thing happening, for the column FKtoClient, its trying to submit: 7L instead of 7(the PK of this user's record). Any ideas?
If someone can please help, I would really appreciate it
Firstly, remove FKtoClient from your form. You need to set the user in your view where you can yes the request object. It's not possible to set an attribute on the form that automatically sets the current user.
When instantiating your form, you can pass a tld instance which already has the user set.
def AccountHome(request):
# I recommend using the login required decorator instead but this is ok
if request.user.is_anonymous():
return HttpResponseRedirect('/Login/')
# create a tld instance for the form, with the user set
tld = Tld(FKtoClient=request.user)
form = SubmitDomain(data=request.POST or None, instance=tld) # A form bound to the POST data, using the tld instance
if request.method == 'POST': # If the form has been submitted...
if form.is_valid(): # If form input passes initial validation...
domainNm = form.cleaned_data['domainNm']
form.save() #save cleaned data to the db from dictionary
# don't use a try..except block here, it shouldn't raise an exception
return HttpResponseRedirect('/Processscan/?domainNm=%s' % domainNm)
# No need to create another form here, because you are using the request.POST or None trick
# else:
# form = SubmitDomain()
tld_set = request.user.tld_set.all()
return render(request, 'VA/account/accounthome.html', {
'tld_set':tld_set, 'form' : form
})
This has an advantage over #dm03514's answer, which is that you can access the user within form methods as self.instance.user if required.
If you want to Require that a user be logged in to submit a form, you could do something like:
#login_required # if a user iS REQUIRED to be logged in to save a form
def your_view(request):
form = SubmitDomain(request.POST)
if form.is_valid():
new_submit = form.save(commit=False)
new_submit.your_user_field = request.user
new_submit.save()
You can get the logged in user from the request object:
current_user = request.user
class Member(models.Model):# member db table
userID = models.CharField(max_length=80,primary_key=True) #user id
password = models.CharField(max_length=32)# password
nickname = models.CharField(max_length=100)# user nickname
penalty = models.PositiveSmallIntegerField(max_length=10,default=0,null=True)
participation=models.ForeignKey('Room',default=None,blank=True,null=True)
def __unicode__(self):
return self.userID
def doJoin(request):
if request.is_ajax() and request.method == 'POST':
# check validation
userID = request.POST['userID']
userNickname = request.POST['nickname']
if (checkID(userID) == False) and (checkNickname(userNickname) == False) :
#save to the database
newUser = Member()
newUser.userID = userID
newUser.nickname = userNickname
newUser.password = request.POST['password']
print newUser.userID , newUser.nickname , newUser.password , newUser.penalty , newUser.participation
newUser.save() #<------------error line!!!!
return HttpResponse('true')
else:
return HttpResponse('false')
else:
HttpResponse('false')
line about 8
In function doJoin:
newUser.save() # <--- error... so sad...
What should I do? Help me please.
What's wrong in this source?
Do you have debugging turned off? If you're getting a 500 and you have debugging turned on, you'll get a stack trace with the exception.
What are checkID() and checkNickname() doing? If those are performing some sort of validation, you really should be doing that in a form class instead of in the view. I also wouldn't be pulling values directly out of the request.POST to populate your model. I would highly recommend retrieving those values from a form's cleaned_data dictionary.