How to add Widgets to UpdateView in Django - django

I need to add this widget to the django UpdateView,
class tlistUpdate(LoginRequiredMixin,UpdateView):
fields = ('title', 'thumbnail', 'content', 'tags')
model = htmlpage
template_name = 'blog/create_form.html'
Tried adding
widgets = {
'content': SummernoteWidget(),
}
and
content = forms.CharField(widget=SummernoteWidget())
But it did't work.

The UpdateView is not constructed to handle advanced form construction. The idea is that you use fields if you aim to construct a simple (standard) Form.
You can simply construct a ModelForm and use that form in your CreateView/UpdateView:
# app/forms.py
from django import forms
class HtmlPageForm(forms.ModelForm):
class Meta:
model = HtmlPage
fields = ('title', 'thumbnail', 'content', 'tags')
widgets = {
'content': SummernoteWidget
}
In your views.py you can then use the form by setting the form_class attribute [Django-doc]:
# app/views.py
from app.forms import HtmlPageForm
class TlistUpdate(LoginRequiredMixin,UpdateView):
model = htmlpage
form_class = HtmlPageForm
template_name = 'blog/create_form.html'
Note: normally a Django models, just like all classes in Python are given a name in PerlCase, not snake_case, so it should be: HtmlPage instead of htmlpage.

Related

Attribute to override generic class based form and use a custom form?

I have the following form in forms.py:
class JobForm(ModelForm):
class Meta:
model = Job
fields = ['title', 'description']
widgets = {'title': TextInput(attrs={'class':'form-control'}),
'description': Textarea(attrs={'class':'form-control'})
}
is there a way I can tell this view (and the CreateView) to use the form above:
from .forms import JobForm
class JobUpdateView(UpdateView):
model = Job
fields = ['title', 'description']
template_name = 'job/edit_job.html'
form = JobForm() # I imagined some attribute like this to specify the form
I'm just getting into using class-cased views and feel like this should have been easy to find with a quick search. Am I missing the point here, are you supposed to not have to define a custom for in forms.py if you are using class-based views?
Use form_class attribute of UpdateView
https://docs.djangoproject.com/en/3.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class

How to filter Django's foreignKey form dropdown

I have a form that is used to edit (update) a record, and the Author field is automatically a dropdown, which is great, but how do you filter this list?
For example, the dropdown is populated with the entire user list. How can I filter this list so that it only shows the items where isDevice == True?
accounts/models.py
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
isDevice = models.BooleanField(default = False)
...
builds/models.py
class BuildQueue(models.Model):
Author = models.ForeignKey(CustomUser,blank=True, null= True, on_delete=models.CASCADE)
...
forms.py
class BuildQueueEditForm(forms.ModelForm):
class Meta:
model = BuildQueue
fields = ['Author','project', 'customer',]
views.py
class buildQueueEdit(LoginRequiredMixin,UpdateView):
model = BuildQueue
form_class = BuildQueueEditForm
template_name = 'buildQueue_edit.html'
Since UpdateView inherited also from FormMixin, in your buildQueueEdit you can override get_form, where form is instantiated and exactly where you can modify the form's field's queryset.
class buildQueueEdit(LoginRequiredMixin,UpdateView):
model = BuildQueue
form_class = BuildQueueEditForm
template_name = 'buildQueue_edit.html'
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['Author'].queryset = CustomUser.objects.filter(isDevice=True)
return form
UPDATE
If you want to change text displayed in your dropdown you can override choises instead of queryset. It worked for me.
form.fields['Author'].choices = [(item.id, item.equipmentName) for item in CustomUser.objects.filter(isDevice=True)]

Django update modelform with field constraints

Having the following Model:
class Book(models.Model):
name = models.CharField()
author = models.CharField()
date = models.DateField()
class Meta:
unique_together = ('name', 'author')
class BookSerializerWrite(serializers.ModelSerializer):
class Meta:
model = Book
class BookView(ApiView):
def put(self, request, *args, **kwargs):
serializer = BookSerializerWrite(data=request.data)
if serializer.is_valid():
serializer.save()
The view above does not work as the serializer.is_valid() is False.
The message is:
'The fields name, author must make a unique set'
Which is the constraint of the model.
How do I update the model?
I would rather not override the serializer's validation method.
I also cannot access the validated_data for an update as in
https://www.django-rest-framework.org/api-guide/serializers/#saving-instances
as this is empty due to the fact that the form does not validate.
Is there a builtin solution?
You can achieve it using UpdateAPIview
serializers.py
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('name', 'author', 'date')
views.py
from rest_framework.generics import UpdateAPIview
from .serializers import BookSerializer
class BookUpdateView(UpdateAPIView):
serializer_class = BookSerializer
urls.py
from django.urls import path
from . import views
url_patterns = [
path('api/book/<int:pk>/update/', views.BookUpdateView.as_view(), name="book_update"),
]
Now, post your data to above url. It should work.
Reference: https://github.com/encode/django-rest-framework/blob/master/rest_framework/generics.py

Add descriptive text to the right of field in Django admin

I have a DecimalField in my model that I'd like to show up in the admin interface with a unit to the right of the field, like so:
I think if I add help_text to the field, that will show up below the field. Is there a way to specify it to show up to the right?
You can handle it with help_text from the forms, overwrite your field in the form, such as the css.
from django.db import models
from django.contrib import admin
from django import forms
from your.models import Post
class PostForm(forms.ModelForm):
ethanol = forms.FloatField(
label='This is Ethanol',
max_value=10,
min_value=0,
widget=forms.NumberInput(
attrs={
'class': 'whatever',
'style': 'position:relative'
}
),
help_text='<span style="position:absolute;right:0">g/mL</span>'
)
class Meta:
model = Post
fields = '__all__'
class PostAdmin(admin.ModelAdmin):
form = PostForm
list_display = ['ethanol', 'id']
admin.site.register(Post, PostAdmin)

Override a Django generic class-based view widget

Say I have a basic CreateView form, like this, to allow new users to register on a site:
from django.contrib.auth import get_user_model
from django.http import HttpResponse
from django.views.generic import CreateView
User = get_user_model()
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
I just tried this, and found that the password field is rendered in plain text; how would I go about overriding the view so that it uses forms.PasswordInput() instead? (I realise it's probably easiest to just define the form by hand, but I'm just curious about how you'd do that.)
You could override get_form(), and modify the form to change the widget on the password field:
from django import forms
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class):
form = super(Signup, self).get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
But an even better way would be to just create a custom form class. In the custom class just set widgets on the Meta class. Like this:
from django import forms
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
widgets = {
'password': forms.PasswordInput()
}
class Signup(CreateView):
form_class = SignupForm
model = User
Usually you would put the custom form class in a forms.py file as well.
Not sure if this affected earlier versions of Django, but in more recent versions the get_form() should have a default form_class=None when overriding that method.
The updated (Python 3, Django 2.2) example would be:
from django import forms
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
https://docs.djangoproject.com/en/2.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin