Displaying user uploaded image in Python Django - python

I am creating a website using the Django python framework and am currently stuck on a problem.
I am using function views to display a page called myaccount, and on 'myaccount' i would like all user details to be displayed using context objects, for this page it is 'user'. I also have another model called Profile, which holds the profile picture and date of birth of the user. However when i attempt to display the image which has been uploaded during the account creation into the media folder named '/media/%y/%m/%d/imagename.filextension' i receive an error saying "The 'profilepicture' attribute has no file associated with it." I have been searching vastly for fixes to this issue and have so far found no result which has worked, i have tried to create a property function which gets the url from the image called 'get_absolute_url' by doing user.profile.profilepicture.get_absolute_url but it fails to work and displays the same error. I was wondering if anyone could point me in the direction of a fix for this or a solution.
I also do have pillow installed.
The code to display the image, views.py and urls.py is down below
views.py
#login_required
def myaccount(request):
return render(request, 'account/myaccount.html', {'section': 'myaccount'})
urls.py
path('', views.myaccount, name='myaccount'),
myaccount.html
<img src="{{ user.profile.profilepicture.url }}" width="260" height="234"/>
Profile model
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date_of_birth = models.DateField(blank =True, null =True)
profilepicture = models.ImageField(upload_to='users/%Y/%m/%d', blank=True)
def __str__(self):
return f'Profile for user {self.user.username}'
The model for User is from 'django.contrib.auth.models'
To confirm whether it was a problem with the context object I tried to display the users first name which worked as expected.
The account register view
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# Set the chosen password
new_user.set_password(
user_form.cleaned_data['password'])
# Save the User object
new_user.save()
Profile.objects.create(user=new_user)
# Create the user profile
return render(request,
'account/register_done.html',
{'new_user': new_user})
else:
user_form = UserRegistrationForm()
return render(request,
'account/register.html',
{'user_form': user_form})
If any other code or information is needed please ask.

After some using some common sense I realised that I actually didn’t have a photo uploaded for the profile picture attribute which would explain there being no url for it... Thanks for the help anyway and sorry for wasting time, I’ve also used an if block now to stop the error from being ran if there is no picture associated with the profile.

Since you are using ImageField, have you also installed the Pillow library using PIP install Pillow?

Related

django URLs MultipleObjectsReturned error

I am making a simple webapp with Django. A user can have a profile, and under that profile create a blog post.
For example:
"path('profile/<int:pk>/',profile, name='profile')"
Returns the URL
"http://127.0.0.1:8000/profile/1/"
A user can then write blog posts which have the name in the URL
Example:
path('profile/<int:pk>/blog/<str:name>',Blogs, name='Blogs'),
Returns the URL
"http://127.0.0.1:8000/profile/1/blog/HelloWOrld"
However, IF two different users both name their blogs the same exact name, i get a 'MultipleObjectsReturned' Error.
I thought that by having the user PK earlier in the URL it would ensure that it would be unique, even if two blogs were called the exact same thing.
Views.py
def Blog(request, pk, name):
blog = Restaurant.objects.get(name=name)
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'user': user,
'blog': blog,
}
return render(request, 'blog/blogs.html',context)
IS there any way to work around this without using the PK of the blog as well?
And if anyone could explain why my logic was wrong and it wasn't working in the first place.
Thanks.
You need to make sure you get the blog of that name of that user. I don't know exactly how your blog models look, but it's going to be something like
user = CustomUser.objects.get(pk=pk)
blog = Restaurant.objects.get(name=name, user=user)
And on the model, use the 'unique_together' property to ensure that the combination of user and blog name are unique, otherwise these URLs aren't going to work. Having the name completely unique as in George's answer isn't necessary and would mean that users couldn't create blog posts with titles already made by another user.
You need to make name field unique, and use SlugField for this if you want to use clean url:
class Restaurant(models.Model):
name = models.CharField(unique=True, ...)
slug = models.SlugField(unique=True, ...)
...

How do you call a user defined function in views.py DJANGO

The requirement is to display the logged in username and his role in the organization in all the pages at the top right corner.
The role can be identified by the permissions he is given.
My approach:
I thought of creating a user-defined function in views.py and call it in each and every other function. The function that I create should check the current user's permissions and based on them his role should be decided. All these details must be sent to base.html so that it will render and display the username and his role every time the page is loaded.
Any suggestions on other approaches are welcomed and if my approach is entirely wrong please let me know.
In the views you could do something like:
context = {
'username': username,
'role': role,
}
return render('template.html', context)
and in template.html you would then render it like:
{username} {role}
You can find your answer in the comments section of: Can I call a view from within another view?
btw, yes you can create a method to validate user/department. below is the sample of how I have done in my app.
A better approach I feel is to save such details in DB as a boolean flag and use django admin's capabilities to ease your work.
def validate_details(request):
user = request.GET['username']
user_details = User.objects.filter(name=user).values_list("name", "department", flat=True)
# Call validation method defined in view
is_ok = validate_user(user_details)
if is_ok:
return render_to_response("main/landing.html", {"user": user_details["name"],"department":user_details["department"]}, context_instance=RequestContext(request))
else:
return render_to_response("main/landing.html", {"user":"NA","department":"NA"}, context_instance=RequestContext(request))

Am I able to create a form that is able to add a new django.contrib.auth User without logging in to the admin panel?

