Why is the inline formset not validating - python

I have two models with foreign key relation
models.py
from django.db import models
# Create your models here.
class Project(models.Model):
STATUSES = (
('Ongoing', 'Ongoing'),
('Completed', 'Completed')
)
YEARS = (
(2019, 2019),
(2020, 2020),
(2021, 2021),
(2022, 2022)
)
name = models.CharField(max_length=200)
client = models.CharField(max_length=100)
year = models.SmallIntegerField(choices=YEARS)
status = models.CharField(max_length=10, choices=STATUSES)
picture = models.ImageField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class Photo(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE, related_name="images", blank=True, null=True)
image = models.ImageField()
description = models.CharField(max_length=100, blank=True, null=True)
slide = models.BooleanField(default=False)
I want photos and project to be created on the same form so I've used inline_formset_factory
forms.py
from django.forms import inlineformset_factory
from projects.models import Photo, Project
from django.forms import ModelForm
class ProjectModelForm(ModelForm):
class Meta:
model = Project
fields = (
'name',
'client',
'year',
'picture',
'status',
'description',
)
class PhotoModelForm(ModelForm):
class Meta:
model = Photo
fields = (
'image',
'slide',
'description'
)
PhotoFormset = inlineformset_factory(Project, Photo, form=PhotoModelForm, extra=1)
I used the generic CreateView
views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from projects.forms import PhotoFormset, ProjectModelForm
from django.shortcuts import redirect, reverse, render
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from .models import Photo, Project
# Create your views here.
class ProjectCreateView(LoginRequiredMixin, CreateView):
template_name = 'projects/project_create.html'
form_class = ProjectModelForm
def get_context_data(self, **kwargs):
context = super(ProjectCreateView, self).get_context_data(**kwargs)
context['photos_formset'] = PhotoFormset()
return context
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
photo_formset = PhotoFormset(self.request.POST)
if form.is_valid() and photo_formset.is_valid():
return self.form_valid(form, photo_formset)
else:
return self.form_invalid(form, photo_formset)
def form_valid(self, form, photo_formset):
self.object = form.save(commit=False)
self.object.save()
print('valid')
photos = photo_formset.save(commit=False)
for photo in photos:
photo.project = self.object
photo.save()
return reverse('projects:projectspage')
def form_invalid(self, form, photo_formset):
if not photo_formset.is_valid():
print('invalid formset')
return self.render_to_response(
self.get_context_data(form=form, photos_formset=photo_formset)
)
def get_success_url(self):
return reverse('projects:projectspage')
this is the template
{% extends 'base.html' %}
{% load crispy_forms_filters %}
<!-- crispy_forms_tags -->
{% block content %}
<div class="container">
<h2>create new project</h2>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<h2 class="display-6 my-5">
Add photos
</h2>
{{ photos_formset.as_p }}
<input type="submit" value="Create" class="btn btn-primary">
</form>
</div>
{% endblock content %}
When I submit form_invalid is returned from the post method of the view
How do i get the inline_formset to validate or is there better way of doing it

I prefer to write those views as functions, seems more straightforward, try:
#login_required
def post_news(request):
if request.method == 'POST':
project_form = ProjectModelForm(request.POST, request.FILES)
photo_form = PhotoModelForm(request.POST, request.FILES)
picture = request.FILES['picture']
image = request.FILES['image']
if project_form.is_valid() and photo_form.is_valid():
project_instance = project_form.save(commit=False)
project_instance.picture = picture
project_instance.save()
photo_instance = project_form.save(commit=False)
photo_instance.project = project_instance
photo_instance.image = image
photo_instance.save()
return reverse('projects:projectspage')
else:
project_form = ProjectModelForm()
photo_form = PhotoModelForm()
return render(request, 'projects/project_create.html',
{'project_form': project_form, 'photo_form': photo_form})
You will have to account for a case when no picture for the project model is is provided I think. Just pop both forms into your template and this should work.

