I am trying to use TreeBeard's built in Form's with django forms (not admin). I specifically wanted to replace the rendering of a Select ForeignKey field with TreeBeard forms format. I thought I could do this by declaring the field in my ModelForm, but I've had no success. I'm new to django so my understanding is limited.
These are my initial classes in my forms.py
MyCategories = movenodeform_factory(Category)
class CreatePost(ModelForm):
class Meta:
model = Post
fields = ['title', 'category', 'region', 'content', ]
I tried implementing it by declaring the category field in the beginning but this clearly isn't the way to do it. The declaration does return an html formatted category list, but I can't replace the Post category (which is a ForeignKey)with it.
class CreatePost(ModelForm):
category = movenodeform_factory(Category)
class Meta:
model = Post
fields = ['title', 'category', 'region', 'content', ]
The reason I want to use TreeBeard forms is because of the way it nests the fields according to the category hierarchy.
SOLVED:
This ended up being much simpler than I realized.
class CreatePost(ModelForm):
CHOICES = MoveNodeForm.mk_dropdown_tree(Category)
category = ChoiceField(choices=CHOICES)
class Meta:
model = Post
fields = ['title', 'category', 'region', 'content', ]
The solution was right in front of me. I just needed to create a list using mk_dropdown_tree and use it in a ChoiceField. I hope this might help someone someday.
class CreatePost(ModelForm):
CHOICES = MoveNodeForm.mk_dropdown_tree(Category)
category = ChoiceField(choices=CHOICES)
class Meta:
model = Post
fields = ['title', 'category', 'region', 'content', ]
Related
I have Profile model, which is auth model. And I have Blog model. I want to serialize model as it will give me {author: {user_name:.., photo: photo_path}, blog_title:some_title, ..}. Shortly, I want use author field as inner serialiser. I have already ProfileSerialiser and BlogSerializer. Here's my BlogList serializer:
class BlogListSerializer(serializers.ModelSerializer):
author = MiniProfileSerializer()
class Meta:
model = Blog
fields = ['title', 'content', 'like_count', 'author']
read_only_fields = ['views', 'author', 'like_count']
And MiniProfileSerializer:
class MiniProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['user_name', 'image']
and view:
class BlogListAPIView(generics.ListCreateAPIView):
serializer_class = BlogListSerializer
queryset = Blog.published.all()
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
Django REST Framework does not support writing to a nested serializer out of the box. You can check out DRF Writeable Nested, or write your own custom behavior on create by overwriting create() in the BlogListSerializer.
EDIT: Here's some more docs on the topic: https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
I'm working on a project that has a Chapter, with each Chapter having a title, content, and order. I'd like to keep the field 'order' named as is, but have the field displayed in a CreateView as something else, like 'Chapter number'. The best information I've found recommends updating the "labels" attribute in the Meta class, but this isn't working for me.
This is what I'm using now, which doesn't work:
class ChapterCreate(CreateView):
model = models.Chapter
fields = [
'title',
'content',
'order',
]
class Meta:
labels = {
'order': _('Chapter number'),
}
I've also tried using the 'label's attribute outside of Meta, but that didn't work either. Should I be using a ModelForm instead, or is there a correct way to do this?
The simplest solution in this case would be to set the verbose_name for your model field
class Chapter(models.Model):
order = models.IntegerField(verbose_name= _('Chapter number'))
Note I have use IntegerField in this example, please use whatever type is required.
Even if it is an old subject, I think a way to do this now with Django 3.1 would be:
in views.py
class ChapterCreate(CreateView):
model = models.Chapter
form_class = ChapterForm
and in forms.py, define ChapterForm
class ChapterForm(ModelForm):
class Meta:
model = models.Chapter
fields = ('title', 'content','order')
labels = {
'order': _('Chapter number'),
}
If you want different values for the verbose_name of the model field and the user-facing label of the form field, the quickest way might be to override the get_form(…) method of CreateView:
class ChapterCreate(CreateView):
(...)
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['order'].label = _('Chapter number')
return form
I want to make it possible for a json that gives all the model instances to go to a particular instance using the additional url field in the serializer.
There is a view to display the list
class DocumentsListView(viewsets.ViewSetMixin, generics.ListCreateAPIView):
user = serializers.PrimaryKeyRelatedField(read_only=True,)
queryset = Documents.objects.all()
serializer_class = DocumentsSerializer
permission_classes = []
def perform_create(self, serializer):
serializer.save(author=self.request.user)
urls.py
router = DefaultRouter()
router.register('', DocumentsListView)
urlpatterns = [
url('', include(router.urls), name='files')
]
serializers.py
class DocumentsSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedRelatedField(view_name='documents-detail')
class Meta:
model = Documents
fields = ('id', 'filename', 'datafile', 'type', 'created', 'url')
but got an error
'Relational field must provide a `queryset` argument, '
AssertionError: Relational field must provide a `queryset` argument, override `get_queryset`, or set read_only=`True`.
If I set read_only='True', it works, but url didnt displayed
I've also tried this way of implementing serializer
class DocumentsSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Documents
fields = ('id', 'filename', 'datafile', 'type', 'created', 'url')
but got an error
Could not resolve URL for hyperlinked relationship using view name "doctype-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field
Recall that every view has a serializer set in serializer_class, and your serializer has a Meta class where you set a model, and thats how you reference the model type you're relating to in HyperLinkedRelatedField. The view_name field is the name of that model followed by '-list' if the url you request does not end with an id(for example when making POST requests), and '-detail' if it does.
Don't know if you eventually solved it but I also experienced something similar, and the solution was changing the HyperlinkedRelatedField to an HyperlinkedIdentityField.
I am trying to understand the process of generating generic form views in django. I have a generic view class with just
class BookUpdate(UpdateView):
model = Book
fields = [ 'name',
'pages',
'categorys'
]
which automatically generates a working html form from my model data. But now, I want to modify the field that is shown for categorys, is there any way to do this, or do I have to create a complete working BookForm class and custom BookUpdate class? Here its just 3 fields, but in my real case there are maybe 15 fields that I would need to code by myself, just because of a tiny change in the category field.
Cant I just overwrite the single field, using any class method?
You can either specify fields or form_class in your generic class-based view. With fields, Django will use a modelform_factory to generate the form. There's not much you can customise then.
You should create a BookForm class so that you can customise the fields. In your BookUpdate view, you only need to remove fields and add form_class = BookForm. Here I'm customising the widget for categorys and overriding the form field for pages:
def BookUpdate(UpdateView):
model = Book
form_class = BookForm
def BookForm(ModelForm):
pages = MyCustomPagesField()
class Meta:
model = Book
fields = '__all__'
widgets = {'categorys': MyCustomWidget()}
Note that you don't have to specify all fields, you can use "__all__" to have all fields or you can set exclude = [<list fields to exclude>] to just exclude a couple.
You don't have to code the fields yourself. But there is a small amount of work to do, as there isn't a method to override.
What you need to do is define a custom form. Since that will be a ModelForm, it will use the same logic to automatically create its fields based on the model. You can then override the definition of one of them.
class BookForm(forms.ModelForm):
categorys = forms.ModelMultipleChoiceField(custom_attributes_here...)
class Meta:
model = Book
fields = ["name", "pages", "categorys"]
And now tell your view to use that form:
class BookUpdate(UpdateView):
form_class = BookForm
I'm trying to have the DateField (created_at/updated_at) I have set up to be a readonly field that I can access through both the list_display and the form for adding in Django Admin. The way I have it set up it's showing as:
%09/%24/%2018
I know it's pulling from DATE_FORMAT in settings.py:
DATE_FORMAT = '%m/%d/%Y'
I just haven't figured out how to remove the % before it is displayed in Admin. Is there a way to clean this up? I've tried already to access the created_at/updated_at fields to write an algorithm to remove the extra characters, but can't seem to extract the values.
Here is my code if that helps. Thanks in advance!
admin.py
class BatchForm(forms.ModelForm):
class Meta:
model = Batch
fields = '__all__'
class BatchAdmin(admin.ModelAdmin):
form = BatchForm
readonly_fields = ('created_at', 'updated_at')
list_display = ('item', 'active', 'desc', 'quantity', 'created_at', 'updated_at')
models.py
class Batch(models.Model):
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
Based on the documentation, for the DATE_FORMAT, you do not need to put the %. So you would actually want to simply put DATE_FORMAT = 'm/d/Y'