Django ModelForm with extra fields - python

So I have this ModelForm in my django project:
class DateForm(ModelForm):
image = forms.ImageField()
class Meta:
model = Date
exclude = ('user',)
the Photo model:
class Photo(models.Model):
date = models.ForeignKey(Date, on_delete=models.CASCADE)
image = models.ImageField(verbose_name='Photos', upload_to='media/date/photos/')
the form:
<p class="p-form">Title</p>
{{ form.title }}
<p class="p-form">Description</p>
{{ form.description }}
<p class="p-form">Place</p>
{{ form.place }}
<p class="p-form">Rating</p>
{{ form.rating }}
<p class="p-form">Photos</p>
{{ form.image }}
Whenever I try to save my form, its form_invalid method is being called and it doesn't save the form. What is the matter? How do I save extra field of ForeignKey model? How can I get that images sent via form? Thanks!

Related

Django: How to do required field validation on ModelChoiceField or Radio Button

I want to run required field validate using the clean function in my form class. I also wanted to validate this with self.add_error to access the field in template.
my form.py
class Step2(forms.Form):
special_purpose = forms.ModelChoiceField(
empty_label=None,
queryset=SpecialPurpose.objects.all(),
to_field_name="id",
widget=forms.RadioSelect(attrs={'style': 'list-style:none'}),
required=False
)
def clean(self):
cleaned_data = super().clean()
special_purpose = cleaned_data.get("special_purpose")
if special_purpose is '':
self.add_error('special_purpose', 'This field is required')
then in my template
<label id="{{ form.special_purpose.id_for_label }}-error" class="error" for="{{ form.special_purpose.name }}">{{ form.special_purpose.errors|striptags }}</label>
{{ form.special_purpose.0 }}<br>
{{ form.special_purpose.1 }}<br>
{{ form.special_purpose.2 }}<br>
{{ form.special_purpose.3 }}<br>
Is there a specific way for doing this for Radio buttons/ModelChoice field
Thank to my buddy Waleed!
the mistake was in the if condition
if special_purpose is '':
this should be
if special_purpose is None:
as in the form declaration i used emplty_label as None

How to dynamically update form data in django

