How can I make a multi-line CharField in a model form in Django? I don't want to use Textarea, as I want the input to be with limited length. The question is about the field 'description'
This is my model:
class Resource(models.Model):
type = models.CharField(max_length=50)
name = models.CharField(max_length=150)
description = models.CharField(max_length=250, blank=True)
creationDate = models.DateTimeField(default=datetime.now, blank=True)
And this is my form:
class AddNewResourceForm(forms.ModelForm):
class Meta:
model = Resource
fields = ("name","type","description")
def __init__(self, *args, **kwargs):
super(AddNewResourceForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class' : 'new-res-name',
'placeholder' : 'max 150 characters'})
self.fields['type'].widget.attrs.update({'class' : 'new-res-type',
'placeholder' : 'max 50 characters'})
self.fields['description'].widget.attrs.update({'class' : 'new-res-
description', 'placeholder' : 'max 250 characters'})
I think that you should use the TextField, making sure to enforce the desired limit, which can be done in 2 steps:
1) Set a max_length attribute on the description field which will make sure that the limit is reflected on the client side.
From the docs:
If you specify a max_length attribute, it will be reflected in the
Textarea widget of the auto-generated form field. However it is not
enforced at the model or database level.
2) Apply MaxLengthValidator to your field to make sure you have a server-side limit validation as well, e.g.
from django.core.validators import MaxLengthValidator
class Resource(models.Model):
type = models.CharField(max_length=50)
name = models.CharField(max_length=150)
description = models.TextField(max_length=250, blank=True,
validators=[MaxLengthValidator(250)])
creationDate = models.DateTimeField(default=datetime.now, blank=True)
Related
I want to change one of the existing field names in the Django model. But, for the backward-compatibleness, we'd like not to override the existing field with the new one, keep both of them for now. Is there any way to have multiple fields referring to the same database object? i.e
Code right now:
class NetworkPackage:
name = models.CharField(unique=True, blank=False, null=False)
inbound = models.CharField(unique=True, blank=False, null=False)
...
I want to implement:
class NetworkPackage:
name = models.CharField(max_length=32, unique=True, blank=False, null=False)
inbound = models.CharField(max_length=128, unique=True, blank=True)
mobile = models.CharField(max_length=128, unique=True, blank=True)
...
Basically, 'inbound' and 'mobile' should refer to the same field and the request could be sent either with 'inbound' field or 'mobile'.
It's a bad idea having two fields within the same model that hold the same info, especially if you need to enforce uniqueness because
You'll need to maintain parity for both fields, so that means if the request was setting inbound, then you'll also have to set mobile.
The database now has to index both inbound and mobile due to uniqueness.
What you can do is utilize python properties as properties are perfect solutions for cases where you have legacy attributes:
class NetworkPackage(models.Model):
name = models.CharField(unique=True, blank=False, null=False)
inbound = models.CharField(unique=True, blank=False, null=False)
...
#property
def mobile(self):
return self.inbound
#mobile.setter
def mobile(self, value):
self.inbound = value
Then in your serializer, you need to:
Add mobile as an additional field sourcing to inbound.
Override the required and allow_blank arguments on both fields since the serializer can allow either fields...
BUT, you'll then need to write a custom validation method to ensure at least 1 of the 2 fields are populated with a value.
Also prioritize the inbound value over the mobile value if both fields are populated.
class NetworkPackageSerializer(serializers.ModelSerializer):
inbound = serializers.CharField(required=False, allow_blank=True)
mobile = serializers.CharField(source="inbound", required=False, allow_blank=True)
class Meta:
model = NetworkPackage
fields = ("inbound", "mobile", ...)
def validate(self, data):
"""Validate `inbound` and/or `mobile`."""
if not data["inbound"] and not data["mobile"]:
raise serializers.ValidationError("missing value on inbound or mobile")
if data["inbound"]:
del data["mobile"]
else:
del data["inbound"]
return data
Not sure why do you make duplicate fields, but I have some suggestions for you.
1. Custom property
class NetworkPackage:
name = models.CharField(unique=True, blank=False, null=False)
inbound = models.CharField(unique=True, blank=False, null=False)
#poperty
def mobile(self):
return self.inbound
2. Serializer
class NetworkPackageSerializer(serializers.Serializer):
mobile = serializers.CharField(source='inbound')
class Meta:
model = NetworkPackage
fields = (
'id',
'inbound',
'mobile',
'name',
...
)
I've got a ModelForm where I can display either a foreignkey field which comes as a dropdown list ({{ form.auto_part }}) or the value or the ID of that foreignkey field which comes as a number ({{ form.auto_part.value }}). But I want to show the __str__ value of the foreignkey field. How can I do that?
forms.py
class AddCostPriceForm(forms.ModelForm):
class Meta:
model = Product
fields = ['auto_part', 'cost_price']
models.py
class Product(Timestamped):
product_list = models.ForeignKey(List)
auto_part = models.ForeignKey(AutoPart)
quantity = models.SmallIntegerField()
unit = models.CharField(max_length=20, default='pcs')
cost_price = models.IntegerField(blank=True, null=True)
class AutoPart(Timestamped):
brand = models.ForeignKey(Brand)
auto_type = models.ForeignKey(AutoType)
part_no = models.CharField(max_length=50)
description = models.CharField(max_length=255)
def __str__(self):
return "{brand} {auto_type} - {part_no}".format(brand=self.brand, auto_type=self.auto_type, part_no=self.part_no)
Using ModelChoiceField should allow you to do this, it is the default behavior. You can configure the labels.
See https://docs.djangoproject.com/en/1.10/ref/forms/fields/#modelchoicefield
Example:
class AddCostPriceForm(forms.ModelForm):
auto_part = forms.ModelChoiceField(queryset=AutoPart.objects.all())
class Meta:
model = Product
fields = ['auto_part', 'cost_price']
I've set the default values for fields in embedded document but when I try to post data it doesn't accept None or Blank values.
Here is what my code looks like-
models.py
class MetaData(EmbeddedDocument):
adcode = StringField(max_length=50, default="", blank=True, Null=True)
additional_html_below_header = StringField(max_length=50, default="")
adhoc_plus_disable_pacing = BooleanField(default=False)
adhoc_plus_has_priority = BooleanField(default=False)
adhoc_server = StringField(max_length=50, default="")
class LandingPage(Document):
type = StringField(max_length=50, default="")
meta_clean_URL_tag = StringField(max_length=50, default="")
meta_name = StringField(max_length=50, default="")
created_time = DateTimeField(default=datetime.datetime.now)
new = BooleanField(default=False)
meta_data = EmbeddedDocumentField(MetaData)
serializers.py
class MetaDataSerializer(serializers.EmbeddedDocumentSerializer):
class Meta:
model = MetaData
class LandingPageSerializer(serializers.DocumentSerializer):
meta_data = MetaDataSerializer()
class Meta:
model = LandingPage
Is there anything wrong I'm doing here?
class MetaDataSerializer(serializers.EmbeddedDocumentSerializer):
adcode = serializers.CharField(allow_blank=True,allow_null=True)
adhoc_server = serializes.CharField(allow_blank=True,allow_null=True)
additional_html_below_header = serializers.CharField(allow_blank=True,allow_null=True)
class Meta:
model = MetaData
DRF-mongoengine or for that matter DRF does not allow null and blank values for strings. They need to be explicitly mentioned. The bounds imposed on models do not hold inside serializers.
The above mentioned change should help you maintain the validations as required by you.
Well, i have this model:
class Application(models.Model):
name = models.CharField("nom", unique=True, max_length=255)
sonarQube_URL = models.CharField("Url SonarQube", max_length=255,
blank=True, null=True)
def __unicode__(self):
return self.name
and this serializer:
class ApplicationSerializer(serializers.ModelSerializer):
nom = serializers.CharField(source='name', required=True, allow_blank=True)
url_sonarqube = serializers.CharField(source='sonarQube_URL', required=False)
flows = FlowSerializer(many=True, read_only=True)
class Meta:
model = Application
fields = ('id', 'nom', 'url_sonarqube', 'flows')
My view is simple:
class ApplicationViewSet(viewsets.ModelViewSet):
queryset = Application.objects.all()
serializer_class = ApplicationSerializer
I use this model of permissions in my settings.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.DjangoModelPermissions',),
'PAGE_SIZE': 10,
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework.renderers.MultiPartRenderer',
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.TemplateHTMLRenderer'
)
}
When I use POST operation on DRF interface (in HTML Form), I filled all the fields of the application Item. As you can see, "required" parameter of "nom" is set to True. And, this is the problem: even if 'nom' is not empty, DRF says "this field is required!". So, I can't POST a new application item.
I don't understand why it not works... Where is the mistake?
The error you got is related to the Django Model(Application). It was failing in model level not in serializer level. Add null=True and blank=True to name field in Application model.
Try to keep your code in English, you can use Django's i18n to translate stuff, also use blank and null for your name field:
class Application(models.Model):
name = models.CharField(_('name'), max_length=255, blank=True, null=True)
sonarqube_url = models.CharField(_('SonarQube URL'), max_length=255, blank=True, null=True)
def __unicode__(self):
return self.name
class ApplicationSerializer(serializers.ModelSerializer):
class Meta:
model = Application
fields = ('id', 'name', 'sonarqube_url')
Let's save flows for later as you don't even have a model relation for them.
I have this model:
class SearchPreference(models.Model):
"""Saves the preferred location and school_type of the User
"""
user = models.OneToOneField(User, related_name='search_preference')
location = models.ForeignKey(Location, null=True)
school_type = models.ForeignKey(SchoolType, null=True)
class Meta:
app_label = 'grants'
and this form:
class SearchPreferenceForm(forms.ModelForm):
location = forms.ChoiceField(queryset=Location.objects.all(),
to_field_name='slug',
required=False)
school_type = forms.ChoiceField(queryset=SchoolType.objects.all(),
to_field_name='slug',
required=False)
class Meta:
model = SearchPreference
fields = ('location', 'school_type')
I am trying to use the form to do validation of POST data, I am not displaying it in a template.
The problem is, the POST data can include a value which isn't in the Location or SchoolType table, so the form doesn't validate. The value is 'all', signifying 'all locations' or 'all school types', and I really want this to be saved as a SearchPreference with no location, i.e. location = null.
I could change 'all' to an empty value and that might work but then validation/logic has moved out of the form.
I thought I could use empty_value = 'all' but this doesn't work on a modelChoiceField.
Is there any way of doing this?
Your model needs blank=True as well and null=True
location = models.ForeignKey(Location, blank=True, null=True)
school_type = models.ForeignKey(SchoolType, blank=True, null=True)
This post talks about blank and null.
This worked in the end:
class SearchPreferenceForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SearchPreferenceForm, self).__init__(*args, **kwargs)
self.fields['location'].empty_values.append('all')
self.fields['school_type'].empty_values.append('all')