Django models, custom functions - django-models

I am creating simple application with django. Also, I realized that I am doing some kind of operations very often. For example I often need to get all Article objects which have isPublick = True. So I am thinking is that possible to define get_published function in model?
if models looks like this (simplified)
class Article(models.Model):
title = models.CharField(...)
isPublished = models.BooleandField()
def get_active(self):
return Article.objects.filter(isPublicshed = 1)
But it doesn't work this way
Can you suggest a way of implementing the function?

What you probably want is a custom manager
From the django docs:
# An example of a custom manager called "objects".
class PersonManager(models.Manager):
def get_fun_people(self):
return self.filter(fun=True)
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
fun = models.BooleanField()
objects = PersonManager()
def __unicode__(self):
return u"%s %s" % (self.first_name, self.last_name)
which then allows you to do something like:
>>> p1 = Person(first_name='Bugs', last_name='Bunny', fun=True)
>>> p1.save()
>>> p2 = Person(first_name='Droopy', last_name='Dog', fun=False)
>>> p2.save()
>>> Person.objects.get_fun_people()
[<Person: Bugs Bunny>]

As is stated in the docs here, if you need to add custom row-level functionality to your objects, you need to define custom methods on your models. However, if what you are after is custom table-wide functionality (such as getting all Article objects that qualify certain conditions), you have to define custom methods on model Managers (much as aciniglio above points out in their answer).

You can use the staticmethod decorator.
class Article(models.Model):
title = models.CharField(...)
isPublished = models.BooleandField()
#staticmethod
def get_active():
return Article.objects.filter(isPublished = 1)

Related

Representing a set in a Django model

I have a use case when a Django model class can have any of a specified set of values. If it weren't a Django model, I'd do something like:
attr_list = ['green', 'blue', 'fuzzy', 'smooth']
class my_model:
def __init__(self, attrs=None):
self._attrs = set(attrs)
def quality(self, attr):
return attr in self._attrs
obj = my_model(['green', 'fuzzy'])
if obj.quality('green'):
print("It's green")
But in Django, the only options seem to be a class that represents the link between the model and the quality, with a class that just has one attribute holding the quality value:
class QualityLink(models.Model):
quality = models.CharField(
choices=[('green', 'Green'), ...]
...)
parent = models.ForeignKey(MyModel, ...)
or, if I want to avoid the overhead of a bunch of database accesses, unwinding the values:
class MyModel(models.Model):
is_green = models.BooleanField(...)
is_blue = models.BooleanField(...)
is_fuzzy = models.BooleanField(...)
is_smooth = models.BooleanField(...)
Neither of these seems like a very good approach. The first seems inefficient and the second way too clunky. Am I missing something?

Problems with StructuredProperty and StringProperty

