How to store user auto in database? - django

I created a form for adding products to an e-Commerce site. The form isn't working perfectly.
First issue: I want to store the user automatically by submitting the form. I actually want to store Who did add the product individually.
Second Issues: The image field is not working, the image is not stored in the database.
How can I fix these issues? help me
forms.py:
from django import forms
from .models import Products
from django.forms import ModelForm
class add_product_info(forms.ModelForm):
class Meta:
model = Products
fields = ('product_title','product_image')
model.py:
class Products(models.Model):
user = models.ForeignKey(User, related_name="merchandise_product_related_name", on_delete=models.CASCADE, blank=True, null=True)
product_title = models.CharField(blank=True, null=True, max_length = 250)
product_image = models.ImageField(blank=True, null=True, upload_to = "1_products_img")
views.py:
def add_product(request):
if request.method == "POST":
form = add_product_info(request.POST)
if form.is_valid():
form.save()
messages.success(request,"Successfully product added.")
return redirect("add_product")
form = add_product_info
context = {
"form":form
}
return render(request, "add_product.html", context)
templates:
<form action="" method="POST" class="needs-validation" style="font-size: 13px;" novalidate="" autocomplete="off" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="d-flex align-items-center">
<button type="submit" class="btn btn-outline-dark ms-auto" style="font-size:13px;">Add</button>
</div>
</form>

