i using django with sqllite i create a survey form with the help of django model and django forms but when i hit submit i see sometime data save twice in my database is it happen normally or something wrong with my code
from django.shortcuts import render, redirect
from django.contrib import messages
from django.template.response import TemplateResponse
from .forms import SurveyForm
def index(request):
if request.method == 'POST':
form = SurveyForm(request.POST)
if form.is_valid():
form.save()
return TemplateResponse(request, 'thankyou.html')
else:
return messages.error(request, 'Please fill the form to continue')
else:
form = SurveyForm()
return render(request, 'learnersform.html', {'form': form})
my forms.py
from django import forms
from django.forms import ModelForm, Textarea
from .models import teacher
class teachersform(forms.ModelForm):
class Meta:
model = teacher
fields = '__all__'
widgets = {'name': forms.TextInput(attrs={'placeholder':'Your Name'}),
'Q3': forms.TextInput(attrs={'placeholder':'Please write your subjects'}),
'Q4': forms.RadioSelect(),
'Q5': forms.RadioSelect(),
'Q6': forms.RadioSelect(),
'Q7': forms.RadioSelect(),
'Q8': forms.RadioSelect(),
'Q9':forms.Textarea(attrs={'placeholder':'Write Here.......'}),
'Q10':forms.Textarea(attrs={'placeholder':'Write Here.......'}),
}
my models.py
from django.db import models
# Create your models here.
class teacher(models.Model):
name = models.CharField(max_length=80, blank=True,)
state = models.CharField(max_length=50, choices=state_choice,)
Q3 = models.CharField(max_length=80, default=None, blank=False)
Q4 = models.CharField(max_length=80, choices=q4_choice, default=None, blank=False)
Q5 = models.CharField(max_length=80, choices=q5_choice, default=None, blank=False)
Q6 = models.CharField(max_length=80, choices=q6_choice, default=None, blank=False)
Q7 = models.CharField(max_length=80, choices=q7_choice, default=None, blank=False)
Q8 = models.CharField(max_length=80, choices=q8_choice, default=None, blank=False)
Q9 = models.TextField(default=None, blank=False)
Q10 = models.TextField(default=None,blank=False)
def __str__(self):
return self.state
Your issues is not related with sqlite but rather with the code in views.py. When you refresh your page after the form has been saved, the same form data getting resubmitted; and same data is getting saved multiple times.
It is recommended that after the form data is successfully saved, a return HttpResponseRedirect or redirect should be used rather than rendering using the HttpRequest.
I would rewrite the code as
def index(request):
if request.method == 'POST':
form = SurveyForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('thankyou/')
#return TemplateResponse(request, 'thankyou.html')
else:
return messages.error(request, 'Please fill the form to continue')
else:
form = SurveyForm()
return render(request, 'learnersform.html', {'form': form})
Add a route to the urls.py like
path( 'thankyou/', views.thankyou, name='thankyou')
Include another function thankyou in views.py
def thankyou(request):
return render(request, 'thankyou.html')
Update:
In case you don't want to use the urls.py route and the extra view function, then you can pass the path thankyou.html to the HttpResponseRedirect constructor. In this case, no need to create route in urls.py or the extra view function.
return HttpResponseRedirect('thankyou.html')
I would personally suggest you extract the data from the form before saving, you can then manipulate the data, or save in other locations as well:
Firstly you will know how the data will be sent through by the names given in the form, so you can build out a dictionary of values...
You will need to build out the 'form_data' section to get a complete dict that is relevant to your form.
form_data = {
"name": request.POST['name'],
"Q3": request.POST['Q3']
my_form = SurveyForm(form_data)
if my_form.is_valid():
new_form = my_form.save(commit=False)
"""
Now you can access any data using the dict method - new_form.name, new_form.Q3
etc. Even if you don't initially use it, you can leave this section blank but use
it in the future at some stage...
new_form.name for example will be the users name entered on the form.
new_form.Q3 will be the answer to question 3.
Although this may be a longer way of doing things, it will allow you to gather the
form data, before saving it. You can also build in additional security features
prior to database submission.
"""
if new_form.Q3 == "Some Specific Answer":
# Add all users to list who answer Q3 in a certain way
some_list.extend(new_form.name)
# Now your done manipulating data, or pushing it to be saved in other places, you can save the form to your database.
new_form.save()
else:
# Form was not valid
messages.error(request, 'Please fill the form to continue')
Not sure what the scope of your project is but the above way will allow you to easily grow its code into the future as you can manipulate that data, for example you could push users names into different collections based on question results etc.
Related
So let's say I have a model called "Post" that looks like this:
class Post(models.Model):
title = models.CharField(max_length=50)
body = models.TextField()
def __str__(self):
return self.title
now, say I have an option for users to create a Post on my site. How could I alter the standard User model and give it a characteristic containing all of the posts that that user has created. For example, say we have a user who has created a post. In the interactive shell that Django has, I could enter "user.posts" and It would pull up all the posts that that user has created. How could I go about this?
You can do this by adding users as a foreign key to your Posts model. Try this after the "body" line and migrating.
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
To query relevant posts in a view you could then filter your Posts model by user like this:
user_posts = Posts.objects.filter(user=request.user)
You add a ForeignKey from Post to the user model:
from django.conf import settings
class Post(models.Model):
title = models.CharField(max_length=50)
body = models.TextField()
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='posts',
editable=False
)
In a view, you can link the logged in user with a post with:
from django.contrib.auth.decorators import login_required
#login_required
def create_post(request):
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('name-of-some-view')
else:
from = PostForm()
return render(request, 'some_template.html', {'form': form})
The related_name parameter specifies the name of the relation in reverse. So the manager to access the Post objects related to a User object. So if you have a user object myuser, you can access the posts with:
myuser.posts.all()
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
I'm trying to make some forms that will allow users to add some objects, delete them or edit but I've stucked with thing like author of model. Let's say we got model Shot which got field
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Because I've created custom user model to expand user by some fields that I want, and then we creating modelForm, creating views etc. and finally got form. When we will try to submit this form, it won't add this object submited in form to db because form has no filled field author author which means this field == Null and that's why it won't add this to db. So my question is how to get it dynamic, for example when user with nick "thebestuser" will try to add this modelForm it will work and mark author as "thebestuser"? Ofc I could add to form field author, but it's the worst way in my opinion and every user would be allowed then to add object for example as a another user, let's say user with nick "anothernick" could add form as a user with "thebestuser" which is In my opinion not acceptable.
models.py
from django.db import models
from django.contrib.auth.models import User
from streamers.models import Streamer
from django.conf import settings
from django.utils import timezone
class Shot(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=70)
url = models.CharField(max_length=100)
streamer = models.ForeignKey(Streamer, on_delete=models.CASCADE)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
forms.py
from django import forms
from .models import Shot
class AddShot(forms.ModelForm):
class Meta:
model = Shot
fields = [
'title',
'url',
'streamer',
]
views.py
#login_required
def add_shot(request):
form = AddShot(request.POST or None)
if form.is_valid():
form.save()
instance = form.save(commit=False)
instance.published_date = request.published_date
instance.author = request.user
instance.save()
context = {
'form': form
}
return render(request, 'shots/add_shot.html', context)
You'll need to do it in your view. When you save your form pass commit=False to your save method, add your user, then save the returned instance.
def my_view(request):
form = AddShot(request.POST)
instance = form.save(commit=False)
instance.author = request.user
instance.save()
Documented here: https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#the-save-method
I have a ModelChoiceField called outage_name. I also have a simple form that allows you to select the item from the list. The ModelChoiceField is pulled from a MySQL DB. This queryset is located in forms.py
outage_name = forms.ModelChoiceField(queryset = Outage.objects.filter(published = True)
The models.py is listed below.
from django.db import models
from django.contrib.auth.models import User
class Outage(models.Model):
outage_name = models.CharField(max_length=60, unique=True)
published = models.BooleanField()
def __unicode__(self):
return self.outage_name
class Detail(models.Model):
detail = models.CharField(max_length=60, unique=True)
user = models.ForeignKey(User)
outage = models.ForeignKey(Outage)
def __unicode__(self):
return self.outage
When I select from the list and submit the form I can't seem to figure out how to match outage = models.ForeignKey(Outage) that was selected on the list. To the correct outage_name. In my views.py I can hard code the id and it submits to the database and everything works fine.
def turnover_form(request):
if request.user.is_authenticated():
if request.method == 'POST':
form = TurnoverForm(request.POST)
if form.is_valid():
details = Detail.objects.get_or_create(
detail = form.cleaned_data['detail'],
user = request.user,
outage = Outage.objects.get(pk=1))
return HttpResponseRedirect('/turnover/user/')
else:
form = TurnoverForm()
variables = RequestContext(request, {'form': form})
return render_to_response('turnover_form.html', variables)
else:
return HttpResponseRedirect('/authorization/')
Any advice on how to match the id with the selected item would be appreciated. I'm sure my code is not very pythonic as I'm still learning.
outage = form.cleaned_data['outage'] # cleaned_data['outage'] is a model instance
I'm trying to build an import feature/form in the django admin interface for a specific model.
I have already found the following question on Stackoverflow, however as I am new to django, I have not been able to wire it all up. Import csv data into database in Django Admin
I guess I understand how to work with Django objects and how to use the CSV reader module, but I have a heck of a time putting it all together in Django.
what i tried so far is this:
models.py
class RfidTag(models.Model):
"""
Available RFID-Tags from Importfile
"""
system = models.DecimalField(
_('system'),
max_digits=4,
decimal_places=0,
)
tagId = models.DecimalField(
_('tag ID'),
max_digits=4,
decimal_places=0,
)
serial = models.CharField(
_('serial'),
max_length=10,
)
# forms.py #
class RfidImport(forms.ModelForm):
file_to_import = forms.FileField()
class Meta:
model = RfidTag
fields = ("file_to_import",)
def save(self, commit=False, *args, **kwargs):
form_input = RfidImport()
file_csv = self.cleaned_data['file_to_import']
csv.register_dialect('excel-new', delimiter=';', quoting=csv.QUOTE_NONE)
records = csv.reader(file_csv, dialect='excel-new')
for line in records:
self.system = line[0]
self.tagId = line[1]
self.serial = line[2]
form_input.save()
datafile.close()
admin.py
class RfidTagAdmin(admin.ModelAdmin):
list_display = ('system','tagId','serial')
actions = ['import_tags']
def get_urls(self):
urls = super(RfidTagAdmin, self).get_urls()
my_urls = patterns('',
(r'^import/$', self.admin_site.admin_view(import_tags))
)
return my_urls + urls
def import_tags(self, request, queryset):
return HttpResponseRedirect("./import")
import_tags.short_description = "Import new RFID tags"
pass
admin.site.register(RfidTag, RfidTagAdmin)
views.py
#staff_member_required
def import_tags(request):
if request.method == "POST":
form = RfidImport(request.POST, request.FILES)
if form.is_valid():
form.save()
success = True
context = {"form": form, "success": success}
return HttpResponseRedirect("../")
else:
form = RfidImport()
context = {"form": form}
return HttpResponseRedirect("../")
My question is, is admin action actually the right way? Is there a better way to achieve what I am trying? And how do I wire this up? I have yet to see the form, after I select the import action and click "go".
The admin is the right way, however i wouldn't be using an action for this, those are designed to function over a list of objects and you don't need that. For this case simply extend the admin/index.html template and add an href to your view. After that you create a normal form in which you do your processing