Django - Model field define unicode - python

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()

Related

Django forms.Form reflecting property field constraints

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.

Django dynamic filterset

So I want to create a django filters.FilterSet from django-filter module, but I want to dynamically add its attributes. For example, if I wanted to add SubName dynamically:
class UsersInfoFilter(filters.FilterSet):
Name=NumberFilter(lookup_type='gte')
def __new__(self):
self.SubName=NumberFilter(lookup_type='gte')
self.Meta.fields.append('SubName')
class Meta:
model = UsersInfo
fields = ['UserID', 'LanguageID', 'Name']
The problem is that FilterSet is a metaclass that immediately runs once the class has been figured out, so there is nowhere before that point that items can be dynamically added.
I've tried putting a function in as a parameter around filters.FilterSet class UsersInfo(AddObjects(filters.FilterSet)) which returns exactly what is passes, but I cannot reference UsersInfoFilter at that point since it still isn't finished being created.
I also tried making UsersInfoFilter its own base class, and then creating a class RealUsersInfoFilter(UsersInfoFilter, filters.FilterSet) as my actual filter, but then FilterSet just throws warnings about missing attributes named as fields.
There doesn't seem to be any kind of constructor function for classes in python. I'm assuming I have to do some kind of magic with metaclasses, but I've tried every combination I can think of and am at wits end.
You can't change Meta subclass from the __init__ method... there are 2 options to approach your issue...
First one - define "wide" filter on all of the model fields:
class UsersInfoFilter(filters.FilterSet):
class Meta:
model = UsersInfo
It will create default filters for all your model fields.
Second, define dynamic fields:
class UsersInfoFilter(filters.FilterSet):
name = NumberFilter(lookup_type='gte')
def __init__(self):
super(UsersInfoFilter, self).__init__()
base_filters['subname'] = NumberFilter(name='subname', lookup_type='gte')
class Meta:
model = UsersInfo
fields = ['user_id', 'language_id', 'name']
(I do not know if this is something you really want - because despite "dynamic" adding field - it should be declared as static - there are no logic here)
p.s.
why CamelCase on properties and fields? use proper pep-8.
To dynamically choose the fields in the FilterSet, I suggest to create a FilterSet factory like this:
def filterset_factory(model, fields):
meta = type(str('Meta'), (object,), {'model': model, 'fields': fields})
filterset = type(str('%sFilterSet' % model._meta.object_name),
(FilterSet,), {'Meta': meta})
return filterset
And then use it like:
DynamicFilterClass = filterset_factory(model=MyModel, fields=[...])
dynamic_filter = DynamicFilterClass(request.GET, queryset=instances)

Django model fields: reference to self on default keyword

I've been having problems to understand this and to come up with a way of doing a reference to self inside the default keyword of a model field:
Here is what I have:
class Bank(models.Model):
number = models.CharField(max_length=10)
class Account(models.Model):
bank = models.ForeignKey(Bank, related_name="accounts")
number = models.CharField(max_length=20)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User)
# This is the guy
special_code = models.CharField(max_length=30, default='%s-%s' % (self.number, self.bank.number))
So I'm trying to access self inside the class definition, which seems to not work out because python doesn't know where self is since its not an object yet.
I've tried different things like:
special_code = models.CharField(max_length=30, default='%s-%s' % (number, bank.number))
But in this case it doesn't recognize bank.number because bank its only a property with models.ForeignKey.
I've tried also using a method inside the Account class:
def bank_number(self):
return self.bank.number
and then:
special_code = models.CharField(max_length=30, default='%s-%s' % (number, bank_number()))
That was kinda dumb because it still needs self.
Is there a way I can do this?
I need it to store the number inside the database, so using a method like this wont help:
def special_number(self):
return '%s-%s' % (self.number, self.bank.number)
I don't think there's any way to access self in the default callable. There's a couple of other approaches to set your field's value:
If you don't want the user to be able to change the value, override the model's save method and set it there.
If the default is just a suggestion, and you do want to allow the user to change it, then override the model form's __init__ method, then you can access self.instance and change set the field's initial value.
Instead of specifying a default for the field you probably want to override the save() method and populate the field right before storing the object in the database. The save() method also has access to self. Here is an example in the docs for that:
https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-model-methods
As already answered, override the save() method of your model to assign a value to special_code. The default option of a field is not meant to depend on other fields of the model, so this will not work.
Also, have a look at the editable option, if you don't want the field to be edited.
special_code = models.CharField(max_length=30, editable=False)
Will prevent the field to be rendered in ModelForms you create from the model.

Why django admin sometimes uses some field of the model in the index, instead of __unicode__ method?

For some of my models, Django-admin, in the index of the model's objects, instead of displaying the output of the __unicode__ method like normally, it just displays one of the model's fields there.
This happens usually when there is something like:
class Meta:
ordering = ['name']
in my model, then the value of the field name is displayed (even though there is also a __unicode__ method), but not always, sometimes it just displays what __unicode__ says even if there is a class Meta ordering.
All my Unicode methods are quite normal, something like:
def __unicode__(self):
return u'[%s] %s' % (self.field, self.name, )
I am puzzled, why is a field used sometimes instead of __unicode__, and how can I make it use the __unicode__ method always? This is Django 1.3. Is this a bug in Django?
You can customise the fields displayed in the django admin using the list_display option in your ModelAdmin class.
The model __unicode__ method, and the Meta.ordering option do not have any affect on the fields displayed.
If you do not set list_display, then the default behaviour is to display a single column with the unicode string for each object.
If the unicode string is not displayed for your model, it sounds like you have set list_display. For example, to display the name field instead of the unicode string, you would do:
class MyModelAdmin(models.ModelAdmin):
list_display = ['name']
If you want to display the unicode string and other fields, simply include __unicode__ in list_display.
class MyModelAdmin(models.ModelAdmin):
list_display = [`__unicode__`, 'name']

Overwrite method add for ManyToMany related fields

Where should I overwrite method add() for ManyToMany related fields.
Seems like it is not manager 'objects' of my model. Because when we are adding new relation for ManyToMany fields we are not writing Model.objects.add().
So what I need it overwrite method add() of instance. How can I do it?
Edit:
So i know that there is ManyRelatedManager. One thing remain how can i overwrite it?
Sorry... not overwrite, but assign it in my Model by default.
http://docs.djangoproject.com/en/1.2/topics/db/managers/#custom-managers
You can create any number of managers for a Model.
You can subclass a ManyRelatedManager and assign it to the Model.
This example may be what you're looking for
# Then hook it into the Book model explicitly.
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
dahl_objects = DahlBookManager() # The Dahl-specific manager.
The objects manage is the default. Do not change this.
The dahl_objects is a customized manager. You can have any number of these.

Categories