Django query not working - python

Here's the thing. I have a model called User and an attribute counter that counts the number of page access. So, if a user already exists, I have to query up the db and for that user only to increase in counter. Otherwise, create a new user. I have an annoying error in the get method. How can I surpass it? if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
u = form.save()
try:
obj = User.objects.get(user=u.user)
obj.counter += 1
obj.ipaddress = request.META['REMOTE_ADDR']
obj.save()
except Statistic.DoesNotExist:
ip = request.META['REMOTE_ADDR']
obj = User(user=u.user, counter=1, ipaddress=ip)
obj.save()
return {'status': 'OK'}
else:
return {'errors': form.errors}
return {'status': 'NOT OK. GET method'} Here's the errorget() returned more than one User -- it returned 2! Lookup parameters were

Django has amazing documentation on their QuerySet API. https://docs.djangoproject.com/en/dev/ref/models/querysets/
get only returns exactly 1 queryset. If no queryset is found, or more then 1 queryset is returned, an error is raised.
To catch this particular error you have to specify except User.MultipleObjectsReturned,

This means there are multiple users matching the query in your database. get should be used to fetch only one. It seems you are already coding for this but I think you are catching the wrong exception type. Try changing
except Statistic.DoesNotExist:
To
from django.core.exceptions import DoesNotExist
except DoesNotExist:

Related

Pass a variable to another function and render an html template at the same time in django

We want to access the same variable in every function inside our views.py. Since it is not constant, we cannot use it as a global variable.
Is it possible to pass a variable to another function while also rendering an HTML template? What are the alternatives if none exist?
This is our login function in views.py
def loginpage(request):
errorMessage = ''
# Applicant Login
if request.method=="POST":
if request.POST.get('username') and request.POST.get('pwd'):
try:
currentUser=Applicant.objects.get(username=request.POST['username'],pwd=request.POST['pwd'])
currentUser=Applicant.objects.get(username=request.POST['username'])
first = currentUser.firstname
middle = currentUser.middleinitial
last = currentUser.lastname
AppDashboard = ApplicantDashboardPageView(currentUser, request)
except Applicant.DoesNotExist as e:
errorMessage = 'Invalid username/password!'
return render(request, 'home.html')
The currentUser variable inside our login function is the variable we want to pass in this function
def ApplicantdashboardPageView(currentUser, request):
appPeriod = ApplicationPeriod.objects.all()
exam = ExaminationSchedule.objects.all()
posts = Post.objects.all().order_by('-created_on')
form = PostForm()
name=userNaCurrent
print('from storeCurrentUser', name)
if request.method == "GET":
try:
posts = Post.objects.all().order_by('-created_on')
form = PostForm()
#applicantID=currentUser.id
#applicantNotification = Applicant.objects.get(id=applicantID)
return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts, 'appPeriod':appPeriod, 'exam':exam})
except ObjectDoesNotExist:
return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts,})
return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts, 'appPeriod':appPeriod, 'exam':exam})
I am new to Django so please bear with me if my question seem too basic. Thank you
Store raw user password is a very big flaw in security. Please read more about Django Authentication system https://docs.djangoproject.com/en/4.1/topics/auth/
Basically, to store critical confidential information like passwords you need to at least, encrypt it. But for passwords you don't need to see the raw value of it, isn't it? Therefore, you just need to hash it and compare it every time you need to authenticate the user. Read more here Best way to store password in database
Django Auth system will also help to solve the issue by injecting the current user into a "global" request object so that you can access it everywhere.
You can do the same by keeping those 2 methods in a class and accessing variables by creating objects for it.

local variable 'user' referenced before assignment error in django function

