Django modelform NOT required field - django

I have a form like this:
class My_Form(ModelForm):
class Meta:
model = My_Class
fields = ('first_name', 'last_name' , 'address')
How can I set the address field as optional?

class My_Form(forms.ModelForm):
class Meta:
model = My_Class
fields = ('first_name', 'last_name' , 'address')
def __init__(self, *args, **kwargs):
super(My_Form, self).__init__(*args, **kwargs)
self.fields['address'].required = False

Guess your model is like this:
class My_Class(models.Model):
address = models.CharField()
Your form for Django version < 1.8:
class My_Form(ModelForm):
address = forms.CharField(required=False)
class Meta:
model = My_Class
fields = ('first_name', 'last_name' , 'address')
Your form for Django version > 1.8:
class My_Form(ModelForm):
address = forms.CharField(blank=True)
class Meta:
model = My_Class
fields = ('first_name', 'last_name' , 'address')

field = models.CharField(max_length=9, default='', blank=True)
Just add blank=True in your model field and it won't be required when you're using modelforms.
"If the model field has blank=True, then required is set to False on the form field. Otherwise, required=True."
source:
https://docs.djangoproject.com/en/4.1/topics/forms/modelforms/#field-types
[Edit]: Change django doc link from 3.1 to 4.1

You would have to add:
address = forms.CharField(required=False)

Solution: use both blank=True, null=True.
my_field = models.PositiveIntegerField(blank=True, null=True)
Explanation:
If you use null=True
my_field = models.PositiveIntegerField(null=True)
then my_field is required, with * next to it in the form and you can't submit the empty value.
If you use blank=True
my_field = models.PositiveIntegerField(blank=True)
then my_field is not required, there won't be a * next to it in the form and you can't submit the value. But it will get null field not allowed.
Note: marking as not required and allowing null fields are two different things.
Pro Tip: Read the error more carefully than documentation.

#Anentropic's solution from the comment on #Atma's answer worked for me. And I think it's the best one too.
His comment:
null=True, blank=True will cause the ModelForm field to be required=False
I just set it on my ManyToMany field in my UserProfile class and it worked flawlessly.
My UserProfile class now looks like this (notice the friends field):
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
friends = models.ManyToManyField('self', null=True, blank=True)
I also think that this is the most beautiful solution since you do the same thing, put null and blank to True, weather you have a simple char field or, like I have, ManyToMany field.

The above answers are correct; nevertheless due note that setting null=True on a ManyToManyField has no effect at the database level and will raise the following warning when migrating:
(fields.W340) null has no effect on ManyToManyField.
A good answer to this is explained in this other thread.

Related

In Django ModelSerializer unable to mark a field required as false

I am trying to make a field investor required as False in Django Restframework's ModelSerializer.
class WatchListSerializer(serializers.ModelSerializer):
class Meta:
model = WatchList
fields = ['id', 'investor', 'property']
extra_kwargs = {
'investor' : {
'required' : False
}
}
However, both the fields are defined as ForeignKeys in the model. As you can see in above implementation I am trying to override the default implementation of field investor using extra_kwargs. Unfortunately, it still asking to provide the value for investor.
Here is the model Watchlist -
class WatchList(BaseModel):
investor = models.ForeignKey(User, on_delete=models.PROTECT, blank=False, null=True)
property = models.ForeignKey(Properties, on_delete=models.PROTECT, blank=False, null=True)
class Meta:
unique_together = (('investor', 'property',))
def __str__(self):
return f'Watch List Object {self.id}:'
With the blank=… parameter [Django-doc], you specify whether the field is required in a ModelForm, ModelAdmin, ModelSerializer and other parts of the code that process data into a model object.
You thus can disable this with:
class WatchList(BaseModel):
# …
property = models.ForeignKey(
Properties,
on_delete=models.PROTECT,
blank=True,
null=True
)

Pass request user to modelform in Django

I have a model where is save one of the groups of the user in my model.
Because user can be member of different groups i need to update the Selection field in my Form depending on the request.user.groups.all() queryset.
I tried to pass the initial variable to my form but this was ignored.
Any hint how to deal with this problem?
EDIT:
My view:
form = CoronaEventModelForm(request.POST or None, initial={'group': request.user.groups.all()})
my model:
user = models.ForeignKey(curr_User, default=1, null=True, on_delete=models.SET_DEFAULT, related_name='group')
group = models.ForeignKey(Group, on_delete=models.CASCADE)
my form:
class CoronaEventForm(forms.Form):
user = forms.CharField()
group = forms.CharField()
title = forms.CharField()
description = forms.CharField()
slug = forms.SlugField()
event_date = forms.DateField()
class CoronaEventModelForm(forms.ModelForm):
class Meta:
model = CoronaEvent
fields = ['group', 'title', 'description', 'slug', 'event_date']
it works with normal text fields but not with the group field.
solved it by adding a init function to my form and passing the object during instantiation of the form.

Serialize many-to-many relation with intermediate model in Django Rest