i am doing the finally degree work in Google App Engine, but i am having problems when i try this:
class Predicate(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.JsonProperty()
class State(ndb.Model):
predicates = ndb.StructuredProperty(Predicate, repeated=True)
class Action(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.StringProperty(repeated=True)
preconditions = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToAdd = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToDel = ndb.StructuredProperty(Predicate, repeated=True)
class Plan(ndb.Model):
plan = ndb.StructuredProperty(Predicate, repeated=True)
class Problem(ndb.Model):
initialState = ndb.StructuredProperty(Predicate)
goalState = ndb.StructuredProperty(Predicate)
actions = ndb.StructuredProperty(Action, repeated=True)
i get this error:
TypeError: This StructuredProperty cannot use repeated=True because its model class (Predicate) contains repeated properties (directly or indirectly).
StructuredProperty, if it contains repetitions, can not be replicated another StructuredProperty. But I need this structure models. How can i solve this?
And sorry for my bad english :(
I solved this problem using LocalStructuredProperty, but I think it will not work at all
The problem with your design is that ndb does not allow nested repeated properties. In other words, you cannot have a repeated structured property, which in turn has its own repeated property. If you remove the repeated=True from the parameters property, it will work.
You will need to re-think your design to work around this. One possible solution may be to use a JsonProperty for parameters, and store the list of strings as a JSON string. You won't be able to query them then of course, but it may work out depending on your requirements.

Django, autogenerate one-to-many tables, and database structure

I am using django for a website where I have a database with users, people, locations, items and so on. Know i find that I need some extra information that requires one-to-many relations like Aliases for most of these tables.
Should I (1) create a common alias table for all of these by using the content type framework (will probably end up with billions of rows), or should I (2) create a alias table for each of these. If the latter one, how do I auto-create one-to-many table like this by just adding a single line like this
"alias = Ailias()"
in each model. I`m sure I saw an app doing something like that way a while ago, I think is was a reversion app of some kind. Even if the second method is not suited i would love tho understand how to do it. I do not know what to search after to find an explanation of this.
I plan to add Haystack with Solr to this, so method 2 might add much extra work there. But I do not have much experience with it jet, so I might be wrong.
PS: ended up wih method one.
Manage to do what I wanted in method 2, easily generate one-to-many fields. Not sure if this is the easiest way, or the best way. If someone has a better way of doing it, I would love to learn it. I am a long way from a django expert, so I might have meddled with some unnecessary complex stuff to do what I wanted.
This example creates an easy way of adding a one-to-many alias relationship.
Alias Managers
class AliasManagerDescriptor(object):
def __init__(self, model,fkName):
self.model = model
self.fkName = fkName
def __get__(self, instance, owner):
if instance is None:
return AliasManager(self.model,self.fkName)
return AliasManager(self.model, self.fkName, instance)
class AliasManager(models.Manager):
def __init__(self, model,fkName, instance=None):
super(AliasManager, self).__init__()
self.model = model
self.instance = instance
#Name of FK linking this model to linked model
self.fkName=fkName
def get_query_set(self):
"""
Get query set, or only get instances from this model that is linked
to the chosen instance from the linked model if one is chosen
"""
if self.instance is None:
return super(AliasManager, self).get_query_set()
if isinstance(self.instance._meta.pk, models.OneToOneField):
#TODO: Checkif this part works, not checked
filter = {self.instance._meta.pk.name+"_id":self.instance.pk}
else:
filter = {self.fkName: self.instance.pk}
return super(AliasManager, self).get_query_set().filter(**filter)
def create(self,**kwargs):
"""
Create alias instances. If FK is not given then it is automatically set
to the chosen instance from the linked model
"""
if self.fkName not in kwargs:
kwargs[self.fkName]=self.instance
print kwargs
super(AliasManager, self).create(**kwargs)
Alias Models
class Alias(object):
def contribute_to_class(self, cls, name):
self.manager_name = name
aliasModel = self.create_alias_model(cls)
descriptor = AliasManagerDescriptor(aliasModel,cls._meta.object_name.lower())
setattr(cls, self.manager_name, descriptor)
def create_alias_model(self, model):
"""
Creates a alias model to associate with the model provided.
"""
attrs = {
#'id': models.AutoField(primary_key=True),
"name": models.CharField(max_length=255),
#Not sure which to use of the two next methods
model._meta.object_name.lower(): models.ForeignKey(model),
#model._meta.object_name.lower(): AliasObjectDescriptor(model),
'__unicode__': lambda self: u'%s' % self.name,
'__module__': model.__module__
}
attrs.update(Meta=type('Meta', (), self.get_meta_options(model)))
name = '%s_alias' % model._meta.object_name
return type(name, (models.Model,), attrs)
def get_meta_options(self, model):
"""
Returns a dictionary of fields that will be added to
the Meta inner class.
"""
return {
}
"""class AliasObjectDescriptor(object):
def __init__(self, model):
self.model = model
def __get__(self, instance, owner):
values = (getattr(instance, f.attname) for f in self.model._meta.fields)
return self.model(*values)"""
Person Model - Only need to add "alias = Alias()" to a model to add a one-to-many alias field.
class Person(models.Model):
name = models.CharField(max_length=30,blank=True,null=True)
age = models.IntegerField(blank=True,null=True)
alias = Alias()
Now you I can do something like this:
per = Person(name="Per",age=99)
per.save()
per.alias.create(name="Mr.P")
per_alias = per.alias.all().values_list("name",flat=True)

Django-nonrel in Google App Engine ListField

I am trying to build an example app in Google App Engine using django-nonrel. and am having problems implementing ListField attribute into a model.
I have created an app test_model and have included it as an installed app in my settings. The model.py is:
from django.db import models
from djangotoolbox import *
from dbindexer import *
# Create your models here.
class Example(models.Model):
some_choices = models.ListField('Choice_examples')
notes = models.CharField(max_length='20')
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % (self.notes)
class Choice_examples(models.Model):
name = models.CharField(max_length='30')
def __unicode__(self):
return u'%s' % (self.name)
The above example gives me:
AttributeError:'module' object has no attribute 'Model'
If I comment out the djangotoolbox import, I get the following :
AttributeError: 'module' object has no attribute 'ListField'
What am I doing wrong here? I can't seem to find any documention as to how to go about using ListField in django-nonrel. Is that because it is supposed to really obvious?
Your imports are smashing each other:
from django.db import models
from djangotoolbox import *
The second import will replace the django.db models with djangotoolbox' empty models module. Using from X import * is a terrible idea in general in Python and produces confusing results like these.
If you're looking to use ListField from djangotoolbox, use:
from djangotoolbox import fields
and refer to the ListField class as fields.ListField.
OK, here is what I did to be able to use ListFields. MyClass the equivalent to your Example class and AnotherClass is the same as your Choice_examples. What I describe will allow you to use ListFields in the admin interface and your self implemented views.
I'll start from the beginning
This is what what my model looks like
class MyClass(models.Model):
field = ListField(models.ForeignKey(AnotherClass))
I wanted to be able to use the admin interface to create/edit instances of this model using a multiple select widget for the list field. Therefore, I created some custom classes as follows
class ModelListField(ListField):
def formfield(self, **kwargs):
return FormListField(**kwargs)
class ListFieldWidget(SelectMultiple):
pass
class FormListField(MultipleChoiceField):
"""
This is a custom form field that can display a ModelListField as a Multiple Select GUI element.
"""
widget = ListFieldWidget
def clean(self, value):
#TODO: clean your data in whatever way is correct in your case and return cleaned data instead of just the value
return value
These classes allow the listfield to be used in the admin. Then I created a form to use in the admin site
class MyClassForm(ModelForm):
def __init__(self, *args, **kwargs):
super(MyClasstForm,self).__init__(*args, **kwargs)
self.fields['field'].widget.choices = [(i.pk, i) for i in AnotherClass.objects.all()]
if self.instance.pk:
self.fields['field'].initial = self.instance.field
class Meta:
model = MyClass
After having done this I created a admin model and registered it with the admin site
class MyClassAdmin(admin.ModelAdmin):
form = MyClassForm
def __init__(self, model, admin_site):
super(MyClassAdmin,self).__init__(model, admin_site)
admin.site.register(MyClass, MyClassAdmin)
This is now working in my code. Keep in mind that this approach might not at all be well suited for google_appengine as I am not very adept at how it works and it might create inefficient queries an such.
I don't know, but try with:
class Choice_examples(models.Model):
name = models.CharField(max_length='30')
def __unicode__(self):
return u'%s' % (self.name)
class Example(models.Model):
some_choices = models.ListField(Choice_examples)
notes = models.CharField(max_length='20')
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % (self.notes)
Looks like the answer is that you cannot pass an object into fields.ListField.
I have ditched trying to work with ListField as documentation is limited and my coding skills aren't at a level for me to work it out.
Anyone else coming across a similar problem, you should consider create a new model to map the ManyToMany relationships. And if the admin view is important, you should look into the following to display the ManyToMany table inline with any given admin view:
http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#s-working-with-many-to-many-models

What is the best way to store multiple date strings in Django?

I'm building a Django app that needs to store multiple selected dates for an event. The first thing that came to mind was build the event model:
class Event(models.Model):
title = models.CharField(max_length=200)
creator = models.ForeignKey(User)
modified = models.DateTimeField(auto_now=True, auto_now_add=False)
created = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
Then build a separate table of EventDates:
class EventDate(models.Model):
event = models.ForeignKey(Event)
date = models.DateField()
modified = models.DateTimeField(auto_now=True, auto_now_add=False)
created = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return "%s / %s" % (self.event, self.date)
class Meta:
ordering = ('created',)
But is this the best way? Is there a better performing alternative, like a comma separated string?
The best way is the one that best serves your purposes. There is no built-in comma separated field in Django, but you can easily roll your own one - the problem is if this is what you really need.
For example - if you need to filter events based on their dates, I'm not sure how you could easily do this with such comma separated field, but I can clearly see how you could do this with your current approach:
Event.objects.filter(eventdate_set__date=my_date)
-- so unless you specify your planned usage pattern, I don't think there is a general answer.

Resources