I have this function in django that adds a new item to the wishlist, the function is doing what it should do but when I add a new user that was not registered, when adding an item to the wish list it returns this error, but when i refresh the page the error no longer exist.
I think the problem is that when a new user registers, he still does not have the database created in the wishlist model, so the try: condition fails because the user does not yet exist in the model, passing the except: condition where the user database is created, but I have to manually refresh the page so that the page no longer shows me the error.
How can I fix this so that the page no longer shows me this error?
def add_or_remove(request, listing_id):
if request.method == "POST":
if (request.POST["action"]) == "add":
try:
user = Wishlist.objects.get(user=request.user)
listing = Listing.objects.get(pk=listing_id)
user.item.add(listing)
except:
create = Wishlist(
user=request.user,
)
create.save()
user.item.add(listing)
messages.success(request, 'you added to Wishlist')
elif (request.POST["action"]) == "remove":
user = Wishlist.objects.get(user=request.user)
item = user.item.get(id=listing_id)
user.item.remove(item)
messages.success(request, 'you removed from Wishlist')
return redirect(reverse("listing", args=[listing_id]))
Django ORM's 'get' function may raise an exception when the requested object is not in the database, you can assure the existence of the 'user' object before going to the next line with a simple logic like this (I've renamed it to 'wishlist' according to the model name):
try:
wishlist = Wishlist.objects.get(user=request.user)
except Wishlist.DoesNotExist:
wishlist = Wishtlist(user=request.user)
wishlist.save()
Or you can use Django's built-in get_or_create() function that does the same thing out-of-the-box.
wishlist = Wishlist.objects.get_or_create(user=request.user)
Please note that your naming conventions may be a little misleading. And also, you need the same logic for the 'listing' object after 'user'.
As the error suggests, simply assign it as empty string at just starting of POST method, so:
def add_or_remove(request, listing_id):
if request.method == "POST":
user=""
if (request.POST["action"]) == "add":
try:
user = Wishlist.objects.get(user=request.user)
listing = Listing.objects.get(pk=listing_id)
user.item.add(listing)
except:
create = Wishlist(
user=request.user,
)
create.save()
user.item.add(listing)
messages.success(request, 'you added to Wishlist')
elif (request.POST["action"]) == "remove":
user = Wishlist.objects.get(user=request.user)
item = user.item.get(id=listing_id)
user.item.remove(item)
messages.success(request, 'you removed from Wishlist')
return redirect(reverse("listing", args=[listing_id]))

How can i fetch my data from database to django template?

Whenever I run this,
Exception Value:
name 'current_user' is not defined;
error is raised.
I am not getting where i am doing the mistake as I m new in django programming. Please help me fetch the data
# To add a new product in the database
def AddNewProduct(request):
if request.method == "POST":
current_user = request.user
product_title =request.POST['product_title']
uid = request.POST['uid']
specification =request.POST['specification']
sale_price = request.POST['sale_price']
discount = request.POST['discount']
img1 = request.FILES['img1']
img2 = request.FILES['img2']
promote_method = request.POST['promote_method']
terms_conditions = request.POST['terms_conditions']
newproduct = AffProduct(user_id=current_user.id, product_title=product_title, uid=uid, specification=specification, sale_price=sale_price,
discount=discount, img1=request.FILES.get('img1'), img2=request.FILES.get('img2'),
promote_method=promote_method, terms_conditions=terms_conditions)
newproduct.save()
# Status message
messages.success(request, 'Product added successfully')
return render(request, 'blink_network.html')
else:
return render(request, 'blink_network.html')
#Here i m trying to fetch my data.
def showproduct(request):
if request.user.is_authenticated:
result = AffProduct.objects.filter(user_id=current_user.id)
else:
result = AffProduct.objects.all()
return render(request, 'blink_viewproduct.html', {'result': result})
It looks like you will be getting that problem from showproduct(request) because you don't define current_user in that method before calling it.
to call this
result = AffProduct.objects.filter(user_id=current_user.id)
you need to define current_user = request.user beforehand
Could you share the relevant models.py file as well? You probably linked the user model with the ForeignKey with the Product model. If you did this, you need to give current_user, not current_user.id, django handles the matching itself.
Also, I guess you are using django form. If you are using it, I recommend you to use it because you can increase the readability of your code by writing less code.

Django Integrity Error Handling

