I am using modelformset_factory with can_order:
BrandFormSet = modelformset_factory(Brand, can_order=True, can_delete=True, extra=0)
And in my views I have:
<form ...>
{{ formset.management_form }}
{% for form in formset %}
{{ form.ORDER }}
{% endfor %}
</form>
It's showing correctly:
<input id="id_form-1-ORDER" name="form-1-ORDER" type="number" value="2" />
...
My Brand model looks like this:
class Brand(models.Model):
name = models.CharField(max_length=50)
order = models.SmallIntegerField()
def __unicode__(self):
return self.name
Now how can I tell Django that order field is where to save the ordering?
Related
i need to make some modifications on my code,as i have a function based view and need to change it to be class based view
FBV:
def Adress_Use_Prev(request):
# print(request.POST)
address_type=request.POST.get('address_type',"shipping")
address_id=request.POST.get("Address-id")
request.session[address_type+"_address_id"]=address_id
next_ = request.GET.get("next")
next_post = request.POST.get("next")
redirected_path = next_ or next_post or None
if is_safe_url(redirected_path, request.get_host()):
return redirect(redirected_path)
return redirect("/")
what is the best solution to convert this fucntion to be CBV
i tried on the following code, but i failed
class UsePrevAddress(NextUrlMixin,FormView):
# def get_success_url(self):
# return self.get_next_url()
def form_valid(self, form):
print("test5")
address_type = self.request.POST.get('address_type', "shipping")
address_id = self.request.POST.get("Address-id")
self.request.session[address_type + "_address_id"] = address_id
return self.get_next_url()
def form_invalid(self, form):
super().form_invalid(form)
the form.html:
{% if address_qs %}
<form method="POST" action="{% url "cart:checkout-Address-reuse" %}"> {% csrf_token %}
{% for Address in address_qs %}
<label for="address-{{ Address.id }}">
<input id="address-{{ Address.id }}" type="radio" name="Address-id" value="{{ Address.id }}"/>
{{ Address.Address_line_1 }},
{% if Address.Address_line_2 %} Address.Address_line_2,
{% endif %}
{{ Address.State }},{{ Address.Postal_Code }},{{ Address.city }}
</label><br/>
{% endfor %}
{% if next_url %}
<input type="hidden" name="next" value="{{ next_url }}">
{% endif %}
{% if address_type %}
<input type="hidden" name="address_type" value="{{ address_type }}">
{% endif %}
<button type="submit" class="btn btn-success">Use Address</button>
</form>
{% endif %}
urls.py:
url('^checkout/Address/reuse$',UsePrevAddress.as_view(),name="checkout-Address-reuse"),
Create a ModelForm for the model class. Add form_class to your CBV.
Ref: ModelForm Django
Example
from django import forms
from django.views.generic.edit import CreateView
class YourModelForm(forms.ModelForm):
model = YourModel
fields = ('field_1', 'field_2', )
# use `CreateView`. `FormView` is for non-model forms
# and I have used a `ModelForm` here.
class YourModelFormView(NextUrlMixin, CreateView):
form_class = YourModelForm
# rest of your code
I am currently struggling to get my form to work properly. I created the form manually (template.html) and I can see all the data when I call it with print(request.POST) (in views.py - checkout) however form.is_valid(): (in views.py - checkout) doesn't work. Means my form is not valid.
I think the issue is, that I created the form manually and combined it with a model form where I want after validating my data with form.valid() save it in. Can anyone of you guys help me with my problem, why it's not valid?
template.html
<form action="{% url 'checkout:reserve_ticket' %}" method="post">
{% csrf_token %}
{% for ticket in event.tickets.all %}
<p>
{{ ticket.name }} for {{ ticket.price_gross }} with quantity:
<input type="hidden" name="order_reference" value="123456af">
<input type="hidden" name="ticket" value="{{ ticket.id }}">
<input type="hidden" name="ticket_name" value="{{ ticket.name }}">
<input type="number" name="quantity" max="{{ ticket.event.organiser.max_quantity_per_ticket }}" placeholder="0">
</p>
{% endfor %}
<button type="submit" class="btn btn-primary">Continue</button>
</form>
models.py
class ReservedItem(models.Model):
order_reference = models.CharField(
max_length=10,
unique=True
)
ticket = models.ForeignKey(
Ticket,
on_delete=models.PROTECT,
related_name='reserved_tickets'
)
ticket_name = models.CharField(max_length=100)
quantity = models.IntegerField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
forms.py
class ReserveForm(forms.ModelForm):
class Meta:
model = ReservedItem
fields = ['order_reference', 'ticket', 'ticket_name', 'quantity']
views.py - events
# Create your views here.
class EventDetailView(DetailView):
context_object_name = 'event'
def get_object(self):
organiser = self.kwargs.get('organiser')
event = self.kwargs.get('event')
queryset = Event.objects.filter(organiser__slug=organiser)
return get_object_or_404(queryset, slug=event)
views.py - checkout
def reserve_ticket(request):
if request.method == 'POST':
form = ReserveForm(request.POST)
if form.is_valid():
print("Hello World")
return redirect("https://test.com")
else:
print("back to homepage")
I've tried looking around for solutions on how to check if a form's name is already existing in the database. I used this link to figure out how, and it is indeed not allowing duplicate names to be entered. But where I expected one, I did not get an error message. I'm not sure what I'm doing wrong here, so if anyone can tell me what I should do, that would be really useful!
addgame.html:
<form method="POST" class="post-form" enctype="multipart/form-data">
{% csrf_token %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
{% endif %}
<div class="form-group">
{{ form.name.label_tag }}
{% render_field form.name class="form-control" %}
<br>
{{ form.genre.label_tag }}
{% render_field form.genre class="form-control" %}
<br>
{{ form.image.label_tag }}
{{ form.image }}
</div>
<hr>
<button type="submit" class="save btn btn-primary">Save</button>
</form>
views.py:
def addgame(request):
if request.method == "POST":
form = InfoForm(request.POST, request.FILES)
if form.is_valid():
infolist = form.save(commit=False)
infolist.created_date = timezone.now()
infolist.save()
return redirect('index')
else:
form = InfoForm()
return render(request, 'ranking/addgame.html', {'form': form})
forms.py:
class InfoForm(forms.ModelForm):
class Meta:
model = GameInfo
fields = ('name', 'image', 'genre')
def clean_name(self):
name = self.cleaned_data['name']
try:
match = GameInfo.objects.get(name=name)
except GameInfo.DoesNotExist:
return name
raise forms.ValidationError('This game has already been added to the list.')
not sure if needed, so I'll post models.py as well:
class GameInfo(models.Model):
GAME_CHOICE = [
("BMU", "Beat 'em up"),
("FT", "Fighting"),
("PF", "Platform"),
("FPS", "Shooter"),
("SV", "Survival"),
("ST", "Stealth"),
("AA", "Action Adventure"),
("EX", "Exploring"),
("SH", "Survival horror"),
("IF", "Interactive fiction"),
("IM", "Interactive movie"),
("VN", "Visual novel"),
("ARP", "Action role-playing"),
("JRP", "Japanese role-playing"),
("TRP", "Tactical role-playing"),
("CAM", "Construction and management"),
("LS", "Life simulation"),
("SP", "Sports"),
("VH", "Vehicle"),
("MOBA", "Multiplayer online battle arena"),
("RTS", "Real-time strategy"),
("RTT", "Real-time tactics"),
("TBS", "Turn-based strategy"),
("TBT", "Turn-based tactics"),
("MMORPG", "MMORPG"),
("MMOFPS", "MMO-FPS"),
("MMOR", "MMO Racing"),
("CG", "Cardgame"),
("PAC", "Point and Click"),
("MG", "Music Game"),
("VR", "Virtual Reality"),
("RC", "Racing"),
]
name = models.CharField(max_length=100)
created_date = models.DateTimeField(default=timezone.now)
image = models.ImageField(upload_to='./media/images/')
genre = models.CharField(
max_length=6,
choices=GAME_CHOICE,
default="BMU",
)
def __str__(self):
return self.name
class Meta:
ordering = ('name',)
If you are rendering the form fields manually, then it's up to you to include the errors, for example:
{{ form.name.errors }}
{{ form.name.label_tag }}
{% render_field form.name class="form-control" %}
I am building a survey tool and I'm wondering how would I continue with this or if my current solution is even the proper way to do it.
Admin of the page may add or remove questions from questionnaires, so if I have understood it, I can't use ModelForms to handle the form data?
A form may consist of 5 multichoice questions and 2 free text questions or any other amount of different types of questions so there isn't any fixed type of questionnaire
How do I then save the values of the form as I do not have a model to use?
Is this even possible to achieve without using a model for the form?
Thank you for any input in advance.
views.py
from django.shortcuts import render
from .models import Questionnaire, Question, Answer
def index(request):
all_questionnaires = Questionnaire.objects.all()
all_questions = Question.objects.all()
return render(request, 'questions/index.html', locals())
def questionnaire_detail(request, questionnaire_id):
questionnaire = Questionnaire.objects.get(id=questionnaire_id)
questions = Question.objects.filter(questionnaire=questionnaire)
return render(request, 'questions/questionnaire.html',
{'questionnaire': questionnaire, 'questions': questions})
def calculate(request):
if request.method == 'POST':
pass
models.py
from django.db import models
MC = 'MC'
CN = 'CN'
TX = 'TX'
CATEGORY = (
(MC, 'Multichoice'),
(CN, 'Choose N'),
(TX, 'Text'),
)
VALYK = '1'
VALKA = '2'
VALKO = '3'
VALNE = '4'
VALVI = '5'
MULTICHOICE = (
(VALYK, 'Least'),
(VALKA, 'Less than average'),
(VALKO, 'Average'),
(VALNE, 'More than average'),
(VALVI, 'Most'),
)
class Questionnaire(models.Model):
questionnaire_name = models.CharField(max_length=100,
verbose_name="Questionnaire",
null=False,
default=None,
blank=False)
def __str__(self):
return self.questionnaire_name
class Question(models.Model):
questionnaire = models.ManyToManyField(Questionnaire)
question_text = models.CharField(max_length=200,
verbose_name="Questionnaire name",
null=True,
default=None,
blank=True)
question_category = models.CharField(max_length=2,
verbose_name="Question category",
null=False,
choices=CATEGORY,
default=None,
blank=False)
def __str__(self):
return self.question_text
class Answer(models.Model):
question = models.ForeignKey(Question)
class MultiChoiceAnswer(Answer):
answer = models.IntegerField(choices=MULTICHOICE)
def __str__(self):
return self.answer
questionnaire.html
{% extends "questions/base.html" %}
{% block title_html %}
Questionnaire
{% endblock %}
{% block h1 %}
Questionnaire
{% endblock %}
{% block content %}
{% if questions|length > 0 %}
<form action="{% url "questions:calculate" %}" method="post">
{% csrf_token %}
{% for question in questions %}
{{ question.question_text }}<br>
{% if question.question_category == "MC" %}
<input type="radio" name="{{ question.id }}" value="1"> 1<br>
<input type="radio" name="{{ question.id }}" value="2"> 2<br>
<input type="radio" name="{{ question.id }}" value="3"> 3<br>
<input type="radio" name="{{ question.id }}" value="4"> 4<br>
<input type="radio" name="{{ question.id }}" value="5"> 5<br>
{% elif question.question_category == "CN" %}
<input type="checkbox" name="{{ question.id }}" value="a">a<br>
<input type="checkbox" name="{{ question.id }}" value="b">b<br>
{% elif question.question_category == "TX" %}
<textarea rows="4" cols="50" name="{{ question.id }}">Test</textarea><br>
{% endif %}
{% endfor %}
<input type="submit" value="Send" />
</form>
{% else %}
<span>No questions</span>
{% endif %}
{% endblock %}
This is the solution I ended up with. Edited it a bit to be more generic.
In the view there is checking if the form was loaded or submitted. If it was submitted, then check the validity of all of the forms. As there are multiple forms they are then made as formsets.
View
def answerpage(request, questionnaire_pk):
AnswerFormSet = formset_factory(AnswerForm, extra=0)
questions = Question.objects.filter(questionnaire=questionnaire_pk)
qname = Questionnaire.objects.get(id=questionnaire_pk)
if request.method == 'POST':
answer_formset = AnswerFormSet(request.POST)
if answer_formset.is_valid():
for answer_form in answer_formset:
if answer_form.is_valid():
instance = answer_form.save(commit=False)
instance.fieldValue = answer_form.cleaned_data.get('fieldValue')
instance.save()
return redirect('main:calcs')
else:
return redirect('main:home')
else:
quest_id = request.session.get('questionnaire_key', defaultValue)
question_data = [{'question': question,
'questionnaire_key': quest_id} for question in questions]
answer_formset = AnswerFormSet(initial=question_data)
combined = zip(questions, answer_formset)
context = {
'combined': combined,
'answer_formset': answer_formset,
'qname': qname,
}
return render(request, 'main/questionnaire.html', context)
The form is a modelform with the default widgets overwritten.
Form
class AnswerForm(forms.ModelForm):
class Meta:
model = QuestionAnswer
exclude = ['']
widgets = {
'field1': RadioSelect(choices=CHOICES, attrs={'required': 'True'}),
'field2': HiddenInput,
}
Webpage renders the values from the view in to a table. Management_form is needed to handle the formset values correctly.
Webpage
{% extends "main/base.html" %}
{% load static %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/survey.css' %}">
<h1>{{ qname.questionnaire_text }}</h1>
<h2>{{ qname.description }}</h2>
<form method="post">{% csrf_token %}
{{ answer_formset.management_form }}
<table>
{% for question, form in combined %}
<tr><td style="width:65%">{{ question }}{{ question.question_type }}</td><td style="width:35%">{{ form.business_id }}{{ form.question }}{{ form.questionnaire_key }}{{ form.answer_text }}</td></tr>
{% endfor %}
</table>
<div class="buttonHolder">
<input type="submit" value="Save" id="next_button"/>
</div>
</form>
{% endblock %}
I'm creating a page where my users can edit their articles but there is one problem, my form is not saving the modifications when I submit my form. Let's have a look:
views.py
def edit(request, id=None, template_name='article_edit.html'):
if id:
article = get_object_or_404(Article, id=id)
if article.user != request.user:
return HttpResponseForbidden()
else:
article = Article(user=request.user)
if request.POST:
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
save_it = form.save()
save_it.save()
form.save_m2m()
return HttpResponseRedirect("/")
else:
form = ArticleForm(instance=article)
context = {'form': form}
populateContext(request, context)
return render(request, template_name, context)
line 3 to 8 : Is to check if it's your own articles there is no problem with that.
line 10 to 18 : There is a problem between these lines, my form is not saving when I submit my form
forms.py (ModelForm)
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
exclude = ['date', 'rating', 'user']
form = ArticleForm()
(Line 4 : I'm excluding the date, the ratings and the username when saved so that the user can not change these informations.)
I don't have any problem in my template.html and the urls.py don't bother with that I checked over 10 times :)
Any help would be great, I'm blocked on this problem since over 1 month...
******* EDIT *******
Models.py
class Article(models.Model):
user = models.ForeignKey(User)
titre = models.CharField(max_length=100, unique=True)
summary = RichTextField(null=True, max_length=140)
contenu = RichTextField(null=True)
date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name="Date de parution")
image = models.ImageField(upload_to='article', default='article/amazarashi.jpeg')
rating = RatingField(can_change_vote=True)
tags = TaggableManager(through=TaggedItem, blank=True)
def __str__(self):
return self.titre
Template.html
{% block body %}
{% if user.is_authenticated %}
<p>Authentificated as <strong>{{ user.username }}</strong></p>
{% else %}
<p>NOT Authentificated</p>
{% endif %}
<h1>Edit this {{ article.titre }}</h1>
<br>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8">
<form enctype='multipart/form-data' action="{% url "article.views.index" %}" method="post" class="form" autocomplete="off" autocorrect="off">
{% csrf_token %}
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
<div class="form-group">SUMMARY
{{ form.media }}
{{ form.summary.errors }}
{{ form.summary }}
</div>
<div class="form-group">CONTENU
{{ form.media }}
{{ form.contenu.errors }}
{{ form.contenu }}
</div>
<div class="form-group">
{{ form.image.errors }}
{{ form.image }}
</div>
<div class="form-group">TAGS
{{ form.tags.errors }}
{{ form.tags }}
</div>
<input type="submit" class="btn btn-default" value="Submit"/>
</div>
</form>
{% endblock %}
According to your error message.. Modify your form in templates:
<form enctype='multipart/form-data' ...>
Add request.FILES to your Form creation:
if request.POST:
form = ArticleForm(request.POST, request.FILES, instance=article)
UPDATE:
You have strange url tag parameter. Are you sure you have defined your url like: ('...', your_view, name='article.views.index')? I am in doubt cause url tag takes url name as parameter but not view path and nobody usually uses url names like this.