You need to set the .user of the .instance wrapped in the form to the logged in user (request.user). Furthermore you need to pass both request.POST and request.FILES to the form to handle files.
from django.contrib.auth.decorators import login_required
#login_required
def add_product(request):
if request.method == 'POST':
form = add_product_info(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
messages.success(request, 'Successfully product added.')
return redirect('add_product')
else:
form = add_product_info()
context = {
'form': form
}
return render(request, 'add_product.html', context)
I would also advise not to use null=True nor blank=True, unless a field is really optional. Likely the product_title should not be optional, nor should the user be, since you use CASCADE in case the user is removed.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: Forms in Django are written in PascalCase, not snake_case,
so you might want to rename the model from add_product_info to ProductInfoForm.
Note: normally a Django model is given a singular name, so Product instead of Products.

why are you using the ForeignKey with your user. the first issue i notice is with the class Meta. Pass this as a list not tuple.
class add_product_info(forms.ModelForm):
class Meta:
model = Products
fields = [
'product_title',
'product_image',
]
then try this as well.
class Products(models.Model):
user = models.OneToOneField(User, related_name="merchandise_product_related_name", on_delete=models.CASCADE, blank=True, null=True)

Related

Django get an instance of a object and pass it through to a form

I am new to Django and programming in general. I am trying to generate a list of records from a database but with two fields that can be edited.
In the browser it should show a line with the fields:
clientcode, clientname, Reason, comment
Name and description come from the model and are a reference. The user should only be able to capture reason and comments
I have created a forms.py file and a ModelForm. My issue is how do I pass through an individual object. For this example I've limited my dataset to 10 records
In my view file
def home(request):
if request.method == 'GET':
nca = NcaRe.objects.all()[:10]
form = NcaReForm(instance= <what should go in here> )
return render(request, 'NCAComments/home.html', {'form': form, 'nca': nca})
else:
pass
In my model I have a field called primarykey. I'm not sure how to pass this to the form so that I only bring in that record. I have tried looking at the documentation but have not been able to follow it.
My Model py.
from django.db import models
class NcaRe(models.Model):
primarykey = models.IntegerField(blank=True, null=False, primary_key=True)
clientcode = models.CharField(db_column='ClientCode', max_length=200, blank=True, null=True)
clientname = models.CharField(db_column='ClientName', max_length=510, blank=True, null=True)
reason = models.TextField(blank=True, null=True)
comment = models.TextField(blank=True, null=True)
class Meta:
db_table = 'NCA_RE'
Forms.py
from django.forms import ModelForm
from .models import NcaRe
class NcaReForm(ModelForm):
class Meta:
model = NcaRe
fields = ['reason', 'comment']
In html I am trying to loop through and pass the form
{% for n in nca %}
<p> {{n.clientcode}}</p>
<form>
{% csrf_token %}
{{ form }}
</form>
{% endfor %}
In general, you need to just return empty form if the method of request if GET like as form(). I write below sample code that you can do your calculation in after form validation form.is_valid()
views.py
from django.shortcuts import render
from testPhilip.forms import NcaReForm
from testPhilip.models import NcaRe
def home(request):
if request.method == 'GET':
nca = NcaRe.objects.all()[:10]
form = NcaReForm()
elif request.method == 'POST':
form = NcaReForm(request.POST)
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return render(request, 'testPhilip/home.html', {'form': form, 'nca': nca})
You can retrieve the data after form validation in a cleaned format like this:
comment = form.cleaned_data['comment']
Update:
If you want to populate your form fields with values from database or any default values, you can pass them in the 'GET' section as below:
nca_object=NcaRe.objects.get(pk=nca_id)
form=NcaReForm({
'comment':nca_object.comment,
'reason':nca_object.reason,
})
For more information about writing forms refer to Django forms doc

How can I autofill author with a model form (video upload)

I need to tie the user to their post but 'author' is not included in the fields of the video upload form so I can't access the field when I save the form.
When I add 'author' to the fields it gives a drop down box. (users shouldn't be able to post as anyone but themselves) I tried just listing the fields individually like so {{form.title}} to keep the author field but not show it to the user, it showed anyway.
In the 'author' field of the VideoPost model I've tried changing out the null=True for these variants on default default=None, default=0, default='None', default=User, default=User.id where User = get_user_model()
When I used default='None' the author dropdown box had the current users name in it, but still allowed a choice, when I tried to post it I got
ValueError: invalid literal for int() with base 10: 'None'
Also, in the views.py, I tried form = VideoPostForm(request.user,request.POST or None, request.FILES or None)
and got CustomUser object has no .get() attribute and that was caused by form.save()
I feel like this might be obvious to someone else but I've been staring at this code for a while now to figure it out.(a couple hours a day doing research and gaining better understanding as to how all of the things I'm doing actually work 'under the hood', I worked on other parts while trying to figure this out because, development speed matters and I could actually figure the other stuff out)
forms.py
class VideoPostForm(forms.ModelForm):
class Meta:
model = VideoPost
fields = ['author','title', 'description', 'file']
views.py
def upload_video(request):
form = VideoPostForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save(commit=False)
VideoPost.author = request.user
form.save()
return redirect('home')
else:
form = VideoPostForm()
return render(request, 'upload_video.html', {'form': form})
models.py
class VideoPost(models.Model):
objects = models.Manager()
author = models.ForeignKey(User, related_name='video_post', on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=50, null=True, blank=True)
published_date = models.DateTimeField(auto_now_add=True)
description = models.TextField()
validate_file = FileValidator(max_size=52428800)
file = models.FileField(upload_to='videos/', validators=[validate_file])
def __str__(self):
return 'Post by {}'.format(self.author)
template (excluding author field)
<h1>Create Post Page</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p> <!-- Normally the fields would be form.as_p -->
{{ form.title }}
{{ form.description }}
{{ form.file }}</p>
<button type="submit">Submit New Post</button>
</form>
The views.py is very close. The form.save() method returns an instance of VideoPost. You can then set the author to the current user directly to the new video post object that was created by the form. See code sample below.
views.py
def upload_video(request):
if request.method == "POST":
form = VideoPostForm(request.POST, request.FILES or None)
if form.is_valid():
new_videopost = form.save()
new_videopost.author = request.user
new_videopost.save()
return redirect('home')
else:
form = VideoPostForm()
return render(request, 'upload_video.html', {'form': form})

How to use Django's HTML form to edit a part of users profile.

I have a user profile model I use django model forms to create and edit the users profiles Now I want to change only 2 fields on the profiles lat and lon . So on my Index.html I have a small html form . As soon as the user clicks locate me. The latitude and longitude are automatically filed in and the submit button will be clicked using Jquery. How do I use the details from this form to update my users lat and lon. Its just that I have not used django's HTML form's and I need to update the lat lon entered on this mini form to the users profile
<form method="post" action="{{ ??????????? }}">
<input id="jsLat" type="text" placeholder="latittude" >
<input id="jsLon" type="text" placeholder="longitude">
<button type="submit" id="submit">Submit</button>
</form>
Do I create another view & url (that way I will have 2 profile edit views and 2 profile edit url's) to add the lat and lon to my existing profile. Or Is there a way I can use the existing view and url and update the 2 fields
below are my models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=100)
age = models.DateField(blank=True, null=True)
profile_image = models.ImageField(default='', blank=True, null=True)
null=True)
is_verified = models.BooleanField(default=False)
lat = models.FloatField(blank=True, null=True)
lon = models.FloatField(blank=True, null=True)
Below is my profiles view
#login_required
def edit_profile(request):
if request.method == 'POST':
user_form = UserEditForm(data=request.POST or None, instance=request.user)
profile_form = ProfileEditForm(data=request.POST or None, instance=request.user.profile, files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
return redirect('accounts:profile', username=request.user.username)
else:
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=request.user.profile)
context = {'user_form': user_form,
'profile_form': profile_form}
return render(request, 'accounts/profile_edit.html', context)
Below are my forms.py
class UserEditForm (forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'username')
class ProfileEditForm(forms.ModelForm): #UserProfileForm or ProfileEdit
class Meta:
model = Profile
fields = ('city', 'age', 'profile_image','lat','lon')
Below are my urls
urlpatterns = [
url(r'^profile/(?P<username>[-\w]+)/$', views.ProfileView.as_view(), name='profile'),
url(r'^edit_profile/$', views.edit_profile, name='edit_profile'),
#Profile created automatically when user is created
]
PS: I have trimmed the geodjango code from here as it's not a part of this question
You definitely can edit the details within the post of your view.
Firstly, in your HTML you should name your inputs.
<form method="post”>
<input id="jsLat" type="text" placeholder="latittude" name=“Lat” >
<input id="jsLon" type="text" placeholder="longitude" name=“Long”>
<button type="submit" id="submit">Submit</button>
</form>
Then in your post view you can retrieve the data by doing: lat = request.POST[‘Lat’] or lon = request.POST[‘Lon’]
Next step is to update the database entry.
To do this you need to retrieve the user’s object.
user = User.objects.get(instance=request.user)
Once you have this you can update fields in the following manner:
user.latitude = lat
user.longitude = lon
user.save()
Further reference:
1. Retrieving data from HTML form
2. Updating database entry
Hope this helps!
Edit:
It is rather recommended that you have the form as a Django form and then simply add the desired HTML attribute there. This allows you to call the form as you usually would for a Django form.