I tried to check another topics, but didn't found a solution...
I have a many-to-many model, that have intermediate model with another field additional_field inside.
class BoardField(models.Model):
title = models.CharField(max_length=500, default='')
class Article(models.Model):
title = models.CharField(max_length=500, default='')
fields = models.ManyToManyField(BoardField, through='ArticleField', through_fields=('article', 'board_field'))
class ArticleField(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='task')
board_field = models.ForeignKey(BoardField, on_delete=models.CASCADE)
additional_field = models.CharField(max_length=200, blank=True, null=True)
I want serialize Article with structure:
[
"title":"Title",
"fields":[
{
"board_field": {
"title":"Title"
},
"additional_field":"Additional info"
}
]
]
So, I wrote serializer:
class BoardFieldSrl(serializers.ModelSerializer):
class Meta:
model = BoardField
fields = (
'title',
)
class ArticleFieldSrl(serializers.ModelSerializer):
board_field = BoardFieldSrl()
class Meta:
model = ArticleField
fields = (
'board_field',
'additional_field',
)
class ArticleListSrl(serializers.ModelSerializer):
fields = ArticleFieldSrl(many=True)
class Meta:
model = Article
fields = (
'title',
'fields',
)
But I always got an error:
Got AttributeError when attempting to get a value for field `board_field` on serializer `ArticleFieldSrl`.
The serializer field might be named incorrectly and not match any attribute or key on the `BoardField` instance.
Original exception text was: 'BoardField' object has no attribute 'board_field'.
I made another several examples, but they doesn't gave my result, that I need... My maximum - I got BoardField with levels, but without intermediate model...
Can you help me with serializer, that return structure, that I mentioned above? It must include intermediate model ArticleField and nested BoardField.
Try fields = ArticleFieldSrl(source='articlefield_set', many=True)
You didn't specified a related_name at M2M field so the default naming is applied which is 'Intermediate model name'_set and if you want to use the fields on M2M relation you have to tell the serializer where to look for.
EDIT:
Camel removed from articlefield_set, model name is always converted to lower case

how could I use Model._meta.get.fields() to read all fields in my model

I want to display some fields and I know I could do it by as follows:
In models.py:
class Person(models.Model):
person_id = models.UUIDField(default=uuid.uuid4, primary_key = True)
date_registered = models.DateField(auto_now_add=True)
first_name = models.CharField(max_length = 50)
last_name = models.CharField(max_length = 100)
date_of_birth = models.DateField()
email = models.EmailField()
In my admin.py:
class AuthorAdmin(admin.ModelAdmin):
list_display = ('last_name', 'first_name', 'last_name', 'date_of_birth' )
fields = [('first_name' ,'last_name'), 'date_of_birth']
pass
admin.site.register(Author, AuthorAdmin)
Unfortunately, my table has many fields and I do not want to write them individually. I found that ._meta.get.fields() could read all fields. However, I can not get it correct. Using it as follows in my admin.py:
admin.site.register(PersonLogin)
admin.site.register(LoginHistory)
class PersonAdmin(admin.ModelAdmin):
list_display = [field.name for field in Person._meta.get_fields() if not field.primary_key]
readonly_fields = ('person_id',)
pass
admin.site.register(Person, PersonAdmin)
it says that _meta is undefined variable.
Latest Django in use.
Thank you in advance.
PG
_meta being unavailable means Django didn't set up its environment yet. You can set it up by adding:
import django
django.setup()
at the top, but this is somewhat dirty. See if you can get away with moving the list comprehension to the __init__:
class PersonAdmin(admin.ModelAdmin):
def __init__(self, model, admin_site):
self.list_display = [
field.name for field in Person._meta.get_fields()
if not field.primary_key
]
super().__init__(model, admin_site)
EDIT: To accommodate the Eclipse introspection errors you can use getattr to explicitly tell it that it's a runtime thing:
self.list_display = [
field.name for field in getattr(Person, '_meta').get_fields()
if not field.primary_key
]

Django admin: list_display/search_fields foreign key of a foreign key in admin view

I have a question for django programmer that should be quite easy but at the moment I cannot figure out how to solve.
I have these three models (I simplify as much as I can):
class Nations(models.Model):
label = models.CharField(max_length=200)
iso2 = models.CharField(max_length=2, unique=True)
class Cities(models.Model):
label = models.CharField(max_length=200, null=True)
country_code = models.ForeignKey(Nations, to_field='iso2', on_delete=models.SET_NULL, null=True, verbose_name='Nation')
class Person(models.Model):
username = models.CharField(max_length=200, blank=False)
city = models.ForeignKey(Cities, on_delete=models.SET_NULL, null=True, blank=True)
As you can see, Person model is just connected with Cities model. What I need to do is to set PersonAdmin class in order to add in the admin view a column showing Nations.label value and make it searchable. In the example below I called this field city__country_code__label, just to make you figure out what I mean (but of course it doesn't work because there is no country_code object in Person model).
class PersonAdmin(admin.ModelAdmin):
list_display = ('id', 'username', 'city', 'city__country_code__label')
ordering = ('username',)
raw_id_fields = ('city',)
search_fields = ['username', 'city__label', 'city__country_code__label']
[...]
how can I ask Django to do this?
Thanx in advance!
Add a method to your model admin that takes a person obj and returns the country label. Then add the method to list_display.
class PersonAdmin(admin.ModelAdmin):
def country_label(self, obj):
return obj.city.country_code.label
list_display = ('id', 'username', 'city', 'country_label')
list_select_related = ['city__country_code']
ordering = ('username',)
raw_id_fields = ('city',)
search_fields = ['username', 'city__label', 'city__country_code__label']
See the list_display docs for more info.
Note I have used list_select_related to reduce the number of SQL queries.