Have created a form but unsure if is right and also unable to add a user, it will show TypeError/
This is how the form I want it to look like
The following is my coding:
class Form_Add_User(forms.Form):
name=forms.CharField(label="Name", max_length=50)
dateofbirth=forms.DateField(label="Date of Birth", widget=forms.widgets.DateInput(format="%m/%d/%Y"))
contactnum=forms.CharField(label="Contact Number", max_length=9)
def adduser(request):
if len(request.POST)>0:
form=Form_Add_User(request.POST)
if(form.is_valid()):
name=form.cleaned_data['name']
dateofbirth=form.cleaned_data['dateofbirth']
contactnum=form.cleaned_data['contactnum']
new_user=User(name=name,dateofbirth=dateofbirth,contactnum=contactnum)
new_user.save()
return redirect('/adduser')
else:
return render(request,'adduser.html',{'form':form})
else:
form=Form_Add_User
return render(request,'adduser.html',{'form':form})
First off: it's always very useful to also post a full error message if you have one. The more info you give us, the easier (and quicker!) is answering your question.
I assume, your User model is not actually django's auth User model (see, if you had posted the model, I wouldn't have to guess).
The form you pass to your template was not instantiated:
#...
else:
form=Form_Add_User() #!!
return render(request,'adduser.html',{'form':form})

How to create a very simple search view for one column of mysql data in Django?

I have searched around and see that most are pointing to a search that was created by Julien Phalip: http://julienphalip.com/post/2825034077/adding-search-to-a-django-site-in-a-snap
Also the answer seems to be here: Very simple user input in django
However I am very new to Django and wanted to create a view where I actually understand what is happening so I have been going through the official Django and the Tango with Rango tutorials but I do not see a straightforward example of what I am trying to understand in regards to a simple form search. The main question I have is why is POST used in the example instead of GET? I thought POST was used to "create" data entries in mysql whereas GET is used to lookup/search for data entries? Am I missing something fundamental about using one vs the other?
I have the following simple example from my app:
models.py
class hardware(models.Model):
text = models.CharField(max_length=200, unique=TRUE)
pub_date = models.DateTimeField(default=timezone.now)
def __unicode__(self):
return self.text
class Barcode(models.Model):
hardware = models.ForeignKey(Hardware)
text = models.CharField(max_length=50)
pub_date = models.DateTimeField(default=timezone.now)
def __unicode__(self):
return self.text
forms.py
class HardwareForm(forms.modelForm):
class Meta:
model = Hardware
fields = ['text'}
views.py
def hardware_search(request):
if request.method == 'POST':
search_id = request.POST.get('textfield', None)
try:
hardwarename = Hardware.objects.get(text = search_id)
html = ("<H1>%s</H1>", hardwarename)
return HttpResponse(html)
except Hardware.DoesNotExist:
return HttpResponse("no such hardware found")
else:
return render(request, 'search.html')
search.html
<form method="POST" action="/hardware_search.html">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Upload text</button>
</form>
My questions are is this the most simple way to request user input to search for and generate the search results? Why is POST used? I plugged in this code and it does seem to work but i just can't understand why.
Secondly how can I display asssociated foreignkey class along with the main class 'hardware' search results? Does the ForeignKey association give a shortcut way of displaying that data as well?
thanks!
The W3 has an excellent introduction to POST vs GET here. There is a lot to be said for why someone might use POST or GET, and what their roles should be. You are probably more interested in the differences from the user's (browser's) perspective. The biggest differences between using POST and GET in a browser, is that the GET request will display the parameters in the URL. Change your form to GET to see for yourself. The user will be taken to:
/hardware_search.html?textfield=Upload%20text
As opposed to where they are taken to when the form action is POST:
/hardware_search.html
The value of the textfield field is still sent to the server, but is not visible in the URL.
There are quite a few other differences in the behavior of GET and POST in form submission. I would highly recommend reading over that introduction by the W3.
You're right, POST is not really appropriate for a search form. Using GET here would be better.
The other thing wrong is that there's no need at all for a ModelForm, or really for any kind of Django form. You're not doing any validation, you're not even using the form for output, so it would be better to leave that out altogether. That makes the view look like this:
def hardware_search(request):
query = request.GET.get('textfield', None)
if query:
try:
hardwarename = Hardware.objects.get(text = query)
html = ("<H1>%s</H1>", hardwarename)
return HttpResponse(html)
except Hardware.DoesNotExist:
return HttpResponse("no such hardware found")
else:
return render(request, 'search.html')
and you can change the form action to GET.

ImageField Upload with Django

I am trying to upload an image with django and so far i can't see the upload_to directory get created or any file source in the database field.
My Model.
class Person(models.Model):
photo = models.ImageField(upload_to='profiles/', null=True, blank=True)
My View
def create_profile(request):
if request.method == "POST":
form = PartialPersonForm(request.POST, request.FILES,)
addressForm = PartialAddressForm(request.POST)
When i upload and save, i dont get any sort of errors. Anyway i can debug this and find out if the photo field is set.
<div class="photo-upload">{{ form.photo|attr:"onchange:readURL(this);" }}
Unless you're doing something special with regard to media storage, you should set up MEDIA_ROOT to the directory where you want the uploaded files to be saved.
When dealing with file-type fields, you will need to following instructions in the Django documentation for FileField.storage.
In your view, you will need to save() the uploaded form data.
def create_profile(request):
if request.method == "POST":
form = PartialPersonForm(request.POST, request.FILES,)
addressForm = PartialAddressForm(request.POST)
form.save()
addressForm.save()
i believe you should create the upload_to directory yourself. Also make sure to set the appropriate permissions for the directory, otherwise it won't be able to write in it.

Categories

Resources