I have a model:
class PartnerPrefs(models.Model):
partner = models.ForeignKey(Partner)
theme = models.IntegerField()
email = models.EmailField()
logo_file = models.ImageField(upload_to='logos/')
And my forms:
class PartnerPrefsForm(ModelForm):
theme = forms.ChoiceField(
choices=THEME_CHOICE,
widget=forms.Select(),
initial='1',
)
class Meta:
model = PartnerPrefs
exclude = ('partner',)
And my views:
...
if request.method == 'POST':
prefsform = PartnerPrefsForm(request.FILES, request.POST)
if prefsform.is_valid():
# do stuff
And finally my template:
<form enctype='multipart/form-data' form action='.' method='post'>
{% csrf_token %}
{{ prefsform.as_p }}
<input type="submit" value="Submit" />
</form>
Whenever I submit the form all field come back with This field is required.... If I eliminate the ImageField from the form, then it works fine. I cannot find what the problem is.
The issue turned out to be the order in which request.POST and request.FILES are passed to the from. request.POST must go first.
Related
I`m using Django 1.9 with the following:
views.py:
def a_new(request):
# submit button
if request.method == "POST":
form = AForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('ui:config-list')
# first visit
else:
form = AForm()
template = 'api/test_template.html'
context = RequestContext(request, {'form': form})
return render_to_response(template, context)
forms.py:
class AForm(forms.ModelForm):
b= forms.ModelMultipleChoiceField(
queryset=B.objects.all(),
widget=FilteredSelectMultiple("b", is_stacked=False)
)
class Meta:
model = A
fields = ('name', 'b', )
test_template.html
...
<form role="form" class="form-inline" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.name }}
{{ form.b }}
</div>
<div class="dl-horizontal">
<button type="submit" class="btn btn-success">Save</button>
</div>
</form>
models.py:
class A(models.Model):
name = models.CharField(max_length=100)
b = models.ManyToManyField(B, null=True, blank=True, name='b')
...
The problem is that when I use the Save button - only the name field is created in the item. The b item, that the widget is being used on, is just not being saved to the DB with the new item A created(it does show error if I leave the b field empty so I guess its checking it too).
What can be the problem?
See the documentation about using commit=False when you have a many-to-many field.
Note that there is no reason for you to be using commit=False here though. Remove it, and the second save, and Django will save your values directly.
b is ManyToManyField, it does on saved on the table A. In a different table the relation between A and B is maintained.
If you have an M2M field and do save(commit=False) you need to call this at the end:
form.save_m2m()
See the docs.
I'm working with a CreateView where I know what some of the field values will be ahead of time. In the example below, I know that the author field for a new Entry object will be the current user and I use get_initial() to preset this.
Now I would like to omit this field from my template form. I've tried several approaches:
Simply commenting out the author field in the form template leads to an invalid form.
Leaving 'author' out of fields. Nope.
And here's a related problem. The example below involves a relationship to a User object that exists. But what if I need to create an object, say an auth Group for editors? I've tried creating a placeholder group and renaming it ... and, well, that didn't work very well.
#
# model
#
class Author(Model):
name = CharField(max_length = 60)
user = OneToOneField(to = User, related_name = 'author_user', on_delete = CASCADE)
class Entry(Model):
title = CharField(max_length = 60)
author = ForeignKey(to = Author, related_name = 'entry_author')
#
# view
#
class EntryCreateView(CreateView):
model = Entry
fields = ('title', 'author')
def get_initial(self):
initial = super(EntryCreateView, self).get_initial()
initial['author'] = get_object_or_404(Author, user = self.request.user)
return initial
#
# template
#
{% extends "base.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<label for="{{ form.title.id_for_label }}">Title:</label>
{{ form.title }}
<label for="{{ form.author.id_for_label }}">Author:</label>
{{ form.author }}
<p>
<input type="submit" class="btn btn-primary" name="save" value="Save" />
<input type="submit" class="btn btn-primary" name="cancel" value="Cancel" />
</form>
{% endblock %}
You can manually set user in form_valid() method of EntryCreateView class:
class EntryCreateView(CreateView):
model = Entry
fields = ('title',)
def form_valid(self, form):
user = self.request.user
form.instance.user = user
return super(EntryCreateView, self).form_valid(form)
You'll need to create a ModelForm for the customizations you need (https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/).
You can't remove author because it's required on your model currently.
Try something like this:
In forms.py...
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['title', 'author']
def __init__(self, *args, **kwargs):
initial = kwargs.get('initial', {})
self.author = initial.get('author')
super(EntryForm, self).__init__(*args, **kwargs)
You can make modifications to the fields (set to not required, delete a field from the form fields, etc) in __init__ or on the class.
Just import and reference this form in your views to use it.
I am working on a Django project with crispy forms.
I want to use images instead of the the default Models title/label to select a instance in a Many to Many relation form.
Content models.py:
class Cloth(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200)
picture = ImageCropField(upload_to='cloth_pics/%Y-%m-%d/',
blank=True)
def __str__(self):
return self.title
class Outfit(models.Model):
owner = models.ForeignKey('profiles.Profile')
title = models.CharField(max_length=200)
cloths=models.ManyToManyField(Cloth)
Content forms.py
class ClothForm(forms.ModelForm):
class Meta:
model = Cloth
fields = ('title','type','picture')
class OutfitForm(forms.ModelForm):
class Meta:
model = Outfit
exclude= ["owner"]
Content views.py
def outfits_new(request):
if request.method == "POST":
form = OutfitForm(request.POST)
if form.is_valid():
outfit = form.save(commit=False)
outfit.owner = get_user(request)
outfit.created_date = timezone.now()
outfit.save()
pk=outfit.id
return HttpResponseRedirect(reverse('outfit_edit_delete', args=[pk]))
else:
cloths = Cloth.objects.filter(owner=request.user.id)
form = OutfitForm()
return render(request, '../templates/outfits_new.html', {'form': form, "cloths":cloths})
Content outfits_new.html
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="btn-group" role="group" aria-label="Basic example">
<input type="submit" value="Submit" name="edit" class="btn btn-success">
</div>
This code produces a Outfit form where I can select different cloths( displaying the cloths title). I want to select different cloths using a image from the cloths.picture field.
Thank you very much,
Patrick
Have a look at select2 at https://select2.github.io/examples.html. It allows you to do images in comboboxes
There is a Django package at https://github.com/applegrew/django-select2
I am trying to submit a form and it will not pass as is_valid in the view.
The form uses forms.Modelforms which I do not have a lot of experience with.
I checked {{ form.errors }} in the template but didn't get anything back.
I appreciate the time and expertise
Form
class AddSubcategory(forms.ModelForm):
class Meta:
model = Subcategory
fields = ['category']
subcategory_name = forms.CharField(max_length=255)
View
#login_required
#locationed
def add_subcategory(request, location):
subcat_form = AddSubcategory(request.POST)
if subcat_form.is_valid():
submitted_subcat_name = subcat_form.cleaned_data['subcategory_name']
selected_cat = subcat_form.cleaned_data['category']
_, was_created = Subcategory.objects.get_or_create(name=submitted_subcat_name, category=selected_cat)
return HttpResponseRedirect(reverse('manage_cat_subcat', args=(location.slug,)))
else:
cat_form = AddCategory()
subcat_form = AddSubcategory()
return render(request, 'inventory/manage_cat_subcat.html', {'location': location,'cat_form': cat_form,'subcat_form':subcat_form})
Template (form)
<form class="form-inline" action="{% url 'add_subcategory' location.slug %}" method="post">
{% csrf_token %}
{{subcat_form.category}}
{{subcat_form.subcategory_name}}
<button class="btn btn-small" type="submit">Add Subcategory</button>
</form>
You specify in fields that you need id, category and name but you don't put them in your form in your template.
You have only category and subcategory_name.
You can add those two elements in your template OR remove them from the fields list.
Also you don't specify an action for your form, you should give the view where the data from your form should be sent.
I have a model:
class Tour(models.Model):
owner_id = models.ForeignKey(User)
name = models.CharField(max_length=50)
location = models.ManyToManyField(Location)
subscribers = models.ManyToManyField(User, related_name="sub")
tour_date = models.DateField(null=True)
description = models.CharField(max_length=300, null=True)
And a template that includes this form:
<form method="post" action="/mytours/">
{% csrf_token %}
<input name="name" value="{{ name }}" class="pull-left" type="text" placeholder="Type the tour name... "></br>
<input name="tour_date" value="{{ tour_date }}" type="text" id="datepicker" placeholder="Pick a tour date..."/>
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</form>
And in my views I am trying to add to my database what is filled in the form:
if request.method == 'POST':
location = Location.objects.get(id=1)
name = request.POST.get('name', '')
tour_date = request.POST.get('tour_date', '')
tour = Tour()
tour.owner_id = user.pk
tour.name = name
tour.tour_date = tour_date
tour.location = location
tour.save()
c = {'name':name, 'tour_date':tour_date, 'tour':tour}
c.update(csrf(request))
return render_to_response("myTours.html", c)
I am new in django and I don't know where is the problem.
You're misunderstanding what to do with the CSRF token. You're creating it on POST, but the point is to create it for the original display of the form on the GET request. It is checked by the middleware on POST, so you don't need to add it there.
You should use the render call as recommended by surfeurX, but on the call that displays the form in the first place.
What I do when I implement forms in django is writing a form class and creating an instance of it in the view. Then pass the instance to the template.
# form class eg. in models.py
from django import forms
class TourForm(forms.Form):
name = forms.CharField(max_length=50)
# in the view
if request.method == 'POST':
form = TourForm(request.POST)
if form.is_valid():
# do your stuff here with form data
else:
form = TourForm() # An unbound form
return render(request, 'myTours.html', {
'form': form,
})
in your template you can display the generated form like this:
<form action="/mytours/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" class="btn btn-primary" />
</form>
for further information just look inside the official django forms documentation
You probably need to add django.middleware.csrf.CsrfViewMiddleware to MIDDLEWARE_CLASSES and add a RequestContext to your response:
return render_to_response("myTours.html", c, context_instance=RequestContext(request))
https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/
How do you render your template ??? I think your csrf_token doesn't print any hidden input, add "request" in your template context like:
return render(request, "template.html", {"var": var})
https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render