Django set ModelForm field without including it in the form

In my app, I have Users create Post objects. Each Post has a User
class Post(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
...
I want to create a post-submission form for editing and submission, so I plan to use Django's ModelForm functionality.
class PostForm(ModelForm):
class Meta:
model = Post
fields = "__all__"
However, if I do this, then whoever is viewing the form will be able to set who the Post author is. I want to make sure that the resulting user field is them. But, if I exclude the user field from the ModelForm,
class PostForm(ModelForm):
class Meta:
model = Post
exclude = 'user'
then the user will not be set on form submission. I've hacked my way around this by making a custom form and updating the post field
def submit_view(request):
....
request.POST = request.POST.copy()
request.POST.update({
'user' : request.user.id
})
form = PostForm(request.POST, request.FILES)
....
but then I lose automatic UI generation and form validation, which in some ways defeats the purpose of the Form class. Could somebody point me to the idiomatic way of setting the user field without including it in the Form?
Try this view:
def submit_view(request):
form = PostForm(request.POST or None)
if form.is_valid():
new_post = form.save(commit=False)
new_post.user = request.user
new_post.save()
view.py
from django.views.generic import CreateView
from .models import Post
class PostCreate(CreateView):
model = Post
template_name ="new_Post_form.html"
fields = ['text']
def form_valid(self, form):
object = form.save(commit=False)
object.user = self.request.user
object.save()
return super(PostCreate, self).form_valid(form)
def get_success_url(self):
return "/"
url.py
url(r'^newpost$',views.PostCreate.as_view(),name='post_new',),
new_post_form.html
<form method="post" enctype="multipart/form-data" class="form" action="newpost" id="new-post-form">
<div class="modal-body">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</div>

Django ImageField won't upload in function based view, but it does in the admin

I've been trying to add some user uploaded profile picture to my website. It works fine when I do it from the admin, the image is showed and all the engines seems to be working fine (image going to the correct upload location and so on). The problem is when I try to do the same thing from my view.
I noticed that the print("upload_location") only appears when I do it from the admin. The weird thing is that all the other fields in my Profile model are working fine (like name "foo" is updated to "foobar") and not only in the admin, but in the view as well. The issue is only with the ImageField.
I believe it could have something to do with the way I'm handling the form.is_valid(), but I've been playing around with that and nothing changed (I know it is working to some extend, since HttpResponseRedirect is working.
Any ideas?
views.py
...
#login_required
def profile_update(request, username=None):
obj = get_object_or_404(User, username=username)
user = obj.profile
form = ProfileForm(request.POST or None, instance = user)
context = {
"form": form
}
if form.is_valid():
form.save()
return HttpResponseRedirect('/profiles/{username}'.format(username=user.user))
template = 'profile_update.html'
return render(request, template, context)
forms.py
from django import forms
from .models import Profile
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = [
"profilePic",
"nome",
...
]
def profile(self, request, user):
print('printing forms')
user.uf = self.cleaned_data['uf']
user.cidade = self.cleaned_data['cidade']
user.telefone = self.cleaned_data['telefone']
user.save()
models.py
...
User = settings.AUTH_USER_MODEL # 'auth.User'
def upload_location(instance, filename):
print("upload_location")
return "%s/%s" %(instance.user, filename)
class Profile(models.Model):
user = models.OneToOneField(User)
id = models.AutoField(primary_key=True)
width = models.IntegerField(default=0, null=True, blank=True,)
height = models.IntegerField(default=0, null=True, blank=True,)
profilePic = models.ImageField(
upload_to = upload_location,
blank=True, null=True,
verbose_name = 'Foto de Perfil',
width_field="width",
height_field="height",
)
...
template.html
...
<form action="" method="POST" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Enviar" class="btn btn-primary"/>
</form>
...
You need to add FILES into the form.
form = ProfileForm(request.POST or None, request.FILES or None, instance = user)
Docs: https://docs.djangoproject.com/en/1.10/topics/http/file-uploads/