I've got a feedback app in django and it all seems to work fine, no errors i can submit the form and it all seems to work, however i have my model registered into my admin however when i submit the form i doesn't appear in my admin. Sorry if this is very basic i just cant get my head around it please help.
in my models.py
class Feedback(models.Model):
email = models.CharField(max_length=100)
message = models.CharField(max_length=1000)
def __unicode__(self):
return self.title
which i then pass through to forms.py
class FeedbackModelForm(forms.ModelForm):
class Meta:
model = Feedback
fields = ["email", "message"]
and my view is
def feedbackform(request):
form = FeedbackModelForm(request.Post or None)
if form.is_valid():
form.save()
return render(request, "feedback.html", {"form": form})
now in my html looks like this
{% block content %}
<div id="feedback">
<div id="feedback-form" style='display:none;' class="col-xs-4 col-md-4 panel panel-default">
<form method="POST" action="{{ form }}" class="form panel-body" role="form">{% csrf_token %}
<div class="form-group">
<input class="form-control" name="email" autofocus placeholder="Your e-mail" type="email" />
</div>
<div class="form-group">
<textarea class="form-control" name="message" required placeholder="Please write your feedback here..." rows="5"></textarea>
</div>
<button class="btn btn-primary pull-right" type="submit">Send</button>
</form>
</div>
<div id="feedback-tab">Feedback</div>
</div>
{% endblock %}
and in my admin
from .models import Feedback
from .forms import FeedbackModelForm
class FeedbackAdmin(admin.ModelAdmin):
form = FeedbackModelForm
admin.site.register(Feedback, FeedbackAdmin)
You have passed the
{{ form }}
as the action attribute, which is completely wrong. Put it inside a div as
{{ form.as_p }}
that will work for you.
And in the action attribute pass a url in the form of
{% url 'home_page_example' %}
if you wanted to remain in the same page and redirect via view
you can write
action = "."
Show us how did you register your model in the admin.
Make sure that you explicit config the form, like this
class FeedbackAdmin(admin.ModelAdmin)
form = FeedbackModelForm
admin.site.register(Feedback, FeedbackAdmin)
You should return email or message in def __unicode__(self):, not title.
class Feedback(models.Model):
email = models.CharField(max_length=100)
message = models.CharField(max_length=1000)
def __unicode__(self):
return self.email
I think that you should check if the view is currently saving your Feedback.
Try inspecting the DB or in a manage.py shell check if len(Feedback.objects.all()) change when you submit a Feedback in your view.
Also, I recommend you to change the email field to an EmailField and use the FormView class based view.
Related
please am new to django, and am trying to save user radio button input of an html form to my database by category have created for different post using CBV, i really don't know how to go about please i need help , thanks in advance
here is my models.py
'
class Data(models.Model):
'name= models.CharField(max_length=50, default='')
data=models.CharField(max_length=50 ,blank=True,null=True)
`class Category(models.Model):
name =models.CharField(max_length=200,default='')
class CandidateForm(models.Model):
image= models.ImageField(upload_to='images/', width_field=None,default=0)
data=models.ForeignKey(Data,blank=True,null=True,on_delete=models.PROTECT)
category=models.ForeignKey(Category,blank=True,null=True,on_delete=models.PROTECT)
Nickname=models.CharField(max_length=100,default='')
Name=models.CharField(max_length=100,)
def __str__(self):
return self.Nickname
here is my views.py
def vote_data(request):
if request.method == 'POST':
post=models.Data()
post.data=models.Category.objects.filter(name='category')
post.name=request.POST['candidate']
post.save()
return redirect('Home')
and lastly, the category.html page
<form action="{%url 'data' %}" method="POST" name="">
{% csrf_token %}
{% for candidate in Post.candidate %}
<div class=".col-md-4-flex" data-aos="zoom-out">
<div class="position-relative">
<img src="{{candidate.image.url}}">
<p>{{candidate.Name}}</p>
<label for="candidates_{{candidate.Nickname}}" class="radio-inline">
<input type="radio" name="candidate" value="{{candidate.Nickname}}"
id="candidates_{{candidate.Nickname}}">{{candidate.Nickname|upper}}
</label>
</div>
{% endfor %}
</div>
<input type="submit" value="submit">
sorry for uneccessary information.
I inherited a project where we wanted to use django's native User model but also give users some additional fields. So I made a model called UserProfiles, which has a foreignkey to each User instance. I made a template to update these UserProfiles called settings-userprofile.html. Previously, we only had the field api_key for people to modify, so things were basic.
We want every User to have their own list of "assistant" Users, a label relevant for an API we'll be implementing. So I added the field assistants and updated settings-userprofile.html to include a <select multiple> element that lists out all the existing users on our site. We're using a theme/template that is able to implement the select2 pillbox/tokenization element (like the rightmost screencap in this picture)
user_profile/models.py
class UserProfile(models.Model):
phone_number = models.CharField(max_length=15, verbose_name='Phone Number')
user = models.OneToOneField(User, on_delete = models.CASCADE)
api_key = models.CharField(max_length=200, default='12345678',)
assistants = models.ManyToManyField(User, related_name="assistants")
settings-userprofile.html
<form class='form-horizontal' method="post" action="{% url 'profileUpdate' %}">
{% csrf_token %}
<div class="form-group row mb-4">
<label for="api_key" class="col-sm-3 col-form-label"><b>Profile Api Key:</b></label>
<div class="col-sm-9">
<input type="text" name="api_key" class="form-control" id="horizontal-apikey-input" value="{{ request.user.userprofile.api_key }}">
</div>
</div>
<div class="form-group">
<label class="control-label">User list</label>
<select name="assistants" class="select2 form-control select2-multiple" multiple="multiple" data-placeholder="Choose ...">
<optgroup label="Existing users">
{% for u in allUsers %}
{% if u in request.user.userprofile.assistants %}
<option selected value="{{ u.username }}">{{ u.username }}</option>
{% else %}
<option value="{{ u.username }}">{{ u.username }}</option>
{% endif %}
{% endfor %}
</optgroup>
</select>
</div>
<div class="form-group row justify-content-end">
<div class="col-sm-9">
<div>
<button type="submit" name='apikey_submit' class="btn btn-primary w-md">Submit</button>
</div>
</div>
</div>
</form>
user_profile/views.py
from .forms import UserProfileForm
#login_required
def display_settings_page(request):
form = UserProfileForm(instance=request.user)
allUsers = User.objects.all()
return render(request, 'settings-userprofile.html', { 'form':form, 'allUsers':allUsers })
#login_required
def settings_update_profile(request):
allUsers = User.objects.all()
if request.method == 'POST':
old_api = request.user.userprofile.api_key
form = UserProfileForm(data=request.POST, instance=request.user.userprofile)
if form.is_valid():
form.save()
messages.success(request, "Your API key was changed from " + old_api + " to " + form.cleaned_data["api_key"])
return render(request, 'settings-userprofile.html', {'form': form, 'allUsers':allUsers})
else:
print(form.errors)
return render(request, 'settings-userprofile.html', {'form': form, 'allUsers':allUsers})
# omitting the rest of this code since it only applies to GET requests
In forms.py, we represented assistants using forms.ModelMultipleChoiceField and specified the queryset as the set of all Users.
user_profile/forms.py
class UserProfileForm(forms.ModelForm):
api_key = forms.CharField(required=False)
assistants = forms.ModelMultipleChoiceField(required=False,
queryset=User.objects.all(),
)
class Meta:
model = UserProfile
fields = ['api_key', 'assistants']
This got me as far as to a point where I see a dropdown menu that lists out all the users on my site, and I can select 1 or more users. usernames and emails are the same on this application, so I see a list of emails as intended.
In the view function, I can use print(request.POST.getlist('assistants')) and it prints a list of the tokenized usernames selected in the dropdown menu on submission.
However, is_valid() is always failing and I'm not sure how to go about fixing it. For instance, we have a user registered at the email/username devtest4#gmail.com . Selecting them and Printing form.errors reveals...
<ul class="errorlist">
<li>assistants
<ul class="errorlist"><li>“devtest4#gmail.co
m” is not a valid value.</li></ul>
</li>
</ul>
The username still isn't being treated as a valid value, despite the fact that the queryset is specified to be a list of all users.
I am trying to save multiple fields of data. I've also changed the database connection from the default sqlite3 to MySQL. And I don't know how to do this
Here's my views.py
def customerview(request):
if request.POST:
form = CustomerForm(request.POST)
if form.is_valid():
if form.save():
return redirect('sales')
else:
return redirect('index')
else:
return redirect('index')
else:
form = CustomerForm
return render(request, 'customer.html', {'form':form})
def salesview(request):
if request.POST:
form = SalesForm(request.POST)
if form.is_valid():
if form.save():
return redirect('index')
else:
return redirect('index')
else:
return redirect('index')
else:
form = SalesForm
data = Customer.objects.latest('id')
return render(request, 'sales.html', {'form':form, 'range':range(data.number_of_transactions)})
Here's my models.py
class Customer(models.Model):
customer_name = models.CharField(max_length=200)
number_of_transactions = models.IntegerField()
class Sales(models.Model):
product_type = models.CharField(max_length=100)
product_code = models.CharField(max_length=100)
product_size = models.CharField(max_length=100)
product_quantity = models.IntegerField()
Here's my brands.html
<form class="form" role="form" action="" method="post"> {% csrf_token %}
{% for i in range %}
<div class="col">
<div class="col-sm-3">
<div class="">
{{ form.product_type | add_class:'form-control' }}
<label for="regular2">Product Type</label>
</div>
</div>
<div class="col-sm-3">
<div class="">
{{ form.product_code | add_class:'form-control' }}
<label for="regular2">Product Code</label>
</div>
</div>
</div>
{% endfor %}
<div class="col-md-12">
<hr>
<div class="card-actionbar-row">
<input type="submit" class="btn btn-flat btn-primary ink-reaction" value="SUBMIT">
</div>
</div>
</form>
The idea is to get the customer details and number of transactions to be performed then that determines the number of fields to be displayed in the sales view. And that works fine.
The problem is to get each of the transactions to be saved in the database. When I submit and check my database tables, only one transaction is saved.
It's clear that you're trying to run before you can walk here.
Firstly, you should concentrate on getting a simple list view to work, without getting confused about the additional complexity involved in displaying a list in a form view. So, make your view inherit from ListView, and remove all the methods. Then fix your template, so that it iterates over stock_list or object_list rather than just stock.
Secondly, once you've got that working, you could try to integrate it with a form. When you do that, learn what methods to override. get_queryset must return a queryset, it should not render a template. In any case, you should almost never need to render a template manually in a class-based view, because the existing logic will do that for you. And if you want to add a queryset to the template context in a create view, for example, you should be overriding get_context_data; which needs to return a dictionary.
Thirdly, if at some point you do need to render a template manually, read the documentation to learn the order of parameters to render: it is request, template_name, context, not as you have it.
I've spent a couple of days on this, read the docs, read some Two Scoops info, and I'm missing something. I'm trying to make a view to log in an AbstractUser. The AbstractUser model is in my_app and the view is in an app called mainsite, that I use to store project-wide views.
After the user logs in, they will have access to class-based views that they will use to add, edit, and delete database records. These users are not staff, so I am not giving them access to the admin.
Every time I try to log in as a user, authenticate(username, password) (in views.py) returns none.
What am I missing?
Here's the setup--I have a custom Person model that extends the AbstractUser model:
# my_app.models.py
class Person(AbstractUser):
date_left = models.DateField(blank=True, null=True)
phone_number = models.IntegerField(blank=True, null=True)
def _full_name(self):
return self.get_full_name()
full_name = property(_full_name)
def __str__(self):
return self.get_full_name()
class Meta:
verbose_name_plural = 'People'
I've added Person to settings.py:
# settings.py
...
AUTH_USER_MODEL = "my_app.Person"
...
I have the following URLconf:
# project/urls.py
from mainsite.views import login_view
...
url(r'^login/$', login_view, name='login'),
...
This view logs in the user:
# mainsite.views.py
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return render(request, 'logged_in.html')
else:
return render(request, 'login.html',
{'message': 'Bad username or password'}
)
else:
return render(request, 'login.html')
And finally, here's the template with the login fields:
#templates/login.html
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<div class="row column"><h1>Login</h1></div>
{% if message %}
<div class="row">
<div class="small-12 medium-6 columns">
<div class="alert callout">
<p>{{ message }}</p>
</div>
</div>
</div>
{% endif %}
<div class="row">
<div class="small-12 medium-6 columns">
<label>Username
<input type="text" id="username" name="username">
</label>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 columns">
<label>Password
<input type="password" id="password" name="password">
</label>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 columns">
<input type="submit" value="Log in" class="button">
</div>
</div>
</form>
I found an answer (with help from reddit) in the docs.
When you use AbstractUser, you need to create your own UserCreationForm and UserChangeForm. If you use AbstractBaseUser, then you will need to create additional forms.
I had not created these forms, and I created my users in the admin using forms automatically generated by Django. These forms did not set the password correctly. The automatically generated form probably used user.password = 'some_password'. The correct way to do it is user.set_password('some_password') .
I am working with Django forms and for some reason, this form will not validate! It submits alright, or at least the runserver shows an http post response with code 200 (ok). For some reason though, my form will not pass the is_valid test!
views.py:
def new_show(request):
if request.method == 'POST':
img_form = ImageForm(request.POST, request.FILES)
show_form = NewShowForm(request.POST)
if show_form.is_valid():
new_Show = Show()
new_Show.title=show_form.cleaned_data['title']
new_Show.body=show_form.cleaned_data['body']
new_Show.pub_date=timezone.now()
new_Show.location=show_form.cleaned_data['location']
new_Show.time=show_form.cleaned_data['time']
new_Show.save()
if img_form.is_valid():
image=Image(image=request.FILES['imageFile'])
new_Show.image_set.add(image)
return HttpResponseRedirect(reverse('shows'))
else:
return HttpResponseRedirect(reverse('shows'))
else:
show_form = NewShowForm()
img_form = ImageForm()
return render_to_response(
'shows/new_show.html',
{'show_form': show_form, 'img_form': img_form},
context_instance=RequestContext(request)
)
Here is my template snippet:
<form action="{% url "new_show" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ show_form.non_field_errors }}</p>
<p>
<label for="title">Title:</label>
<input type="text" name="title"/>
</p>
<p>
<label for="body">Body:</label>
<textarea type="text" name="body"> </textarea>
</p>
<p>
<label for="location">Location:</label>
<input type="text" name="location"/>
</p>
<p>
<label for="time">Date:</label>
<input type="text" id="time" maxlength="25" size="25" name="time"><img src="{{ STATIC_URL }}../../static/cal.gif" width="16" height="16" border="0" alt="Pick a date">
</p>
<!-- Upload Form. Note enctype attribute! -->
{% csrf_token %}
<p>{{ img_form.non_field_errors }}</p>
<p>{{ img_form.imageFile.label_tag }}</p>
<p>
{{ img_form.imageFile.errors }}
{{ img_form.imageFile }}
</p>
<p><input type="submit" value="Add Upcoming Show"></input></p>
</form>
Here is my form Class:
class NewShowForm(forms.Form):
title=forms.CharField()
body=forms.CharField(widget=forms.TextArea)
location=forms.CharField()
time=forms.DateTimeField(required=True)
class ImageForm(forms.Form):
imageFile = forms.FileField(required=False, label='Select an Image')
Please help me!
If new_Show is a model, why not create a ModelForm instead of forms.Form?
So, instead of
class NewShowForm(forms.Form):
title=forms.CharField()
body=forms.CharField(widget=forms.TextArea)
location=forms.CharField()
time=forms.DateTimeField(required=True)
class ImageForm(forms.Form):
imageFile = forms.FileField(required=False, label='Select an Image')
why not using,
from django.forms import ModelForm
class NewShowForm(ModelForm):
class Meta:
model = NewShow
class ImageForm(ModelForm):
class Meta:
model = Image
?
Using ModelForm will ensure that form validation meets that of model. Moreover, it can cut off your code (especially line 6 to 11).
It will help to add these two lines to your view before if is_valid() to see the errors it's giving:
if request.method == 'POST':
img_form = ImageForm(request.POST, request.FILES)
show_form = NewShowForm(request.POST)
print(form.is_valid())
print(form.errors)
if show_form.is_valid():
You can paste the errors here and we can see what's the issue
Since you've put 2 Django forms together under one HTML form tag, when you submit the form on the front-end you're sending an extra field through request.POST that your NewShowForm doesn't have. If you combine both forms into a single Django form, you should be able to get this to work.