I have created a website for user registration with first name, last name, phone no and so on.
I have successfully established a connection to MySQL database. I want help regarding IntegrityError handling in django,since I'm a newbie.
When 2 users input same phone number, django takes me to its debug page with whole lots of information. Instead I want to notify the user then and there that another user with same phone number already exists. Please provide any pointers on this.
Following is my views.py file in which I process the form:
from django.shortcuts import render
from formProcessing.forms import UserForm
def form(request):
#This is using regular Django forms
#print request.POST
#form = EmailForm(request.POST or None)
#This is using model forms
form = UserForm(request.POST or None)
if form.is_valid():
new_instance = form.save(commit=True)
new_instance.save()
context = {"form": form }
template = "form.html"
return render(request,template,context)
In your UserForm you can overwrite clean method of your number attribute, lets say that your attribute is called 'number'
class UserForm(ModelForm):
#your user form attributes and stuff
def clean_number(self, value):
user_number = value
number_occurrences = User.objects.filter(number=user_number).count()
if number_occurrences > 0:
raise forms.ValidationError("You number is already taken by other user")
return self.cleaned_data
Check django docs about form validation
If you dont wan't to overwrite clean method and do it whitin your view. you can. (Is not elegant)
def form(request):
#This is using regular Django forms
#print request.POST
#form = EmailForm(request.POST or None)
#This is using model forms
number = request.POST.get('telephone')
number_occurrences = User.objects.filter(number=user_number).count()
if number_occurrences > 0:
context = {'error':'Number already exist'}
return render(request,template,context)
form = UserForm(request.POST or None)
if form.is_valid():
new_instance = form.save(commit=True)
new_instance.save()
context = {"form": form }
template = "form.html"
return render(request,template,context)
Before you create an object, query the db for the existence of that phone number.
if form.is_valid():
ph_number = #"Phone number from form"
if User.objects.filter(phone_number = ph_number).first():
return HttpResponse("The number already exists.")
new_instance = form.save(commit=True)
new_instance.save()
The first() method returns the index 0 of the queryset. So, if there is element 0 in the queryset, the error message will be displayed to the user.
you can probably do something with field validation, although I donĀ“t know exactly what your error is, or how the model is designed.
Anyway, you could try to look up whether the value is unique (i.e., look if another record exists with the same number), before trying to save it; this might be the cleanest.
https://docs.djangoproject.com/en/1.7/ref/forms/validation/#cleaning-a-specific-field-attribute
so something like:
def clean_telephone(self):
n = User.objects.filter(telephone=self.cleaned_data['telephone']).count()
if n > 0:
raise forms.ValidationError("telephone number is already in database")
return data
Or you could try to save it and catch the unique error with a try/except clause. This uses less databases access attempts.

Why Django test with blank data post does not work?

I'd like to understand why this testing case does not work: I'm testing that my signup form in my view returns errors when I try to submit an empty form.
In tests.py:
class SignupViewTestCase(TestCase):
def test_signup_post_blank(self):
resp = self.client.post(reverse(signup), {}) # blank data dictionary
self.assertFormError(resp, form='signup_form', field='email',
errors='Ce champ est obligatoire') # French version of "This field is mandatory"
In views.py:
def signup(request):
signup_form = SignupForm(request.POST or None)
if signup_form.is_valid():
ema = signup_form.cleaned_data['email']
raw_pwd = signup_form.cleaned_data['password']
try:
BizProfile.create(ema, raw_pwd)
except IntegrityError:
signup_form.errors['__all__'] = signup_form.error_class([
ERR_USER_EXISTS])
else:
messages.success(request, SUC_ACC_CREA)
messages.info(request, INF_CONN)
return redirect(signin)
return render(request, 'sign_up.html', locals())
When testing manually in my browser, I can see there IS actually an error on the email field when I submit it without data.
But test result says:
AssertionError: The field 'email' on form 'signup_form' in context 0 contains no errors
Any idea of what is happening? Thanks.
Actually, the problem is related to the or None.
That's because an empty dictionary is false. In an "or" condition, Python always returns the second value if the first is false. That means your form is being instantiated just with "None", rather than an empty dictionary: which means it is not being bound at all. A non-bound form does not have any errors.
Changing your test is not a good solution, because a browser would never submit the "email" key without a value: fields without values are simply not send in the POST data, which is why an empty dictionary is the right way to test this. Instead of changing your test, you should use the canonical view pattern, and remove that broken shortcut.
if request.method == 'POST':
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
...
else:
signup_form = SignupForm()
return...

Categories