I'm implementing a Django Form witch should contain the field 'fieldA' from modelA:
class ModelA(models.Model):
fieldA = models.CharField(max_length=8)
...
My question is: Is there a way to have Django form, which will automatically handle validation of fieldA (check the max_length)? I know I Could use form.ModelFormclass referring to ModelA, but then the form would reflect all the fields of the ModelA. I would like to use simple forms.Form.
I'm looking for a solution like:
class formX(forms.Form):
fieldA = forms.CharField(**modelA.fieldA.constraints)
fieldB = ... some other fields not related to ModelA ...
.... even more fields
Maybe this question is an XY problem, but let me try...
Direct question: get field constraints from existing model
from django import forms
from django.db import models
class Foo(models.Model):
x = models.CharField(max_length=30)
y = models.IntegerField(null=True)
class FooForm(forms.Form):
foo_x = forms.CharField(max_length=Foo._meta.get_field('x').max_length)
You can access the field directly in two ways:
ModelClass.field_name.field (kind of hack, ModelClass.field_name is a django.db.models.query_utils.DeferredAttribute)
ModelClass._meta.get_field('field_name') (better way, described somewhere in docs)
However, this way you have to a) update form if field constraints are added or b) specify all attributes in advance (max_length, min_length, verbose_name, blank, etc.), making declaration of FooForm.foo_x too verbose.
Alternatives
Fields subset
First of all, if you need a subset of Foo fields, use ModelForm and specify them:
class FooForm(forms.ModelForm):
class Meta:
fields = ('x',)
Now you have a form with only x field.
Add some fields
If you want to add fields to this form (that are not related to other model), do it:
class FooForm(forms.ModelForm):
another_field = forms.IntegerField()
class Meta:
fields = ('x',)
def clean_another_field(self):
data = self.cleaned_data['another_field']
if data != 42:
raise ValidationError('Not an answer!') # i18n should be here
return data
Also you can override clean and save methods for another goals, documentation explains that nicely.
Mix fields from different models
If you need fields of two different models to be present in one form, you don't. You need two separate forms in this case, plus some inter-validation logic outside of this forms maybe (as a view method, for example, or as another class that is not a form). Maybe what you need is inline formset, it doesn't represent two mixed forms, but at least has some inter-model communication.
I found a way how to achieve a validation of form Field reflecting constrains from model Field.
class Foo(models.Model):
x = models.CharField(max_length=30)
y = models.IntegerField(null=True)
class FooForm(forms.Form):
foo_x = forms.CharField(validators=Foo._meta.get_field('x').validators)
Like this, the form will respect the max_length validator of attribute x or any other validator defined.
Related
My main model class looks like this:
class Article(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
authors = models.TextField(max_length=200)
year = models.IntegerField()
form = models.TextField(choices=FORMS)
language = models.TextField(choices=LANGUAGES)
region = models.TextField(choices=REGIONS)
tags = models.TextField()
def __str__(self):
return self.title
And, for my api to send backend data to front end, I have a serializers class that looks like this:
class ArticleSerializers(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content', 'authors', 'year'...)
Clearly, the current way of writing fields as a bunch of hard-coded strings is very clumsy and prone to mistake (since I might change the fields in Article class but forget to update the fields in the serializer).
So my question is, how can I improve the style of fields?
Also, another side question, what is this type of coding rule / principle called, when you try to make one part of the code to be dependent on the other, so you need to change one part, instead of always having to remember changing both parts?
Thanks!
The documentation on specifying which fields to include [drf-doc] says:
You can also set the fields attribute to the special value '__all__' to indicate that all fields in the model should be used.
We thus can include all fields with:
class ArticleSerializers(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
If you want to exclude certain fields, you can work with an exclude option:
You can set the exclude attribute to a list of fields to be excluded from the serializer.
So if you want to exclude the tags for example, you can work with:
class ArticleSerializers(serializers.ModelSerializer):
class Meta:
model = Article
exclude = ['tags']
Clearly, the current way of writing fields as a bunch of hard-coded strings is very clumsy and prone to mistake
Normally the metaclass logic will raise an exception if it can not find that field when it constructs the class, so when you start the application. This thus means that typos will not result in any problems. The only thing that could go wrong is specifying another field that exists for the given model.
I have to models
class Parent(object):
text_field = models.TextField()
boolean_field = models.BooleanField()
class Child(Parent):
another_text_field = models.TextField()
With the following ModelAdmin
class ChildAdmin(admin.ModelAdmin):
pass
admin.site.register(Child, ChildAdmin)
I currently see all fields in the admin page, i.e. text_field, boolean_field, and another_text_field.
Question: How can I get a parent select field and exclude text_field and boolean_field (for latter I guess I can use exclude).
Current Solution: I add a Form and use its clean method to set the parent field. text_field and boolean_field can be excluded by addind it to the ModelAdmin's excluded variable.
simply overwrite fields
class Child(Parent):
another_text_field = models.TextField()
text_field = None
boolean_field = None
if you want to use inheritance in django models use abstract models please.
I am not sure if it is really necessary to use model inheritance. if not, you may consider using OneToOneField without model inheritance.
Example using OneToOneField:
models.py
class Parent(models.Model):
text_field = models.TextField()
boolean_field = models.BooleanField()
class Child(models.Model):
parent = models.OneToOneField(Parent,
on_delete=models.CASCADE,
primary_key=True)
child_field = models.TextField()
admin.py
#admin.register(Parent)
class ParentAdmin(admin.ModelAdmin):
pass
doing so you can see a drop down menu for picking Parent instance at child admin page. but meanwhile, you lose one 'benefit' of using inheritance, which is the availability of Parent field in Child
as mentioned in the docs,
All of the fields of Place will also be available in Restaurant,
although the data will reside in a different database table.
but there is a easy fix for that, just use something like Child.objects.filter(parent__text_field="something"). Query performance should be the same (I guess) since implementation in db are basically the same for these two approaches (both use separated table) (please correct if I am wrong)
Apart from from this and admin display behavior, I am not sure how these two approaches (your approach and this answer) are differed.
As we can define the __unicode__ representation of a model,
Is there a way to define the same for a model field ? (or is it a bad idea ?)
You can add your own methods. For example, when you use choices for a field, django automatically creates a get_FIELD_display method for the FIELD.
class Something(models.Model):
name = models.CharField(max_length=25)
def get_name_uppercase(self):
return self.name.upper()
then when you have
something = Something.get(id=1)
you can access it via
something.get_name_uppercase()
Expanding from this question: Can "list_display" in a Django ModelAdmin display attributes of ForeignKey fields?, could it be possible to do something like this:
class MyModelInline(admin.StackedInline):
model = MyModel
extra = 1
fields = ('my_field',)
def my_field(self, obj):
return obj.one_to_one_link.my_field
If something like this were possible, it would solve most of my current Django problems, but the code above does not work: Django (rightly) complains that my_field is not present in the form.
You can do that, but you must also add my_field to your MyModelInline class's readonly_fields attribute.
fields = ('my_field',)
readonly_fields = ('my_field',)
From the docs:
The fields option, unlike list_display, may only contain names of fields on the model or the form specified by form. It may contain callables only if they are listed in readonly_fields.
If you need the field to be editable, you should be able to do that with a custom form but it takes more work to process it.
Can someone please explain why is meta class used in the following example.
Ex:
Class Employee (models.Model):
name = models.ForeignKey(name)
Gender = models.IntegerField()
class Meta:
ordering = ["Gender"]
Thanks.
Django models use the Meta class to contain extra information about the model that would not necessarily be appropriate to contain within the model class itself. Note that this is not the same as Python's metaclass; that is a completely different topic.
In this case it ordering or sorting the queries to this model by field "Gender"
Because author/programmer wants to sort results by value of Gender field.
In this case it defines the default field for ordering if you don't provide ORDER_BY in your query.
It is explained in Django Documentation for Models
https://docs.djangoproject.com/en/dev/topics/db/models/
Give your model metadata by using an inner class Meta, like:
Class Employee (models.Model):
....
class Meta:
ordering = ["attribute-X"]
Another useful option can be used in class Meta is verbose_name.