Related

Django: How do I assign a button to take info and save()

Is there a way for the button to do the following? : When user press the button it takes the user.username of the current user and automatically fill up a form of BookInstance from models.py and save it to the database.
From models.py :
class BookInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
book = models.ForeignKey("Book", on_delete=models.RESTRICT, null=True)
imprint = models.CharField(max_length=200, blank=True, null=True)
due_back = models.DateField(blank=True, null=True)
borrower = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
LOAN_STATUS = (
('m', 'Maintenance'),
('o', 'On Loan'),
('a', 'Available'),
('r', 'Reserved')
)
status = models.CharField(
max_length=1, choices=LOAN_STATUS, blank=True, default='a')
class Meta:
ordering = ['due_back']
def __str__(self):
return f'{self.id} - {self.book.title}'
def get_absolute_url(self):
return reverse("catalog:book_list")
class Book(models.Model):
title = models.CharField(max_length=50)
author = models.ForeignKey(
'Author', on_delete=models.SET_NULL, null=True)
summary = models.TextField(
max_length=500, help_text="Enter brief description")
isbn = models.CharField('ISBN', max_length=13, unique=True)
genre = models.ManyToManyField(Genre, help_text="Select genre")
language = models.ForeignKey(
"Language", on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("catalog:book_detail", kwargs={"pk": self.pk})
This is my from my views.py :
def borrowBook(request, pk):
context = {
'book_instance': BookInstance.objects.all()
}
success_url = reverse_lazy('catalog:index')
if request.method == "POST":
form = BorrowForm(request.POST or None)
if form.is_valid():
book_instance.id = BookInstance.objects.get(pk=pk)
book_instance.book = BookInstance.objects.get(book=book)
book_instance.borrower = request.user
book_instance.status = 'o'
book_borrowed_count = BookInstance.objects.filter(
owner=request.user).count()
if book_borrowed_count < 4:
book_instance = form.save(commit=False)
book_instance.save()
else:
print("Maximum limit reached!")
return redirect('catalog:index')
return render(request, 'catalog/book_detail.html', {'form': form})
here's from my BorrowForm from forms.py :
class BorrowForm(forms.ModelForm):
class Meta:
model = BookInstance
fields = '__all__'
here's my from my urls.py :
path("book_list/book/<int:pk>/borrow", views.borrowBook, name="borrowBook"),
I also tried using a CBV here:
class BorrowBookView(PermissionRequiredMixin, CreateView):
permission_required = 'login'
model = BookInstance
fields = '__all__'
template_name = 'catalog/borrow_form.html'
success_url = reverse_lazy('catalog:index')
def post(self, request, *args, **kwargs):
book_instance.id = BookInstance.objects.get(pk=pk)
book_instance.book = BookInstance.objects.get(book=book)
book_instance.borrower = request.user
book_instance.status = 'o'
book_instance = form.save(commit=False)
book_instance.save()
CBV path from urls.py :
path("book_list/book/<int:pk>/borrow/",
views.BorrowBookView.as_view(), name="book_borrow"),
Here's how I implemented the button using suggestions from here:
<form action="#" method="post">
{% csrf_token %}
<button
type="submit"
class="btn btn-dark flex-shrink-0 "
value="{{ book.id }}">Borrow
</button>
but when I pressed it doesn't seem to save anything to the database and just popup errors, though I may implemented the button or the function from my is views wrong. Thanks and appreciate for any help provided.
You do not need a Django form for this. Forms are usually used for when you want to create objects or edit its fields (like in the admin page). While here an user is not editing nor creating an object (book), but borrowing one.
So basically, we just need to list all available book instances (status='a'), and have a button to "borrow" it. The borrow action is to update status to 'r' or 'o' and have the borrower updated to the current user which is guaranteed to exist inside the request object by LoginRequiredMixin
views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django.contrib import messages
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from .models import BookInstance
class BorrowBook(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
book_id = kwargs['pk']
available_books = BookInstance.objects.filter(book__pk=book_id, status='a')
return render(request, 'borrow_book.html', {'available_books': available_books})
def post(self, request, *args , **kwargs):
book_instance_id = request.POST['id']
obj = get_object_or_404(BookInstance, id=book_instance_id)
obj.status = 'r'
obj.borrower = request.user
# Maybe also update due_back data
# obj.due_back = ...
obj.save()
messages.success(request, "Your book is reserved.")
# I used the redirection to the same template
# But you probably want to send the user somewhere else
return HttpResponseRedirect(reverse('core:borrow-book', kwargs={'pk': 1}))
borrow_book.html
{% extends 'base.html' %}
{% block content %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% for instance in available_books %}
<form action="{% url 'core:borrow-book' instance.book.id %}" method="POST">
{% csrf_token %}
<input type="hidden" name="id" value="{{instance.id}}">
<p>{{instance.book}}</p>
<p>{{instance.book.language.name}}</p>
<input type="submit" value="Borrow this book.">
</form>
{% endfor %}
{% endblock content %}
urls.py
from django.urls import path
from core import views
app_name = 'core'
urlpatterns = [
path("book_list/book/<int:pk>/borrow/", views.BorrowBook.as_view(), name="borrow-book"),
]

Django version 3.1.3 form not saving to model

I am following this tutorial
I have gone back and written the code to match exactly. I have another form that works called category_add which is exactly the same as this form. But for the life of me I cannot figure out why bookmark_add doesn't update the database with the form entries.
Models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
title = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='categories', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Categories'
def __str__(self):
return self.title
class Bookmark(models.Model):
category = models.ForeignKey(Category, related_name='bookmarks', on_delete=models.CASCADE)
title = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
url = models.CharField(max_length=255, blank=True)
created_by = models.ForeignKey(User, related_name='bookmarks', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
View.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import BookmarkForm
#login_required
def bookmark_add(request, category_id):
if request.method == 'POST':
form = BookmarkForm(request.POST)
if form.is_valid():
bookmark = form.save(commit=False)
bookmark.created_by = request.user
bookmark.category_id = category_id
bookmark.save()
return redirect('category', category_id=category_id)
else:
form = BookmarkForm()
context = {
'form': form
}
return render(request, 'bookmark/bookmark_add.html', context)
Forms.py
from django.forms import ModelForm
from .models import Bookmark
class BookmarkForm(ModelForm):
class Meta:
model = Bookmark
fields = ['title', 'description', 'url']
Urls.py
path('', dashboard, name='dashboard'),
path('categories/', categories, name='categories'),
path('categories/add/', category_add, name='category_add'),
path('categories/<int:category_id>/', category, name='category'),
path('categories/<int:category_id>/add_bookmark', bookmark_add, name='bookmark_add')
]
bookmark_add.html
{% extends 'core/base.html' %}
{% block content %}
<div class="container">
<h1 class="title">Add link</h1>
<form method="post" action=".">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="button is-primary">Submit</button>
</form>
</div>
{% endblock %}
Solved this!
This was a dumb issue and an oversight on my end. Thanks to the content creator on youtube. I just needed to append "/" to the url path for add_bookmark.
Problem:
path('categories/<int:category_id>/add_bookmark', bookmark_add, name='bookmark_add')
The Fix:
path('categories/<int:category_id>/add_bookmark/', bookmark_add, name='bookmark_add')

Getting error 405 while using ModelFormMixin with DetailView

I want to create a DetailView page which displays the detail of a model but I want to add a Comment section in the DetailView page using ModelFormMixin.
This is my views.py code:
class PostDetailView(ModelFormMixin, DetailView):
model = UserPost
context_object_name='post_detail'
form_class = UserCommentForm
def get_context_data(self, *args, **kwargs):
context = super(PostDetailView, self).get_context_data(*args, **kwargs)
context['form'] = self.get_form()
return context
def get_absolute_url(self):
return reverse(request, 'basic_app:post_detail', kwargs={'pk':self.pk})
But when I hit the submit button it shows the following error:
Edited part:
This is my views.py file
model.py
forms.py
userpost_detail.html
browser image before clicking enter button
browser image after clicking enter button
django admin page
I'm sorry for not uploading the actual code because it was too difficult to upload that bulk of code.
I think the following code will help you. I code it a long time ago, but it seems to solve your problem (I didn't use taggit, so I created a PostTag model):
Models:
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.timezone import localtime
from django.urls import reverse
class User(AbstractUser):
pass
class PublishedManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(status='published')
class PostTag(models.Model):
name = models.CharField(max_length=40)
slug = models.SlugField(max_length=40)
def __str__(self):
return self.name
class Post(models.Model):
POST_STATUS = (('draft', 'Draft'), ('published', 'Published'))
title = models.CharField(max_length=100)
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
created = models.DateTimeField(auto_now_add=True)
publish = models.DateTimeField(auto_now=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=100, unique_for_date='publish')
status = models.CharField(max_length=10, choices=POST_STATUS, default='draft')
tags = models.ManyToManyField(PostTag, blank=True)
def get_absolute_url(self):
local_time = localtime(self.publish)
return reverse("blog:post_date_detail", args=[local_time.year, local_time.month, local_time.day, self.slug])
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
objects = models.Manager() # The default manager.
published = PublishedManager() # Custom manager.
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
def get_absolute_url(self):
local_time = localtime(self.post.publish)
return reverse("blog:post_date_detail", args=[local_time.year, local_time.month, local_time.day, self.post.slug])
class Meta:
ordering = ('created',)
def __str__(self):
return f'Comment by {self.name} on {self.post}'
Views:
from django.shortcuts import render, get_object_or_404, HttpResponseRedirect
from django.views.generic import ListView, DetailView, View
from django.views.generic.edit import FormView, SingleObjectMixin, CreateView
from django.views.generic.dates import YearArchiveView, MonthArchiveView, DateDetailView
from django.core.mail import send_mail
from django.db.models import Count
from .models import Post, User, Comment, PostTag
from .forms import EmailPostForm, CommentForm
class PostListView(ListView):
queryset = Post.published.all()
context_object_name = 'posts'
paginate_by = 4
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# si hay kwargs se actualiza el context
if self.kwargs:
context["tag"] = self.kwargs['tag_slug']
return context
def get_queryset(self):
tag = None
if self.kwargs:
tag_slug = self.kwargs['tag_slug']
tag = get_object_or_404(PostTag, slug=tag_slug)
posts = self.queryset.filter(tags__in=[tag])
return posts
return self.queryset
class PostYearArchiveView(YearArchiveView):
queryset = Post.published.all()
template_name = 'blog/post_list.html'
date_field = "publish"
context_object_name = 'posts'
make_object_list = True
paginate_by = 4
class PostMonthArchiveView(MonthArchiveView):
queryset = Post.published.all()
template_name = 'blog/post_list.html'
date_field = "publish"
context_object_name = 'posts'
month_format='%m'
paginate_by = 4
class PostDateDetailView(DateDetailView):
queryset = Post.published.all()
date_field = "publish"
month_format='%m'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = self.get_object()
post_tags_pks = obj.tags.all().values_list('pk', flat=True)
related_posts = self.queryset.filter(tags__in=post_tags_pks).exclude(pk=obj.pk)
related_posts = related_posts.annotate(same_tags=Count('tags')).order_by('-same_tags','-publish')[:3]
context["related_posts"] = related_posts
comments = obj.comments.filter(active=True)
context["comments"] = comments
context['post_id'] = obj.pk
context['form'] = CommentForm()
return context
class NewComment(CreateView):
model = Comment
template_name = 'blog/post_detail.html'
form_class = CommentForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
post = context["form"].instance.post
context['post'] = post
post_tags_pks = post.tags.all().values_list('pk', flat=True)
related_posts = Post.published.filter(tags__in=post_tags_pks).exclude(pk=post.pk)
related_posts = related_posts.annotate(same_tags=Count('tags')).order_by('-same_tags','-publish')[:3]
context["related_posts"] = related_posts
comments = post.comments.filter(active=True)
context["comments"] = comments
return context
class PostDetail(View):
def get(self, request, *args, **kwargs):
view = PostDateDetailView.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = NewComment.as_view()
return view(request, *args, **kwargs)
class SharePostView(SingleObjectMixin, FormView):
form_class = EmailPostForm
template_name = 'blog/post_share.html'
success_url = '/blog'
context_object_name = 'posts'
queryset = Post.published.all()
def get(self, request, *args, **kwargs):
post = self.get_object()
context = {'post': post, 'form': self.form_class}
return render(request, self.template_name, context)
def form_valid(self, form):
post = self.get_object()
post_url = self.request.build_absolute_uri(post.get_absolute_url())
form.send_mail(post, post_url)
return super(SharePostView, self).form_valid(form)
Considerations: See get_context_data to add other data to the context: in this case tags, related_post, the form, etc...
I have used 3 views. DateDetailView (similar to your DetailView) to display the page (with the context needed).
CreateView to manage the POST method and save the comment into the DB. I have also added context to get the post information.
Finally a View with the intention of managing the same URL,but calling the appropiate view
when the request is GET or POST. See urls.py
URLS:
from django.urls import path
from blog import views
from blog.models import Post
app_name = 'blog'
urlpatterns = [
path("", views.PostListView.as_view(), name="post_list"),
path('tag/<slug:tag_slug>/', views.PostListView.as_view(), name='post_list_by_tag'),
path('<int:year>/', views.PostYearArchiveView.as_view(), name="post_year_archive"),
path('<int:year>/<int:month>/', views.PostMonthArchiveView.as_view(), name="post_month_numeric"),
path('<int:year>/<int:month>/<int:day>/<slug:slug>/', views.PostDetail.as_view(), name="post_date_detail"),
path('<int:pk>/share/', views.SharePostView.as_view(), name='post_share'),
]
Comment form:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('name', 'email', 'body', 'post')
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'Name'}),
'email': forms.EmailInput(attrs={'placeholder': 'E-mail'}),
'body': forms.Textarea(attrs={'placeholder': 'Write your message here'}),
'post' : forms.HiddenInput(),
}
form in template:
<form method="post" action="" novalidate>
{% csrf_token %}
<div class="input-group input-group-icon">
{{ form.name }}
<div class="input-icon"><i class="fas fa-user"></i></div>
{% if form.name.errors %}
{{form.name.errors}}
{% endif %}
</div>
<div class="input-group input-group-icon">
{{form.email }}
<div class="input-icon">
<i class="fas fa-envelope"></i>
</div>
{% if form.email.errors %}
{{form.email.errors}}
{% endif %}
</div>
<div class="msg">
<div class="input-group">{{form.body}}
{% if form.body.errors %}
{{form.body.errors}}
{% endif %}
</div>
</div>
<input type="hidden" name="post" value="{{ post.pk }}">
<div class="input-group send-reset">
<input type="submit" value="Enviar Comentario" />
</div>
</form>
Considerations: See the input type=hidden to get the post.pk. This is needed to save the comment.post field.
I think I covered all the issues you can have. Hope it helps!!

