I want to display first name and last name. To achieve that, I have used __str__() method. But it is not working.
class OnlineUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return f"{self.user.first_name} {self.user.last_name}"
Instead it display, user ID.
In admin.py,
class OnlineUsersAdmin(admin.ModelAdmin):
# a list of displayed columns name.
list_display=['user']
admin.site.register(OnlineUsers, OnlineUsersAdmin)
Where I'm doing wrong? How to get the format I want?
Version:
Django==2.0.1
Debug:
user_info=OnlineUsers.objects.get_or_create(user=self.user)
print(user_info.__str__())
Output:
((<OnlineUsers: FIRST_NAME LAST_NAME >, False))
You should use __str__ instead of user in list_display:
list_display=['__str__']
Otherwise you tell django to show user field. And since User model doen't have overrided __str__ method you see user's id.
Also you can just remove list_display attribute. In this case __str__ will be used by default.
The list_display--(Django doc) support callable methods too. So, define a user(...) method on Model admin as,
class OnlineUsersAdmin(admin.ModelAdmin):
# a list of displayed columns name.
list_display = ['user']
def user(self, instance):
return instance.__str__()
Here, inside return you can return only str + str, not str + int. So, you have to convert every int to str
from django.db import models
# Create your models here.
class Fabonacci(models.Model):
numstr = models.IntegerField()
terms = models.CharField(max_length=500)
def __str__(self):
return "The first " + str(self.numstr) + " terms in fibonacci series : " + self.terms
Related
I am try to refer 'spot_price' of model 'Spot' in model 'Basis' in django model layer, How can I manage this?
I have designed view.py to automaticaly render the templates. so I am not able to modifty any view.py to choose data like 'models.B.objects.get().field'.
and more, str is set to indicate the date, so, in the django backstage admin, the 'spot' field display would be 'date' formate, how would be change to 'spot_price'?
model Spot
class Spot(models.Model):
date = models.DateField(primary_key=True)
spot_price = models.FloatField(blank=True, null=True)
def __str__(self):
return str(self.date) if self.date else ''
need to refer the model Spot'spot_price by date, cause date is unique but spot_price is not
class Basis(models.Model):
date = models.DateField(primary_key=True)
major_future_contract_close_price = models.FloatField(blank=True)
spot = models.OneToOneField(Spot, on_delete=models.CASCADE)
basis = models.FloatField(default=calculate_basis)
def __str__(self):
return str(self.date) if self.date else ''
def calculate_basis(self):
return abs(self.major_future_contract_close_price -
self.spot.spot_price)
I expect the Basis.query.data would to like 'date: 2019-04-25, major_future_contract_close_price: 100.0, spot: 96.5, basis: 3.5'
You can't use class method as default, because it requires self, which is not existing when you are still creating the object.
If you need to have it stored in field (database), override default save() method or use signals to modify the basis field once your object is created. Also note that you have to recalculate basis every time close_price or spot_price changes, as the value is just written in database.
Probably better solution would be to use #property so for anyone that will be using you model it will look like a field, but it will dynamically calculate value based on current data.
For example, I'm overriding save() to calculate the basis field. I set it as editable=False, which means it won't appear in forms by default (and you will not be able to see it in admin!). You can safely remove that part if you want to just look at the values.
Additionally I add basis_as_property property.
class Basis(models.Model):
date = models.DateField(primary_key=True)
major_future_contract_close_price = models.FloatField(blank=True)
spot = models.OneToOneField(Spot, on_delete=models.CASCADE)
basis = models.FloatField(editable=False, blank=True)
#property
def basis_as_property(self):
return '%s' % (self.calculate_basis())
def __str__(self):
return str(self.date) if self.date else ''
def save(self, *args, **kwargs):
if not self.basis:
self.basis = self.calculate_basis()
super(Basis, self).save(*args, **kwargs)
def calculate_basis(self):
return abs(self.major_future_contract_close_price - self.spot.spot_price)
As for Spot str repr, I don't think it's possible to change it based on where it is referenced. If you want to use spot_price, you can just use: return str(self.spot_price) if self.spot_price else str(self.date)
I want to do a query on the django User table like this:
u = User.objects.filter(member__in = member_list)
where:
class Member(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dob = models.DateField('Date of Birth', blank=True, null=True)
and member_list is a list of eligible members.
The query works fine but the problem is I do not actually know the model member is called member. It could be called anything.
I store the name of the model I want in a model called Category. I have a link to the name of the model through content_type.Category is defined as:
class Category(models.Model):
name = models.CharField('Category', max_length=30)
content_type = models.ForeignKey(ContentType)
filter_condition = JSONField(default="{}", help_text=_(u"Django ORM compatible lookup kwargs which are used to get the list of objects."))
user_link = models.CharField(_(u"Link to User table"), max_length=64, help_text=_(u"Name of the model field which links to the User table. 'No-link' means this is the User table."), default="No-link")
def clean (self):
if self.user_link == "No-link":
if self.content_type.app_label == "auth" and self.content_type.model == "user":
pass
else:
raise ValidationError(
_("Must specify the field that links to the user table.")
)
else:
if not hasattr(apps.get_model(self.content_type.app_label, self.content_type.model), self.user_link):
raise ValidationError(
_("Must specify the field that links to the user table.")
)
def __unicode__(self):
return self.name
def _get_user_filter (self):
return str(self.content_type.app_label)+'.'+str(self.content_type.model)+'.'+str(self.user_link)+'__in'
def _get_filter(self):
# simplejson likes to put unicode objects as dictionary keys
# but keyword arguments must be str type
fc = {}
for k,v in self.filter_condition.iteritems():
fc.update({str(k): v})
return fc
def object_list(self):
return self.content_type.model_class()._default_manager.filter(**self._get_filter())
def object_count(self):
return self.object_list().count()
class Meta:
verbose_name = _("Category")
verbose_name_plural = _("Categories")
ordering = ('name',)
So I can retrieve the name of the model that links to User but I then need to convert it into a class which I can include in a query.
I can create an object x = category.content_type.model_class() which gives me <class 'cltc.models.Member'> but when I them perform a query s = User.objects.filter(x = c.category.object_list()) I get the error Cannot resolve keyword 'x' into field.
Any thoughts most welcome.
The left hand side of the filter argument is a keyword, not a python object, so x is treated as 'x', and Django expects a field called x.
To get around this, you can ensure that x is a string, and then use the python **kwarg syntax:
s = User.objects.filter(**{x: c.category.object_list()})
Thanks to https://stackoverflow.com/a/4720109/823020 for this.
I want to generate an unique string in my django1.6 application. For that I want to concatenate the primary key (autofield) with the string. My code is
class Complaints(models.Model):
gid = models.AutoField(primary_key=True)
complaint_no = models.CharField(max_length=50)
status = models.IntegerField(default=0,blank=False,null=False)
def __str__(self):
return ('%s %s' % (self.gid, self.complaint_no))
def save(self, force_insert=False, force_update=False):
self.complaint_no = '%s%d' % (self.complaint_no,self.gid)
super(Complaints, self).save(force_insert, force_update)
class Meta:
db_table = 'complaints'
verbose_name = "complaints"
But I got the error message as
TypeError at /callcentre/register/
%d format: a number is required, not NoneType
Please help me to solve this error!
Create field id as charfield e.g.
string_id = models.CharField(max_length=100, default='file')
Make a function that make string id when the model is saved.
def save(self):
new_id = self.id
self.string_id = str(new_id) + '_dot'
super(YourModelName, self).save()
You need to call super() first.
As you can read in the documentation:
There’s no way to tell what the value of an ID will be before you call save(), because that value is calculated by your database, not by Django.
When you call super().save(), the database engine calculates the id (or gid in your case, but please reconsider using the provided id) and thus allows you to use it. Before that it is None.
You may check this topic as well.
As you can guess from the title, I'm not exactly sure how to describe what I want. Please take a look at the following classes:
from django.db import models
from django.contrib.auth.models import User as Auth_User
class User(Auth_User):
Portfolio = models.ManyToManyField('PortfolioItem', through='SkillTag')
Age = models.IntegerField(blank=False)
#property
def full_name(self):
return self.first_name + ' ' + self.last_name
def __unicode__(self):
return self.full_name
class PortfolioItem(models.Model):
Title = models.CharField(max_length=200, blank=False)
class SkillTag(models.Model):
User = models.ForeignKey('User')
PortfolioItem = models.ForeignKey('PortfolioItem')
Tag_Name = models.CharField(max_length=200, blank=False)
What I need to do, is for every user, get all the Tag_Name values of it's SkillTags, how do I do this?
You can do something like this
class User(Auth_User):
#other attributes
def tag_names(self):
return self.skilltag_set.values_list('Tag_Name', flat=True)
So, here, we are doing a couple of things:
Querying in reverse ForeignKey relationship.
Since you are not using a related_name in the ForeignKey attribute, by default django would assign the model name (lowercase) followed by _set attribute, which makes it .skilltag_set.all()
values_list
Returns a ValuesQuerySet — a QuerySet subclass that returns tuples when used as an iterable, rather than model-instance objects.
Example: [('a'), ('b'), ('c')]
Basically, you are retriving an iterable of ValuesQuerySet (think of it as a list or any other iterables) consisting of tuples.
flat=True
This basically flattens the on-tuples into single values.
Example: ['a', 'b', 'c']
most obvious: using the reverse relationship of ForeignKey fields:
def skill_names_1(user):
return [t.name for t in user.skilltag_set.all()]
The same thing, but explicitly selecting for the user. also, it fetches only the required field from the database.
def skill_names_2(user):
return SkillTag.objects.filter(User=user).values_list('Tag_Name',flat=True)
Either of these can also work as a method of User. Of course, typically the argument would be called self instead of user.
All the skills for a group of users:
def skill_names_3(users):
return SkillTag.objects.filter(User__in=users).values_list('Tag_Name',flat=True)
So right now I'm editting the Querydict that the modelform gives to the view to make the submission in one field all lowercase and have no spaces. but then when I construct and pass that dictionary back to the Modelform to be validated/saved it doesn't give me an error if the same thing has been entered more than once. It seems like unique=True should work for all submissions that are in the correct format not just ones from request.POST. Any help/insight on the issue would be awesome.
EDIT: CODE
THE VIEW THAT HANDLES THE MODELFORM
dict = {}
sitename = request.POST['sitename']
#insert an if statement telling them only letters are allowed
urltitle = ''.join(sitename.split()).lower()
dict['sitename'] = urltitle
make = MakesiteForm(dict)
if make.is_valid():
make.save()
MODEL IN QUESTION
class Makesite(models.Model):
sitename = models.CharField(max_length=100, unique = True)
siteinfo = models.ManyToManyField(Siteinfo)
ref_id = models.ManyToManyField(RefID)
def __unicode__(self):
return u'%s' %(self.sitename)
1.Don't reassign built-in dict function
2.Field processing logic should be done in clean method:
class MakesiteForm(forms.ModelForm):
# your code... Then
def clean_sitename(self):
sitename = self.cleaned_data['sitename']
return ''.join(sitename.split()).lower()
3.Show what errors you get if form is not valid?