I was following the post, when I try to solve my solution but it doesn't work for me.
My problem:
I have Django Model object with 4 attributes.
Let's say I have something like this
class MyModel(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
first_at = models.IntegerField()
second_at = models.IntegerField()
third = models.TextField()
Then I have some view in which I would like to present the form with this object. But, I would like the user to only insert 2 of them, user and the third parameter need to be filled automatically; user from current user and third from another HTML element (in which row the form was filled).
class HomePage(LoginRequiredMixin, generic.CreateView):
template_name = 'index.html'
model = MyModel
fields = ('first', 'second')
success_url = reverse_lazy('home')
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
Then I have in HTML created
<form action="." method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="third" value="{{ item.third }}" />
<input type="submit" value="submit" />
</form>
Does anyone know why this is not working? And or how should I make it work? Is there is a better way?
Marko
You can try this approach
Create a custom form under a forms.py and exclude the fields let's say
class UserForm(forms.ModelForm):
class Meta:
model=Mymodel
exclude = ['user','third']
and in your create view import the form recenlty created and the use it into the CreateView with form_clas
class HomePage(LoginRequiredMixin, generic.CreateView):
form_class = UserForm
template_name = 'index.html'
model = MyModel
fields = ('first', 'second')
success_url = reverse_lazy('home')
I found the solution,
The problem is, that when you use the generic.CreateView and set either fields, or form_class, then this class will only read those fields. Even if you add manually additional input field it will not be passed inside class.
To solve this problem I created form class with hidden field.
class MyForm(forms.ModelForm):
class Meta:
model = models.OrderDetail
fields = ('first', 'second', 'third')
widgets = {
'third' : forms.HiddenInput(),
}
Then I use this form as normal inside view class
class HomePage(LoginRequiredMixin, generic.CreateView):
template_name = 'index.html'
model = MyModel
form_class = forms.MyForm
success_url = reverse_lazy('home')
Then add additional hidden field inside HTML file
<form action="." method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="third" value="someValue" />
<button type="submit" name="_submit" class="btn btn-raised btn-primary">Submit</button>
</form>
This way, you replace your hidden field that come with form.as_p with custom one.
Note: You don't really replace field. If you inspect the code, you will see, that you will have 2 hidden fields, but only one with value. But because both are hidden, no one could add value to another, so the behaviour is the same as the field would be replaced.
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
At the moment I have some Posts to show to the users. The GenericView handling this page is a DetailView and I've already passed FormMixin into it to handle Comment functionality.
Now I want to add a Flag or Report form to bottom of each Post. I've found some ways to pass two different forms to a single generic view, but I found them messy and django suggest not to do such complex things. My question is how would I do this task?
Actually I was trying to render the form manually but I couldn't figure out how to pass reason id to the action of the form.
Report's Model:
class Report(models.Model):
reporter = models.ForeignKey(User, related_name='reporters')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = GenericForeignKey('content_type', 'object_id')
reason = models.IntegerField(choices=REASON_CHOICES, default=BROKEN_LINK)
Report's Form:
BROKEN_LINK, RUDE, BAD_TRANSLATE, IRR = range(4)
REASON_CHOICES = (
(BROKEN_LINK, 'Broken_link'),
(RUDE, 'Rude'),
(BAD_TRANSLATE, 'Bad_translate'),
(IRR, 'Irr')
)
class ReportForm(forms.ModelForm):
class Meta:
model = Report
fields = ['reason']
widgets = {
'reason': forms.RadioSelect,
}
Report views.py:
( report_object and ReportCreateView are doing the same job, the first one was for the time that I decide to don't use generic views to create handle the form )
def report_object(request, model, object_id, reason):
if request.post == POST:
...
class ReportCreateView(CreateView):
model = Report
form_class = ReportForm
template_name = "forms/report_form.html"
def form_valid(self, form):
...
In textdeatilview I define reasons as:
context['reasons'] = REASON_CHOICES
Here's what I was thinking to do inside template:
<form class="report" method="POST" id="{{ post.id }}" action="{% url 'report_create' model="post" object_id=post.id reason=??? %}">
{% csrf_token %}
{% for id, value in reasons %}
<p><input type="radio" name="reason" id="" value="{{ id }}" />{{ value }}</p>
{% endfor %}
<input type="submit" value="Add">
</form>
Is this the right approach? If so, how should I fix it?
No. The reason ID is part of the submitted form data, it's not part of the URL and it doesn't need to be a parameter to the view.
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.