Dropdownlist not displayed in Django

I am trying to implement a dropdownlist from my models into an HTML using Django. The form is working perfectly, but the dropdownlist is not displayed, it only displays "languages:" but not a dropdownlist or any options.
Any ideas?
add_page.html
{% extends 'main/header.html' %}
{% block content %}
<br>
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button style="background-color:#F4EB16; color:blue"
class="btn btn-outline-info" type="submit">Add Page</button>
</form>
{% endblock %}
forms.py
from django import forms
from django.forms import ModelForm
from main.models import Pages
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.db import models
class NewUserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
def save(self, commit=True):
user = super(NewUserForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
class PagesForm(ModelForm):
class Meta:
model = Pages
fields = ["title","language","content"]
models.py
from django.db import models
from datetime import datetime
#from django.forms import ModelForm
# Create your models here.
LANGUAGE_CHOICES = (
('english','ENGLISH'),
('spanish', 'SPANISH'),
('german','GERMAN'),
('french','FRENCH'),
('chinese','CHINESE'),
)
#Pages son entradas del diario
class Pages(models.Model):
title = models.CharField(max_length=300)
content = models.TextField()
author = models.CharField(max_length=50)
published_date = models.DateTimeField("Published: ", default=datetime.now())
language = models.CharField(max_length=7, choices=LANGUAGE_CHOICES, default='english')
def __str__(self):
return self.title
views.py
#/pages/my_pages/add_page
#login_required
def add_page(request):
if request.method == "POST":
form = PagesForm(request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.author = request.user.username
model_instance.timestamp = timezone.now()
messages.success(request, f"New page created, thank you: {model_instance.author}")
model_instance.save()
return redirect('/')
else:
form = PagesForm()
return render(request, "main/add_page.html", {'form': form})
I've got nothing else to say, but the editor wont let me edit unless I write more text...

GeoDjango display map on template form from model

I am trying to build a sample website based on Django(GeoDjango) and OpenStreetMap. So far I have this simple scenario:
Models.py
class Parks(models.Model):
park_name_en = models.CharField(max_length=256)
description = models.TextField()
picture = models.ImageField()
geom = PolygonField()
#property
def picture_url(self):
return self.picture.url
def __unicode__(self):
return self.title
views.py
def park_insert(request):
form = ParkForm()
return render(request, 'addpark.html', {'form': form})
forms.py
class ParkForm(forms.ModelForm):
class Meta:
model = Parks
fields = ('park_name_en', 'description', 'picture',)
geom = forms.PolygonField()
and last but not least the template addpark.html
<html>
<head>
{{ form.media }}
</head>
<body>
<div id="map">
<form enctype="multipart/form-data" method="post" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
</div>
</body></html>
When I open the template page all fields come up right, except the PolygonField() which comes up as a text. How can I display a map on the user form also (I got it working in the admin panel, but I want to create a form for inserting new parks)
You need to describe "forms " models.py.
Models.py
from django.contrib.gis import forms
class Parks(models.Model):
park_name_en = models.CharField(max_length=256)
description = models.TextField()
picture = models.ImageField()
geom = models.PointField(widget= forms.OSMWidget(attrs={'map_width': 800, 'map_height': 500}) )
#property
def picture_url(self):
return self.picture.url
def __unicode__(self):
return self.title
views.py
def park_insert(request):
form = ParkForm()
return render(request, 'addpark.html', {'form': form})
forms.py
class ParkForm(forms.ModelForm):
class Meta:
model = Parks
fields = ('park_name_en', 'description', 'picture',)
geom = forms.PolygonField()
Try it. And looked this
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/forms-api/#widget-classes
I added widget in forms.py because adding this attribute in model causes exception.
forms.py
from django.contrib.gis import forms
from .models import Memory
class AddMemoryForm(forms.Form, forms.ModelForm):
class Meta:
model = Memory
fields = ['title', 'description', 'location']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-input'}),
'description': forms.Textarea(attrs={'cols': 60, 'rows': 10}),
'location': forms.OSMWidget
}
views.py
class ShowMemory(LoginRequiredMixin, UpdateView):
template_name = 'world/detail_memory.html'
model = Memory
form_class = UpdateMemoryForm
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = context['memory']
return context
def get_success_url(self):
return reverse_lazy('memory')
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
UpdateMemoryForm is the similar to AddMemoryForm

Categories