I wanted to create simple datepicker that does not accept back dates. Within my models.py I have defined MealDay class and standalone functionvalidate_pub_date.
The logic behin works just fine, but I do not understand the way Django is showing up the ValidationError("Date can't be past!").
Why this is where it is, and why it seems to be within <li> tag? Is there any possibilty to handle the error within the HTML template or any other way to add some html/css to it? There is how the error looks now:
models.py:
def validate_pub_date(value):
if value < timezone.now() - datetime.timedelta(days=1):
raise ValidationError("Date can't be past!")
return value
class MealDay(models.Model):
day = models.DateTimeField(default=timezone.now().day, validators = [validate_pub_date])
breakfast = models.TextField(max_length=100, blank=True)
lunch = models.TextField(max_length=100)
dinner = models.TextField(max_length=100, blank=True)
views.py
class MealdayCreateView(CreateView):
model = MealDay
template_name = "mealplanner/mealday_new.html"
form_class = CreateMealdayForm
forms.py
class CreateMealdayForm(ModelForm):
class Meta:
model = MealDay
fields = '__all__'
widgets = {
'day': forms.DateInput(attrs={'type':'date'}),
}
mealday_new.html
{% extends "mealplanner/base.html" %}
{% block content %}
<h1>Plan your meals!</h1>
<form action="" method="post"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
{% endblock content %}
{% endblock content %}
in django model (validate_field_name) method is connected with .is_valid() method so when all fields of modelform not get correct input till it's raise a validation error.
Related
My models.py and this is my model for photos.
# home photo page
class Photos(models.Model):
photo_title = models.CharField(max_length=50, blank=False)
photo_description = models.CharField(max_length=50, blank=False)
photo_date = models.DateField(blank=False)
photo_location = models.CharField(max_length=50, blank=False)
photo_file = models.FileField(upload_to='photos', blank=False)
def __str__(self):
return self.photo_title
My forms.py this is the model form I made to render it as a form.
class UploadPhotosForm(forms.Form):
class Meta:
model = Photos
fields = '__all__'
my views.py these are my relavent imports and section I coded in view file.
from .forms import CampForm, ProjectForm, HikeForm, UploadPostsForm, UploadPhotosForm
posts = UploadPostsForm()
photo = UploadPhotosForm()
print(photo.as_p())
here this code should print the form as text into console isn't it?
But I don't have any console output. It seems like the nothing has been initialized to the photo variable isn't it?
I do not have any clue what happened.
context = {
'title': 'manage_wall',
'posts': posts,
'photo': photo,
}
return render(request, 'manager/manage_wall.html', context)
My template
{% block content %}
<div class="container">
<div class="row">
<div class="col">
<form action="" method="post">
{% csrf_token %}
{{photo.as_p}}
<input type="submit" value="Add">
</form>
</div>
<div class="col">
<form action="" method="post">
{% csrf_token %}
{{posts.as_p}}
<input type="submit" value=" Add">
</form>
</div>
</div>
</div>
{%endblock %}
As you can see here my photoForm is not rendering in the frontend can someone point out the mistake I have made not to render that form only while other forms are successfully rendering in the frontend. My Question is all other model forms rendered successfully why this is not displaying properly.
Your UploadPhotosForm is inherited from forms.Form(...)
class which does not contain model in Meta class so instead of inheriting from forms.Form class inherit from form.ModelForm(...)
here is final version of your code
class UploadPhotosForm(forms.ModelForm):
class Meta:
model = Photos
fields = '__all__'
I found the answer in models.py it should be forms.ModelForm
class UploadPhotosForm(forms.ModelForm):
class Meta:
model = Photos
fields = '__all__'
it is not rendering unless it is a ModelForm
Rendered django model object cannot give any output in template. My Code is:
model.py:
class MyModel(models.Model):
address = models.GenericIPAddressField(
max_length=15,
verbose_name=_('address')
)
Path = models.CharField(
max_length=300,
verbose_name='path',
)
activate = models.CharField(max_length=5, default='off', )
views.py:
class MyView(ListView):
model = models.MyModel.objects.all()[0]
template_name = '../on_off.html'
context_object_name = 'obj_list'
admin.py:
class MyAdmin(admin.ModelAdmin):
list_display = ('address', 'Path', )
exclude = ('activate', )
change_list_template = '../on_off.html'
on_off.html:
{% extends 'admin/change_list.html' %}
{% block object-tools %}
{% if obj_list %}
<form id="on_off_status" method="POST">
<label id="onoff" class="switch">
{% csrf_token %}
<input type="checkbox" id="togBtn" value=" {{ obj_list.activate }} ">
<div class="slider round"></div>
</label>
</form>
{% endif %}
...
In Django model, the system accepts only one object and I want to give to toggle switch button value in template using activate field in MyModel model. But it is not rendered in template, I couldn't get any object data even if I try <h1> {{ obj_list }} </h1>, it turns <h1> </h1> . Any help or suggestion appreciated.
Render the field manually
<label id="onoff" class="switch">
{% csrf_token %}
{{ obj_list.activate }}
<div class="slider round"></div>
</label>
Instead of using the views.py, django-admin provide a function named changelist_view(). Now it is working, I deleted the funtion in views.py and I added changelist_view() function to my admin.py looks like:
class MyAdmin(admin.ModelAdmin):
list_display = ('address', 'Path',)
exclude = ('activate',)
change_list_template = '../nfs_on_off.html'
def changelist_view(self, request, extra_context=None):
object = self.model.objects.all()
context={
'obj_list': object,
}
return super(MyAdmin, self).changelist_view(request, context)
I have two models. One is project and another is todo. The todo model has a foreign key that is the related project's id.
I have a template that displays the individual project and generates a link to a form to add a todo list. How do I pass the project id to the todo form?
I guess I could simply pass the project id in the URL but is that the best way?
My current views.py
class CompanyProjectsDetailView(DetailView):
model = Project
id = Project.objects.only('id')
template_name = 'company_accounts/project_detail.html'
class TodoCreateView(CreateView):
model = ProjectTodo
template_name = 'company_accounts/add_todo.html'
fields = ['title', 'notes', 'status']
Here is my template:
{% extends 'base.html' %}
{% block content %}
<h1>Add Todo</h1>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="save">
</form>
{% endblock content %}
To check to see if the project id is being passed to the form I have tried {{ project.id }} in the template and several other things that have not worked.
Adding this to the views solved the issue:
class TodoCreateView(CreateView):
model = ProjectTodo
template_name = 'company_accounts/add_todo.html'
fields = ['title', 'notes', 'status']
def form_valid(self, form):
project = get_object_or_404(Project, id=self.kwargs.get('pk'))
todo = form.save(commit=False)
todo.project = project
todo.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('project_detail', args=[self.kwargs.get('pk')])
I am trying to display a checklist in the CreateView using the values in the ForeignKey fields for descriptions.
models.py
class Structure(models.Model):
name = models.CharField(max_length = 30)
description =models.CharField(max_length = 300, null=True, blank=True)
def __str__(self):
return self.name
class SelectedFramework(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
structure = models.ForegignKey(Structure)
selected = models.BooleanField(default = False)
views.py
class FrameworkCreateView(generic.CreateView):
model = SelectedFramework
fields =['structure', 'selected']
template_name = 'catalogue/structure.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super(FrameworkCreateView, self).form_valid(form)
structure.html
{% extends 'catalogue\base.html' %}
{% block container %}
<h2>{% block title %}Structures{% endblock title %}</h2>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div class="col-sm-10">{{form.structure}} {{form.selected}}</div><br>
{% endfor %}
</div>
</form>
{% endblock %}
The code above works but will display the ForeignKey 'structure' as a dropdown list with the values of __str__. Is there a way to display string for structure.name and structure.description with the checkbox from selected in the CreateView?
In your template use:
{{ form.structure.name }}
{{ form.structure.description}}
You can write custom form, override the save method and create Structure object manually there:
class FrameworkForm(forms.ModelForm):
structure_name = forms.CharField(required=True)
structure_description = forms.CharField(required=False)
class Meta:
model = SelectedFramework
fields = [
'structure_name', 'structure_description', 'selected'
]
def save(self, commit=False):
instance = super(FrameworkForm, self).save(commit=False)
structure = Structure(
name=self.cleaned_data.get('structure_name'),
description=self.cleaned_data.get('structure_description')
)
structure.save()
instance.structure = structure
instance.save()
return instance
Also add form_class = FrameworkForm to your view instead of fields = ['structure', 'selected']
EDIT:
Perhaps you want something like this:
<ul>
{% for structure in form.fields.structure.choices.queryset %}
<li>{{ structure.name }} - {{ structure.description }}</li>
{% endfor %}
</ul>
If you want to get fields by iterating in the template. You have to use-
{% for field in form %}
{{ field }}
{% endfor %}
don't have to use any dot notation to get the field. If you want to get the label of the field you can use {{ field.label}} usually before {{field}}
I am trying to create a simple CRUD with ModelForm. It works fine except that every time I edit, saving creates a new instance of the data. So i edit and get an extra row in DB instead of an updated one. I am at a loss as to how it knows to save an existing charity as it does not store the PK (id) as a hidden field in the form. That is how I always did it before trying to use the 'fabulous' ModelForm!
It's driving me nuts, I have read everything and as far as I can tell I am doing everything right.
Here is my code..
Model:
from django.db import models
from django.conf import settings
COUNTRY_CHOICES = settings.COUNTRIES
class Charities(models.Model):
charity_name = models.CharField(max_length=100)
country = models.CharField(max_length=4, choices=COUNTRY_CHOICES)
registration_number = models.CharField(max_length=100)
address1 = models.CharField(max_length=100)
address2 = models.CharField(max_length=100)
city = models.CharField(max_length=30)
zip = models.CharField(max_length=10)
phone = models.CharField(max_length=20)
email = models.EmailField()
charity_logo_image = models.CharField(max_length=100)
charity_banner_image = models.CharField(max_length=100)
charity_accepted = models.IntegerField()
def __str__(self):
return self.charity_name
def __unicode__(self):
self.charity_name
View:
def list(request):
charities = Charities.objects.all()
return render_to_response('charities_charity_list.html', {'charities': charities})
def add(request):
return add_or_edit(request)
def edit(request, charity_id):
return add_or_edit(request, charity_id)
def add_or_edit(request, charity_id=None):
print "ID = " + str(charity_id)
form = CharityForm(request.POST or None,
instance=charity_id and Charities.objects.get(pk=charity_id))
# Save new/edited student
if request.method == 'POST' and form.is_valid():
print form
form.save()
return HttpResponseRedirect('/charities/list/')
return render_to_response('charities_charity_edit.html', {'form': form})
Form:
class CharityForm(ModelForm):
class Meta:
model = Charities
Template:
{% extends "base.html" %}
{% block title %}Charities Add{% endblock %}
{% block content %}
<form method="post" action="/charities/add/" id="save"><table cellpadding="0">{{ form.as_table}}</table><input type="submit" value="Save"></form>
{% endblock %}
It doesn`t work because your template is always POSTing to the view that adds a new Charity. When you manually type a URL like /charities/edit/5, it creates the ModelForm with the right initial data, but then POSTs to /charities/add, thus creating a new instance. You need to POST to /charities/edit/5, for example. Take a look at the url template tag.
I suggest you use 2 templates, one for adding, another for editing. I know it may not be very DRY, but I believe it's clearer this way.
Add template:
{% extends "base.html" %}
{% block title %}Charities Add{% endblock %}
{% block content %}
<form method="post" action="{% url charities_app.views.add %}"><table cellpadding="0">{{ form.as_table}}</table><input type="submit" value="Save"></form>
{% endblock %}
Edit template:
{% extends "base.html" %}
{% block title %}Edit Charity{% endblock %}
{% block content %}
<form method="post" action="{% url charities_app.views.edit charity.id %}"><table cellpadding="0">{{ form.as_table}}</table><input type="submit" value="Save"></form>
{% endblock %}
You may also want to check the create_object and update_object generic views, they are very useful in simple cases like yours.