I have an app, in which the main User adds a sub user and sends him an email. I want the sub user to have a button in the email template that would lead him/her to a Feedback form. That feedback form's url must have the user's name in it as it gives a personal touch. But I am not understanding how do I pass the sub user data and save the feedback data against the data. I will create a scenario to make you guys understand better.
1. There is a main user Chris, Chris adds a sub user Leon in his email list. (P.S both are Resident .Evil characters).
2. Chris sends an email to Leon, Leon will receive the email and if he want he can give a feedback by clicking the feedback button in email.
3. If Leon clicks the button he will be redirected to a page where the url could be something like this (www.feedback/Leon.com), there will be form where Leon will add his review and submit.
The problem is how do I save Leon's feed back in the FeedBack model through the email form against his information from the sub user model (PersonData).
models.py
class FeedBack(models.Model):
feedback = models.TextField('Feedback')
user_feedback = models.ForeignKey(PersonData)
class PersonData(models.Model):
user_relation = models.ForeignKey(User)
person_first_name = models.CharField("First Name", max_length=25)
person_last_name = models.CharField("last Name", max_length=25)
person_email = models.EmailField("Email", max_length=512)
views.py
# class FeedBackCreateView(CreateView):
# model = FeedBack
# template_name = "userfiles/FeedBack.html"
# def form_valid(self, form):
# obj = form.save(commit=False)
# obj.user_feedback_id = self.request.persondata_id
# obj.save()
# return redirect("Home-Page")
def feedback(request, username):
person_data = PersonData.objects.get(person_first_name=username)
item = FeedBack.objects.all().filter(user_feedback=person_first_name)
form = FeedBackForm
if request.method == 'POST':
if form.is_valid():
form.save(commit=False)
profile.employee_name = user
profile.save()
return redirect('Home-Page')
context = {'all_item': all_item}
return render(request, 'userfiles/AlbumPicsList.html', context)
------------------------------------------------------------------
#This View is from another app called salami. This sends the email
------------------------------------------------------------------
def send_email(request, s_id, pr_id):
salami_data = SalamiCalculator.objects.get(id=s_id)
person_data = PersonData.objects.get(id=pr_id)
context = {'salami_data': salami_data,
'person_data': person_data}
subject = "Thank You"
email_from = settings.EMAIL_HOST_USER # email from
to_email = [person_data.person_email] # email to
msg = EmailMultiAlternatives()
msg.from_email = email_from
msg.to = to_email
msg.subject = subject
msg.body = salami_data.thankyou_msg
html_body = render_to_string("salamifiles\email-thanks.html")
html_template = get_template("salamifiles\email-thanks.html")
html_content = html_template.render(context)
msg.attach_alternative(html_content, "text/html")
msg.send()
messages.success(request, ("Email Sent !!"))
return render(request, 'salamifiles\email-thanks.html', context)
url.py
url(r'^(?i)Feedback/(?P<user_feedback>\w+)/$',
AlbumPicturesDetail.as_view(), name='Album-Pictures-View'),
==============================================
Salami URL
==============================================
url(r'^Congratsmail/(?P<s_id>[0-9]+)/(?P<pr_id>\d+)/$',
views.send_email, name='Congrats-EMAIL'),
forms.py
class FeedBackForm(forms.ModelForm):
class Meta:
model = FeedBack
fields = ("feedback")
email.html
Have Not Yet modified the email template by adding the button
Email Sending template
{% for i in items %}
<a href={% url 'Congrats-EMAIL' s_id=i.id pr_id=i.realted_person.id %}>Send Mail</a>
{% endfor %}
=========================================================================
I expect when Chris send Leon the email, Leon by clicking on the button gets redirected to a page where the URL has his name and the form already is knows he's Leon so that it saves the data against his id/name.
I do not understand why you cannot do
class FeedBack(models.Model):
feedback = models.TextField('Feedback')
user_feedback = models.ForeignKey(PersonData, related_name="received_feedbacks")
giver_feedback = models.ForeignKet(PersonData, related_name="given_feedbacks")
I agree with #HenryM, You can add an extra field for relating to PersonData.
class FeedBack(models.Model):
feedback = models.TextField('Feedback')
user = models.ForeignKey(PersonData, related_name="received_feedbacks")
giver = models.ForeignKet(PersonData, related_name="given_feedbacks")
Then, you can use it like this:
from django.contrib.auth.decorators import login_required
#login_required
def feedback(request, username):
person_data = PersonData.objects.get(person_first_name=username)
item = FeedBack.objects.all().filter(user_feedback=person_first_name)
form = FeedBackForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
feedback = form.save(commit=False)
feedback.user = person_data
feedback.giver = PersonData.objects.get(user_relation=request.user)
feedback.save()
profile.employee_name = user
profile.save()
return redirect('Home-Page')
context = {'form': form}
return render(request, 'form_which_renders_feedbackform.html', context)
I would recommend using OneToOne relation instead of ForeignKey for user_relation field in PersonData. So that you can simply access it via request.user.persondata.
Related
I found posts with similar problem, but the solutions dont seem to work with me. Or maybe I am missing something.
I created a form in Django, but as a default it seems that every mandatory fields have this "this field is required" text above.
Ideally, I would like to have this only when someone tries to submit a form and a field is missing.
form.py
class ElderFlowerChampFormAdmin(ModelForm):
fieldsets=[
("Look",{'fields':[
('look_colour','look_clarity','look_effervescence')]}),
}
widgets = {
'user': forms.Select(attrs={'class':'form-control','required':'True'}),
'look_colour':forms.Select(attrs={'class':'form-control','required':'True'}),
}
view.py
def elderflowerchamp(request, product_id):
global ChampageRating
product = Product.objects.get(pk=product_id)
url = request.META.get('HTTP_REFERER')
submitted = False
try:
if request.method == "POST":
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST, instance=reviews)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST, instance=reviews)
if form.is_valid():
ChampageRating = form.save(commit=False)
ChampageRating.user = request.user
ChampageRating.save()
return redirect('home')
else:
#This part goes to the page, but doesnt submit
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
if 'submitted' in request.GET:
submitted = True
except:
reviews = None
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
return render(request,"main/ElderFlowerReview.html", {'form':form, 'submitted':submitted,'reviews':reviews, 'product':product})
models.py
LOOKCOLOUR=(
(1,'Straw'),
(2,'Yellow'),
(3,'Gold'),
(4,'Amber'),
)
class ChampageRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="champcomments", on_delete=models.CASCADE)
look_colour=models.IntegerField(choices=LOOKCOLOUR, default=0)
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
Any ideas
something wrong on case request.GET here:
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
You send the FormClass into the template context, and not the form instance.
Also see eror on the except case: If i have a GET, i should not render BoundedForm, here should be form.bounded = false (form is not bounded with any data). But you are always made the BoundedForm, with the request.POST data after error here:
reviews = ChampageRating.objects.get(pk=product_id)
My opinion is - you should try to read about Django-GCBV, it is better way to avoid complex errors, like in your question.
https://docs.djangoproject.com/en/4.0/topics/class-based-views/
I am trying to make the user submit a form only once. I have a /dashboard page which is shown after submitting the /petform. But, I want the user to submit the form only once after logging in and other times it should redirect to the /dashboard directly (or show a message that "form already submitted").
models.py
class PetFormData(models.Model):
abstract = True
name = models.CharField(max_length=100)
age = models.IntegerField()
breed = models.CharField(max_length=100)
amount_spent = models.CharField(max_length=100, choices=AMOUNT_CHOICES)
pincode = models.CharField(max_length=15)
services_required = models.CharField(max_length=100, choices=SERVICE_CHOICES)
auth_user_email = models.ForeignKey(User, on_delete=models.CASCADE)
form_submitted = models.BooleanField(default=False)
views.py
#login_required
def showformdata(request):
form = PetForm(request.POST)
if request.method == 'POST':
if not PetFormData.form_submitted and user == PetFormData.auth_user_email:
PetFormData.form_submitted = True
print(PetFormData.form_submitted)
if form.is_valid():
user = request.user
nm = form.cleaned_data['name']
age = form.cleaned_data['age']
breed = form.cleaned_data['breed']
am_sp = form.cleaned_data['amount_spent']
pin = form.cleaned_data['pincode']
ser_req = ','.join(form.cleaned_data['services_required'])
model_pet_form = PetFormData(name=nm, age=age, breed=breed, amount_spent=am_sp, pincode=pin,
services_required=ser_req, auth_user_email=user)
model_pet_form.save()
print(session_data)
return redirect('/dashboard')
else:
print(PetFormData.form_submitted)
return HttpResponse('Form already submitted', content_type="text/plain")
else:
form = PetForm()
return render(request, 'petform.html', {'form': form})
Successfully submitting the form once presumably stores something in the database. A subsequent visit to that page can interrogate the database, discover it has already been done, and display the appropriate next page.
Something like this (I don't fully understand your problem)
if PetFormData.objects.filter( auth_user_email = request.user).exists() :
return redirect('/dashboard')
# OK, user hasn't submitted yet.
I am trying to associate the user with the post. I have two models students is for user and sublists is for user posts with a foreign key(author). I am using MySQL database and using forms to store data into them. when my form.author execute in my HTML file it gives me a list of ids for all users in the databse but I am already logged in and i want to post as the logged in user without choosing. If remove it says my form is not valid which make sense since im not inputing for form.author.Since I'm using MySQL, I'm not using the built-in User authentication method, but instead comparing both email and password with the login form input. Spend too much time on this but hard to get around with this one. Any help would be appreciated
my views.py look like this
def addnew(request):
if request.method == 'POST':
form = Sublist(request.POST)
if form.is_valid():
try:
form.save()
messages.success(request, ' Subscirption Saved')
name = sublist.objects.get(name=name)
return render (request, 'subscrap/main.html', {'sublist': name})
except:
pass
else:
messages.success(request, 'Error')
pass
else:
form = Sublist()
return render(request, 'subscrap/addnew.html', {'form': form})
#login_required(login_url='login')
#cache_control(no_cache=True, must_revalidate=True, no_store=True)
def main(request):
return render(request, 'subscrap/main.html')
def mod(request):
student = students.objects.all()
return render(request, 'subscrap/mod.html' , {'students': student})
My Models.py
class students(models.Model):
fname = models.CharField(max_length=50)
lname = models.CharField(max_length=50)
password = models.CharField(max_length = 50 , null = True)
passwordrepeat = models.CharField(max_length = 50, null = True)
email = models.EmailField(max_length=150)
class Meta:
db_table = "students"
class sublist(models.Model):
author = models.ForeignKey(students, related_name='sublist' ,on_delete=models.CASCADE)
name = models.CharField(max_length=150)
cost = models.IntegerField(default = 0)
renewalcycle = models.IntegerField(default = 0)
class Meta:
db_table = "sublist"
Since I'm using forms here's my forms.py
lass StudentForm(forms.ModelForm):
class Meta:
model = students
fields = "__all__"
class Studentlogin(forms.Form):
email = forms.EmailField(max_length=150)
password = forms.CharField(max_length = 50, widget=forms.PasswordInput)
class Sublist(forms.ModelForm):
class Meta:
model = sublist
fields = "__all__"
Exclude the Author from the Sublist form:
class Sublist(forms.ModelForm):
class Meta:
model = sublist
exclude = ['author']
In the addnew method, you associate the .instance.author with the request.user:
#login_required(login_url='login')
def addnew(request):
if request.method == 'POST':
form = Sublist(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
messages.success(request, ' Subscirption Saved')
return redirect('some_view')
else:
messages.error(request, 'Error')
else:
form = Sublist()
return render(request, 'subscrap/addnew.html', {'form': form})
Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from sublist to Sublist.
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use SublistForm instead of
Sublist.
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 students directly. For more information you can see the referencing the User model section of the documentation.
This is my model
class User(models.Model):
name = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
class Phone(models.Model):
user = models.ForeignKey(Osoba, editable=False, related_name='phone', on_delete=models.CASCADE)
phone = models.CharField(max_length=50)
and i want to add phone to current User selected by ID and display it on site
i have tried that
def create_phone(request, id):
user = User.objects.get(id=id)
form = PhoneForm(request.POST or None, instance=user)
if form.is_valid():
form.save()
return redirect('list_users')
return render(request, 'index-phone.html', {'form': form})
But it doesnt work, when i click button, its not creating new Phone
My urls
urlpatterns = [
path('', list_users, name='list_users'),
path('new', create_user, name='create_user'),
path('/<int:id>/update', update_user, name='update_user'),
path('/<int:id>/delete', delete_user, name='delete_user'),
path('/<int:id>/', create_phone, name='create_phone')
]
I'm not sure about the content of your PhoneForm class, but I would guess that is a form to create and edit a Phone object. When instantiating a new PhoneForm the instance parameter should either be an existing Phone instance, or None.
You should set the user of the Phone instance another way, either by making it a field on the PhoneForm, or by manually setting the user.
This would be correct:
def create_phone(request, id):
user = User.objects.get(id=id)
form = PhoneForm(request.POST or None)
if form.is_valid():
# Setting commit to False does not save the object to the database yet.
# We do this because we still want to edit the object.
phone = form.save(commit=False)
phone.user = user
phone.save()
return redirect('list_users')
return render(request, 'index-phone.html', {'form': form})
I am trying to create a formset that captures a parameter from the url to prefill one of the fields. The form is displaying correctly and at the correct address, but after clicking "submit" the page redirects to "/correction/" instead of the intended /correction/A07686+dwdID19, and the form does not save. What might be the issue?
In models.py:
class correction(models.Model):
corrected_word = models.ForeignKey(item)
correction_author = models.ForeignKey(User)
correction_made = models.IntegerField(u'correction_made', choices=CORRECTION_CHOICES)
correction_word = models.CharField(u'correction_word', max_length=200, blank=True, null=True)
time = models.DateTimeField(auto_now_add=True)
approved = models.IntegerField(u'approved', choices=APPROVAL_CHOICES, blank=True, null=True)
def __unicode__(self):
return str(self.time)
In views.py:
def submit_corr(request, bdword):
if hasattr(request, 'user') and request.user.is_authenticated():
word = item.objects.filter(file_position=bdword)[0]
CorrFormSet = inlineformset_factory(item, correction, fields=['correction_made', 'correction_word','correction_author'], can_delete=False, extra=1)
form = CorrFormSet(request.POST, request.FILES, instance=word, initial=[{'correction_author': request.user,}])
if request.method == 'POST':
if form.is_valid():
for entry in form:
entry.save()
else:
form = CorrFormSet(instance=word, initial=[{'correction_author': request.user,}])
return render(request, "correctionform.html", {"form": form,"word": word})
In urls:
url(r'^correction/(?P<bdword>.*)$', 'english.views.submit_corr'),
In the template:
Submit correction</th>
Thanks in advance!
Submit correction doesn't submit a form because it's a link and when you press a link, this sends a request with a GET method to the server so never enter to if request.method == 'POST': .
Please try something like
<form action="/correction/{{word.file_position}}" method="POST">
{# your inputs fields#}
<button type="submit">Submit correction</button>
</form>
I hope to be useful. Regards