I have a field named bar i need to write a validation function to validate this bar in django what conditions can i apply to this and how should my function be?
Note:Please dont share link of django validators
models.py
class Model:
bar = models.CharField('Bar', max_length=255, blank=True, null=True)
You can define a function that will validate the value and raise a ValidationError [Django-doc] in case the condition is not valid, so:
from django.core.exceptions import ValidationError
def validate_bar(value):
if not some-condition:
raise ValidationError('Bar should satisfy a certain condition', code='some_code')
then you add this function to the validators of that field
class MyModel(models.Model):
bar = models.CharField('Bar', max_length=255, blank=True, null=True, validators=[validate_bar])
note that validators will only run in ModelForms, ModelAdmins, ModelSerializers, etc. Not by the Django ORM for performance reasons.
def val(v):
if v is not None:
try:
if len(v) <= 255:
return True
except ValidationError:
return False
does this work ? with balnk = True ,null = True and max_length
Related
What is meant is, I want to save only one object with is_featured field true, if user tried to save another object with is_featured field true it needs to give a prompt, How can i accomplish that in django any idea?
class Event(BaseModel):
title = models.CharField(max_length=200)
time = models.TimeField()
date = models.DateField()
location = models.CharField(max_length=200)
location_url = models.URLField()
description = models.TextField()
is_featured = models.BooleanField(default=False)
image = VersatileImageField('Image', upload_to="web/events")
class Meta:
db_table = 'web_event'
verbose_name = ('Event')
verbose_name_plural = ('Event')
ordering = ('auto_id',)
def __str__(self):
return str(self.title)
You can add a check that if event is already created with is_featured true then you can return error else you can create instance
if Event.objects.filter(is_featured=True).exists():
return Response({"error":"Featured Event Already Exists"})
else:
Event.objects.create(**data)
```
I am giving this validation rule in my django forms, so when the field is none then it will rasie validation error but validationcoming ervey time , i meant when is none or not none i am getting the validationerror every time, How i solve this issue.
models.py
class Check(models.Model):
use_for_car = models.BooleanField(default=False)
Forms.py
class CheckForm(forms.ModelForm):
translated_names = TranslationField()
def clean(self):
cleaned_data = super(CheckForm, self).clean()
use_for_car = self.cleaned_data.get("use_for_car")
if use_for_car is None:
raise ValidationError("Use For Car NEED TO BE FILLED ")
return use_for_registrations
class Meta:
fields = "__all__"
model = models.Check
This is already the case, since you did not specify blank=True [Django-doc], this means that the form field is required, so this means that for the form field, required=True [Django-doc], and for a BooleanField form field [Django-doc], this means:
Since all Field subclasses have required=True by default, the validation condition here is important. If you want to include a boolean in your form that can be either True or False (e.g. a checked or unchecked checkbox), you must remember to pass in required=False when creating the BooleanField.
You thus can simply let Django do the work:
class CheckForm(forms.ModelForm):
translated_names = TranslationField()
# no clean override
class Meta:
model = models.Check
fields = '__all__'
I've a django Form with 2 choices (yes and no), on my "create page" i can render the select field to save the data and it works just fine, when i try to use on the "edit page" the value is not pre-selected with the current value, how can i make the current value selected on the select input field?
The form:
class MyForm(forms.ModelForm):
choose = forms.BooleanField(
required=False,
widget=forms.Select(
choices=[(1, 'Yes'), (0, 'No')],
attrs={'class': 'form-control'}
)
)
class Meta:
model = MyModel
When i call the view to edit:
class MyUpdateView(
LoginRequiredMixin,
SuccessMessageMixin,
UpdateView,
):
model = MyModel
form_class = MyForm
template_name = "my/template.html"
success_url = reverse_lazy('my-url')
success_message = 'Updated!'
def get_object(self, queryset=None):
data = super(MyUpdateView, self).get_object()
if not data.user == self.request.user:
raise Http404
# data.choose is False
return data
The HTML input will be always "1" (Yes) even tough the current value is "0" (No)
The HTML:
{{ form.choose }}
The Model:
class MyModel(models.Model):
choose = models.BooleanField(
default=False,
verbose_name='Cumulativo'
)
add this to your MyUpdateView:
initial = { 'choose': 1 }
You are defining the custom field 'choose' in the form, which does not refer to MyModel field 'choose'. that's why you are always getting the first value 'Y' as default or the first value 'Y' in the dropdown.
If you want to refer to your model object, you can simply use self keyword in the form
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['choose'].widget.attrs['class'] = 'form-control'
class Meta:
model = MyModel
fields = ('__all__')
I'm writing a web application (DRF + Vue.js) where frontend should have an ability to narrow down GET request results via different filters.
For example, I have a model like this:
class Human(models.Model):
first_name = models.CharField(_('first name'), max_length=50, null=True, blank=True)
last_name = models.CharField(_('last name'), max_length=50, null=True, blank=True)
birth_date = models.DateField(_('birth date'), blank=True, null=True)
city = models.ForeignKey('City', on_delete=models.SET_NULL, blank=True, null=True)
phone_number = models.ForeignKey('Contact' on_delete=models.SET_NULL, blank=True, null=True)
#property
def full_name(self):
# Last name + First name
return ' '.join(str(x) for x in (self.last_name, self.first_name) if x)
#property
def is_adult(self):
now = timezone.now()
if self.birth_date:
if now.year - self.birth_date.year - \
((now.month, now.day) < (self.birth_date.month, self.birth_date.day)) >= 18:
return True
return False
Now I have simple CRUD ViewSet where I can use a list of search_fields to search by all needed fields (in my case that's birth_date, city, phone_number and full_name/is_adult). But here next problems arise:
Using search_fields I can do a search only by all fields specified in the ViewSet's search_fields (frontend can't search only by city or other distinct fields if it wants to) - other way I'll need to create a separate ViewSet (and separate URL?) for every combination of fields to filter by. Terrific.
So it looks like the correct decision must be capable of filtering by several GET parameters at once. Ideally - with opportunity to choose exact/icontains/etc comparison method on each query.
That sounds like a work for django-filter but I'm not sure yet.
It's impossible to search/filter by full_name or is_adult because they are dynamic model properties, not usual fields.
So it looks like instead of using model properties I need to use separate QuerySets (Manager methods?) that will do the logic of fiddling with model fields and creating the filtered result.
But for now I didn't find a way to choose different QuerySets in a single ViewSet depending on GET parameters (or how to use search by these complex properties together with simple search from problem 1?).
And I have no understanding if it is possible to provide this kind of search by the same URL as a "simple" search - like site.com/api/people/?city=^New&full_name=John%20Doe (perfectly - with opportunity to document query parameters for OpenAPI schema / Swagger)
So maybe someone knows which is the most elegant way to provide a capability of such complex search with Django/DRF? In which direction should I look?
"full_name" alias needs to be part of your queryset.
You can achieve it by queryset annotation.
In your People view (api/people/ controller) you have to set your queryset to be:
from django.db.models.functions import Concat
from django.db.models import Value
queryset = Human.objects.annotate(fullname=Concat('first_name', Value(' '), 'last_name'))
Also, customize your "filter_backed" to act the way you need.
class PeopleFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
params_serializer = PeopleFilterSerializer(data=request.params)
params_serializer.is_valid(raise_exception=True)
valid_params = params_serializer.data
if full_name := valid_params.get("full_name")
queryset = queryset.filter(full_name__icountains=full_name)
# insert here all of other filters logic
return queryset
PeopleFilterSerializer is your custom params serializer,
You have to specify there all of your accepted params:
from rest_framework import serializers
class PeopleFilterSerializer(serializers.Serializer):
full_name = serializers.CharField() # set required=False if not required
city = serializer.CharField()
I'm trying to replace the standard queryset:
queryset: MyModel.objects.all()
on my:
def get_queryset(self, username=None):
if username is not None:
user = UserModel.objects.get(username=username)
queryset = MyModel.filter(author=user)
return queryset
else:
queryset = MyModel.objects.all()
return queryset
when I remove the "queryset", and leave only "get_queryset", an error appears:
AssertionError: base_name argument not specified, and could not automatically determine the name from the viewset, as it does not have a .queryset attribute.
All together looks so:
class MyModelView(viewsets.ModelViewSet):
permissions_classes = (permissions.IsAuthenticated,)
serializer_class = MyModelleSerializer
def get_queryset(self, username=None):
if username is not None:
user = UserModel.objects.get(username=username)
queryset = MyModel.filter(author=user)
return queryset
else:
queryset = MyModel.objects.all()
return queryset
lookup_field = 'username'
lookup_value_regex = '[a-zA-Z0-9$&(._)\-]+'
So how to override method correctly?
In the latest DRF, you need to explicitly set base_name in your viewset url if you don't have queryset defined.
So, something like this should do good:
router.register(r'my-model/', MyModelView, basename='MyModel')
See this: docs
You must add an argument called basename for the register method in the url.py file, Like the following code in url.py :
"In url.py"
...
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'my-model/' , MyModelView , basename='MyModel')
urlpattern=[...]
You need to set basename attribute in your url conf. Docs here
in my case i'm using rest framework Default router and changing view name to exact match with model name solved the problem.
View:
class DailyQuote(ModelViewSet):
queryset = DailyQuote.objects.all()
serializer_class = DailyQuoteSerializer
Model:
class DailyQuote(models.Model):
quote = models.TextField()
text = models.TextField()
so just change MyModelView to Model.