Is it possible to have a field in a Django model which does not get stored in the database.
For example:
class Book(models.Model):
title = models.CharField(max_length=75)
description models.CharField(max_length=255, blank=True)
pages = models.IntegerField()
none_db_field = ????
I could then do
book = Book.objects.get(pk=1)
book.none_db_field = 'some text...'
print book.none_db_field
Thanks
As long as you do not want the property to persist, I don't see why you can't create a property like you described. I actually do the same thing on certain models to determine which are editable.
class Email(EntryObj):
ts = models.DateTimeField(auto_now_add=True)
body = models.TextField(blank=True)
user = models.ForeignKey(User, blank=True, null=True)
editable = False
...
class Note(EntryObj):
ts = models.DateTimeField(auto_now_add=True)
note = models.TextField(blank=True)
user = models.ForeignKey(User, blank=True, null=True)
editable = True
Creating a property on the model will do this, but you won't be able to query on it.
Example:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
def _get_full_name(self):
return "%s %s" % (self.first_name, self.last_name)
def _set_full_name(self, combined_name):
self.first_name, self.last_name = combined_name.split(' ', 1)
full_name = property(_get_full_name)
full_name_2 = property(_get_full_name, _set_full_name)
Usage:
from mysite.models import Person
a = Person(first_name='John', last_name='Lennon')
a.save()
a.full_name
'John Lennon'
# The "full_name" property hasn't provided a "set" method.
a.full_name = 'Paul McCartney'
Traceback (most recent call last):
...
AttributeError: can't set attribute
# But "full_name_2" has, and it can be used to initialise the class.
a2 = Person(full_name_2 = 'Paul McCartney')
a2.save()
a2.first_name
'Paul'
To make it an instance variable (so each instance gets its own copy), you'll want to do this
class Book(models.Model):
title = models.CharField(max_length=75)
#etc
def __init__(self, *args, **kwargs):
super(Foo, self).__init__(*args, **kwargs)
self.editable = False
Each Book will now have an editable that wont be persisted to the database
If you want i18n support:
# Created by BaiJiFeiLong#gmail.com at 2022/5/2
from typing import Optional
from django.db import models
from django.utils.translation import gettext_lazy as _
class Blog(models.Model):
title = models.CharField(max_length=128, unique=True, verbose_name=_("Title"))
content = models.TextField(verbose_name=_("Content"))
_visitors: Optional[int] = None
#property
def visitors(self):
return self._visitors
#visitors.setter
def visitors(self, value):
self._visitors = value
visitors.fget.short_description = _("Visitors")
Related
When importing a file I want to skip all of the new rows that doesn't exist, and only update and change the ones that already exists, I've been trying for days to solve this problem, any ideas will help.
https://ibb.co/1Gw4Q19
also the file type is ".xls" or ".xlsx"
here's my code:
models.py:
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField('Book name', max_length=100)
author = models.ForeignKey(Author, blank=True, null=True, on_delete=models.CASCADE)
author_email = models.EmailField('Author email', max_length=75, blank=True)
imported = models.BooleanField(default=False)
published = models.DateField('Published', blank=True, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True)
def __str__(self):
return self.name
admin.py:
class BookResource(resources.ModelResource):
class Meta:
model = Book
import_id_field = 'id'
import_id_fields = ('id',)
fields = ('id', 'name', 'price',)
skip_unchanged = True
report_skipped = True
dry_run = True
class CustomBookAdmin(ImportMixin, admin.ModelAdmin):
resource_class = BookResource
# tried to override it like so but it didn't work
def skip_row(self, instance, original):
original_id_value = getattr(original, self._meta.import_id_field)
instance_id_value = getattr(instance, self._meta.import_id_field)
if original_id_value != instance_id_value:
return True
if not self._meta.skip_unchanged:
return False
for field in self.get_fields():
try:
if list(field.get_value(instance).all()) != list(field.get_value(original).all()):
return False
except AttributeError:
if field.get_value(instance) != field.get_value(original):
return False
return True
So if you want to skip any rows in the import file which do not already exist in the database, then you can ignore any rows which don't have a pk (i.e. have not previously been persisted):
Just add the following to your BookResource sub class
def skip_row(self, instance, original):
return getattr(original, "pk") is None
I hope this works - let me know if I've misunderstood anything.
The full solution exists here
To only update existing items while ignoring any new item you can use:
# Do not import any new items. Only update records
def skip_row(self, instance, original):
if original.id:
return False
return super(BookResource, self).skip_row(instance, original)
To import only new items while preventing updates you can use:
# Only import new items. Do not update any record
def skip_row(self, instance, original):
if not original.id:
return False
return True
This assumes import_id_fields = ('id',) and resource is called BookResource
Appologies for the beginner question and/or stupidity - I'm learning as I go.... I'm trying to pass a user entered url of a PubMed article to access the metadata for that article. I'm using the following code, but I cannot access anything form the save method in he 'Entry' model. For example in my html form I can display {{entry.date_added }} in a form but not {{ entry.title}}. I suspect it's a simple answer but not obvious to me. Thanks for any help.
models.py
from django.db import models
from django.contrib.auth.models import User
import pubmed_lookup
from django.utils.html import strip_tags
class Topic(models.Model):
"""Broad topic to house articles"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
"""Return a string representation of the model"""
return self.text
class Entry(models.Model):
"""Enter and define article from topic"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
pub_med_url = models.URLField(unique=True)
date_added = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
query = self.pub_med_url
email = "david.hallsworth#hotmail.com"
lookup = pubmed_lookup.PubMedLookup(query, email)
publication = pubmed_lookup.Publication(lookup)
self.title = strip_tags(publication.title)
self.authors = publication.authors
self.first_author = publication.first_author
self.last_author = publication.last_author
self.journal = publication.journal
self.year = publication.year
self.month = publication.month
self.day = publication.day
self.url = publication.url
self.citation = publication.cite()
self.mini_citation = publication.cite_mini()
self.abstract = strip_tags(publication.abstract)
super().save(*args, **kwargs)
class Meta:
verbose_name_plural = 'articles'
def __str__(self):
return "{} - {} - {} - {} [{}]".format(self.year,
self.first_author, self.journal, self.title, str(self.pmid), )
In Django ORM, you have to manually specify all fields that need to be saved. Simply saving it as self.foo = bar in the save method is stored in the Entry instance object (=in memory), but not in the database. That is, there is no persistence. Specify all the fields that need to be saved in the model and run python manage.py makemigrations,python manage.py migrate. Assigning fields to the model is actually the task of designing the relational database.
class Entry(models.Model):
"""Enter and define article from topic"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
pub_med_url = models.URLField(unique=True)
date_added = models.DateTimeField(auto_now_add=True)
title = models.CharField(...)
authors = models.CharField(...)
...
def assign_some_data_from_pubmed(self):
email = "david.hallsworth#hotmail.com"
lookup = pubmed_lookup.PubMedLookup(query, email)
publication = pubmed_lookup.Publication(lookup)
self.title = strip_tags(publication.title)
self.authors = publication.authors
self.first_author = publication.first_author
self.last_author = publication.last_author
self.journal = publication.journal
self.year = publication.year
self.month = publication.month
self.day = publication.day
self.url = publication.url
self.citation = publication.cite()
self.mini_citation = publication.cite_mini()
self.abstract = strip_tags(publication.abstract)
Usage:
entry = Entry(...)
entry.assign_some_data_from_pubmed()
entry.save()
I have a super class for my models as below:
class BaseModel(models.Model):
""" BaseClass vase aksare model ha """
def __init__(self, *args, **kwargs):
super(BaseModel, self).__init__(args, kwargs)
print('******> base model __init__')
status = models.IntegerField(default=1)
is_deleted = models.BooleanField(default=False)
create_user = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_creator_related")
create_date = models.DateTimeField()
update_date = models.DateTimeField()
update_user = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_updater_related")
class Meta:
abstract = True
def validate(self):
print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^base validation')
and I have a profile model as below:
class Profile(BaseModel):
def __init__(self, *args, **kwargs):
super(Profile, self).__init__(args, kwargs)
""" User profile """
user = models.OneToOneField(User, related_name='profile')
mobile = models.CharField(max_length=25, null=True)
firstname_en = models.CharField(max_length=500, null=True)
lastname_en = models.CharField(max_length=500, null=True)
gender = models.IntegerField(default=0)
birth_date = models.DateTimeField(null=True)
edu_bg = models.ForeignKey('Category', related_name="profile__edu_bg", null=True)
region = models.ForeignKey('Category', related_name="profile__region", null=True)
credit = models.DecimalField(default=0, decimal_places=6, max_digits=15)
key = models.TextField(null=True)
secret = models.TextField(null=True)
I have an error when I want to insert a new userProfile as below:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'.
then print the vars(userprofileObject) and realized that 'id': ((), {}), however, I have not set it. When I removed the __init__ functions or set id to None in insertion code, problem solved.
Any idea?
I need those __init__ and also don't want to set id=None in my code
This is how django's models work. You shouldn't change their __init__ method.
This is why
You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved. Rather than overriding __init__, try using one of these approaches:
# Add a classmethod on the model class:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
#classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
Source https://docs.djangoproject.com/en/1.10/ref/models/instances/#django.db.models.Model
Also read this Writing a __init__ function to be used in django model
I am following a tutorial online for Django. The presenter loads in random data as follows:
for i in xrange(100): Vote(link = Link.objects.order_by('?')[0],voter=a).save()
From what I could understand, it goes from 0 to 100 and creates a new vote. The vote object has a link object. I don't understand what the order_by('?') means.
Here is the model.py file:
from django.db import models
from django.contrib.auth.models import User
from django.db.models import Count
class LinkVoteCountManager(models.Manager):
def get_query_set(self):
return super(LinkVoteCountManager, self).get_query_set().annotate(
votes=Count('vote')).order_by("-votes")
class Link(models.Model):
title = models.CharField("Headline", max_length=100)
submitter = models.ForeignKey(User)
submitted_on = models.DateTimeField(auto_now=True)
rank_score = models.FloatField(default=0.0)
url = models.URLField("URL", max_length=250, blank=True)
description = models.TextField(blank=True)
with_votes = LinkVoteCountManager()
objects = models.Manager()
def __unicode__(self):
return self.title
class Vote(models.Model):
voter = models.ForeignKey(User)
link = models.ForeignKey(Link)
def __unicode__(self):
return "%s voted %s" %(self.voter.username, self.link.title)
I'm trying to add an "event" in the admin and get this error:
TypeError at /admin/sms/event/add/
'Contact' object is not subscriptable
models.py:
class Contact(models.Model):
users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="contact")
name = models.CharField(_("Recipient"), max_length=40)
phone = models.IntegerField(_("Phone"), max_length=10)
def __unicode__(self):
return "%s: %d" % (self.name, self.phone)
class Event(models.Model):
calendar = models.ForeignKey(Calendar, verbose_name=_("Calendar"), related_name="event_calendar")
message = models.ForeignKey(Message, verbose_name=_("Message"), related_name="event_message")
recipient = models.ForeignKey(Contact, verbose_name=_("Recipient"), related_name="event1")
event_date = models.DateField(_("Date"))
start_time = models.TimeField(_("Start time"))
end_time = models.TimeField(_("End time"), blank=True, null=True)
location = models.CharField(_("Location of meeting"), blank=True, null=True, max_length=100)
reminder_options = models.IntegerField(choices=ReminderOptions.CHOICES, verbose_name=_("Reminder time"))
content = models.CharField(_("Event Notes"), max_length=160)
# recurring_options = models.IntegerField(choices=RecurringOptions.CHOICES, verbose_name=_("Recurring time"))
def __unicode__(self):
return self.recipient
def get_absolute_url(self):
return u'/create-event/'
First guess is that your phone field gets a string from your admin form. Use a charField for phone in your model and make a custom form in your admin.py.
In models.py change your phone Integerfield to a CharField:
class Contact(models.Model):
...
phone = models.CharField(_("Phone"), max_length=200)
def __unicode__(self):
return "%s: %s" % (self.name, self.phone) # %d becomes %s
In Admin.py create a form:
from models import Contact
from django import forms
from django_localflavor_fr.forms import FRPhoneNumberField
class ContactForm(forms.ModelForm):
phone = FRPhoneNumberField()
class Meta:
model = Contact
https://docs.djangoproject.com/en/1.5/ref/contrib/localflavor/
In Admin.py create a ModelAdmin:
class ContactAdmin(admin.ModelAdmin):
form = ContactForm