I am new to django and I am trying to create a review system, whereby each team member reviews all the other members within their team.
Here is my models.py file:
from django.db import models
from django.contrib.auth.models import User
class Team(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class Trait(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class Review(models.Model):
reviewer = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='reviewer_id')
reviewee = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='reviewee_id')
trait = models.ForeignKey(Trait, on_delete=models.CASCADE)
trait_score = models.IntegerField()` return
This is my views.py file:
from django.shortcuts import render, redirect
from review.forms import ReviewForm
from django.http import HttpResponse
from django.contrib.auth.models import User
from accounts.models import UserProfile
def positivity_review(request):
if request.method == 'POST':
form = ReviewForm(request.POST)
if form.is_valid():
form.save()
return redirect('/review/relationships')
else:
form = ReviewForm()
users = UserProfile.objects.filter(review_team=1)
args = {'form': form, 'team_members': users}
return render(request, 'review/positivity.html', args)` return
This is my forms.py file:
from django import forms
from django.forms.widgets import NumberInput
from review.models import Team, Review
class RangeInput(NumberInput):
input_type = 'range'
class ReviewForm(forms.ModelForm):
trait_score = forms.IntegerField(widget=RangeInput, min_value=0,
max_value=100, label='')
class Meta:
model = Review
fields = (
'trait_score',
)` return
This is the HTML file:
{% extends 'base.html' %}
{% block head %}
<title>Review</title>
{% endblock %}
{% block content %}
<br>
<h1>Review</h1>
<h2>Do they foster a postive climate?</h2>
<div class="row">
<div class="col-md-2">
<p>Exhibits a lack of awareness for a positive climate. Resistance to prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates at times, within structured activities and friendly under prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates within the team environment without prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates well with others, enthusiastic and positve. Occationally prompts others to engage positively.</p>
</div>
<div class="col-md-4">
<p>Seeks to continuously and consistently create a positive environment. Acts as a role model for the team through prompting being supportive and encouraging and showing genuine concern for others.</p>
</div>
</div>
<div>
<form method="post">
{% for user in team_members %}
<p>Reviewing: {{ user.first_name }} {{ user.last_name }}</p>
{% csrf_token %}
{{ form.as_p }}
{% endfor %}
<button class="btn btn-primary" type="submit">Next</button>
</form>
</div>
{% endblock %}`
Currently I am passing in the queryset through the views.py into the html file and looping through it to load the relevant number of team members.
Since I am loading a form each time for each individual in the team, how can I make the form submit so that it knows who is being reviewed? For example, submitting the reviewer, trait and score is simple as most of that can be passed directly into the view, however, submitting the reviewee (person being reviewed) is the part im not sure how to handle, as they are loaded within the form using the template tagging. I was wondering if it is possible to submit some kind of data back into the form such as first + last name or thier user id, anything so that when I go to publish the results I have a way of filtering individuals results.
Hopefully the description is sufficient. Thanks in advance!
If I understand your question correctly, this might be the answer.
First, create a simple form (rather than ModelForm) and add this, among other things:
pk = forms.CharField(
widget=forms.TextInput(
attrs={
'type': 'hidden',
}
),
label=''
)
This will hold the pk of the reviewee and won't be visible to reviewer.
Then, in the html file, I think you have to generate a separate form for each user rather than only the input (I'm not sure, try it). You can do this:
{% for user in team_members %}
<form method="post" id="review_form_{{user.pk}}">
<p>Reviewing: {{ user.first_name }} {{ user.last_name }}</p>
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" type="submit">Next</button>
</form>
<script type="text/javascript">
$('#review_form_{{user.pk}}').children('#id_pk').val("{{user.pk}}");
</script>
{% endfor %}
Remember that when django generates a form, each input will have to get an id and django adds id_ to the beginning of the name of the field you create in fields.py
And lastly, when the reviewer submit a form, you can find your reveiwee in views.py this way:
form = ReviewForm(request.POST)
if form.is_valid():
reviewee_id = request.POST.get('pk')
reviewee = User.objects.get(pk=reviewee_id)

Django pass variables to form_class

I am trying to figure out how to access fields from a Model that is used as a ForeignKey within the Model that the forms are querying.
Each Room has a form where the user selects a Layout from a dynamic list of possible Layout objects.
1—The HTML forms/room/update/layouts.html
<form class="layouts__form form-horizontal" action="" method="post" enctype="multipart/form-data">
<fieldset class="form__options">
{% csrf_token %}
{% for field in form.layout %}
<div class="layouts__layout">
{{ field.tag }}
{{ field.choice_label }}
<label for="value_{{ forloop.counter0 }}">
<div class="layouts__layout__thumbnail layouts__layout__thumbnail--{{ field.choice_label }}" style="background-image: url('### (I WOULD LIKE TO LOAD 'Layout.thumbnail' HERE) ###');"></div>
</label>
</div>
{% endfor %}
<div class="form__submit">
<button type="submit">Submit</button>
</div>
</fieldset>
</form>
2—The form is being called by this in views.py:
class RoomLayoutView(UpdateView):
model = Room
form_class = RoomLayoutForm
template_name = 'forms/room/update/layouts.html'
3—Which is being created by this in forms.py:
class RoomLayoutForm(forms.ModelForm):
layout = forms.ModelChoiceField(
widget=forms.RadioSelect(attrs={'type': 'radio', 'id': 'value',}),
queryset=Layout.objects.all(),
required=False, empty_label=None)
class Meta:
model = Room
fields = ['layout']
4—Which uses the Room model from:
class Room(models.Model):
title = models.CharField(max_length=200, blank=True)
layout = models.ForeignKey(Layout, related_name='template_selected', blank=True, null=True)
def __str__(self):
return self.title
5—Which takes one of the Layout models as a ForeignKey defined here:
class Layout(models.Model):
title = models.CharField(max_length=200)
...
padding_top = models.IntegerField(blank=False, default=0)
...
thumbnail = models.FileField(upload_to='layouts')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-title',)
def __str__(self):
return self.title
I am trying to figure out how to access attributes from Layout model within the actual form. I would especially like to dynamically load the Layout.thumbnail or Layout.padding_top within the form at the top. I have tried at least 8 different methods and was unable to figure out a way to make this work. Any help would be really appreciated.
As stated in this answer, you can access the current instance associated with the form like this in your template:
{{ form.instance }}
So to access the thumbnail or padding_top attributes of the linked layout:
{{ form.instance.layout.thumbnail }}
{{ form.instance.layout.padding_top }}

Can't use CKEDITOR in django template

I am using a form without a model class.
class ClubWallForm(forms.Form):
title = forms.CharField(label='Post title', max_length=100)
description = RichTextField()
imgURL = forms.CharField(label='Post image url', max_length=100)
filefield = forms.FileField( label='Select a file',validators=[validate_file_extension] )
In my template I used
` {% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}`
CKEDITOR is not geting displayed in my template.
This is what I am getting.
Inside my views it tried to use ipdb and found that the form has only fields title imgurl and filefield .
You have two issues:
RichTextField is a model field. RichTextFormField is the corresponding form field.
You're not handling the form media in the template. This is outlined in the documentation.
You can also use widget tweaks
First install it by
pip install django-widget-tweaks
then load it in your template file with
{% load wiget_tweaks %}
also use this in your site header
<script src="https://cdn.ckeditor.com/4.16.1/standard/ckeditor.js"></script>
now you can set your class to your form with out change it in forms.py
so the themplate file should be like this
{{ form.description|add_class:"ckeditor" }}
Second way is:
just use this code in themplate file
{{ form.media }}
{{ form.description }}
Finally I got an answer from my friend.
it was to replace
description = RichTextField()
with
description = forms.CharField(label='Description',
widget=forms.Textarea(attrs={'class': 'ckeditor'}))
inside forms.py
and it is working

Put model's id in hidden input in template

I would like to put a hidden input in my template containing my model's id. This is what I have:
models.py:
class MyModel(models.Model):
name = models.CharField(max_length=10)
class MyModelForm(ModelForm):
class Meta:
model = MyModel
fields = ['name']
widgets = {
'name': TextInput(),
}
index.html:
{{ form.name.label_tag }}
{{ form.name }}
This works fine and displays a simple form with a text input. What I want to do is add a hidden input that contains the model's id. I tried:
models.py:
class MyModel(models.Model):
name = models.CharField(max_length=10)
class MyModelForm(ModelForm):
class Meta:
model = MyModel
fields = ['name', 'id']
widgets = {
'name': TextInput(),
'id': HiddenInput(),
}
index.html:
{{ form.name.label_tag }}
{{ form.name }}
{{ form.id }}
But it doesn't work. If possible I wanted to avoid manually doing this:
index.html:
{{ form.name.label_tag }}
{{ form.name }}
<input type="hidden" name="id" value="{{ form.instance.id }}">
Thanks!
UPDATE
My overall goal is to have a form that edits an existing model. So I retrieve a model using the ORM and display it on the form. When I submit the form to update the object, I need to know its id in order for the ORM to know which object to update. Thanks!

Categories

Resources