Django: reverse list of many to many relationship? - django-models

I have two simple models in models.py: Service and Host. Host.services has a m2m relationship with Service.
In other words, a host has several services and one service can reside on multiple hosts; a basic m2m.
models.py
class Service(models.Model):
servicename = models.CharField(max_length=50)
def __unicode__(self):
return self.servicename
class Admin:
pass
class Host(models.Model):
#...
hostname = models.CharField(max_length=200)
services = models.ManyToManyField(Service)
#...
def service(self):
return "\n".join([s.servicename for s in self.services.all()])
def __unicode__(self):
return self.hostname
class Admin:
pass
How do I get a one-to-many output in the admin interface, with the class 'Service' as basis (a reverse many-to-many?).
Do I need to use '_set.all()' ?

Use related_name on the services:
services = models.ManyToManyField(Service, related_name='hosts')
and then do
service.hosts.all()
to get the hosts for a service.

This seems to do the trick:
class Service(models.Model):
servicename = models.CharField(max_length=50)
def hostname(self):
return "\n".join([s.hostname for s in self.hosts_services.all()])
def __unicode__(self):
return self.servicename
class Host(models.Model):
#...
services = models.ManyToManyField(Service, related_name='hosts_services')
#...

Related

Extending the typer of user the most simple way in Django

I want to create two types of user in Django in the most simple way.
I want to use class AbstractBaseUser
class BaseUser(AbstractBaseUser):
email = models.EmailField(max_length=254, unique=True)
class Service_provider(BaseUser):
company = models.CharField(max_length=140);
def __unicode__(self):
return self.company
class Customer(BaseUser):
name = models.CharField(max_length=140);
def __unicode__(self):
return self.name
I don't know how to pass this two user to the user model without applying any complicated change in the auth model.
Is it possible?
No. Django's built-in auth framework does not support more than one user model. You will need to write your own auth framework from scratch.

Django: how to save additional fields in a database?

I have a class in models.py:
class Person(AbstractUser):
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
It`s related to AbstractUser from contrib/models.py
I`ve made a class that lets make additional fields to it.
class ExtraTextField(models.Model):
add = models.ForeignKey(Person)
new_field_text = models.TextField(max_length=200, verbose_name='content')
def __unicode__(self):
return u'%s' % (self.new_field_text)
class AddText(admin.StackedInline):
model = ExtraTextField
extra = 0
class AdminForm(admin.ModelAdmin):
inlines = [AddText]
As you see, amount of fields is not defined, so I can`t just put them into class Person. But as a logical continuing, these additional fields are not saved in the database. Please, help, how can I solve this problem?

Override Django User model __unicode__

Currently, Django 1.2.3 User model unicode is
def __unicode__(self):
return self.username
and I'd like to override it so its:
def __unicode__(self):
return u'%s, %s' % (self.last_name, self.first_name)
How to?
To similar effect:
User._meta.ordering = ['last_name', 'first_name']
works when defined anywhere
If you simply want to show the full name in the admin interface (which is what I needed), you can easily monkey-patch it during runtime. Just do something like this in your admin.py:
from django.contrib import admin
from django.contrib.auth.models import User
def user_unicode(self):
return u'%s, %s' % (self.last_name, self.first_name)
User.__unicode__ = user_unicode
admin.site.unregister(User)
admin.site.register(User)
Django's Proxy Model solved this problem.
This is my solution:
form.fields['students'].queryset = Student.objects.filter(id__in = school.students.all())
Here school.students is a m2m(User), Student is a proxy model of User.
class Student(User):
class Meta:
proxy = True
def __unicode__(self):
return 'what ever you want to return'
All above helps you to solve if your want to show your User ForeignKey in your custom method. If your just want to change it in admin view, there is a simple solution:
def my_unicode(self):
return 'what ever you want to return'
User.__unicode__ = my_unicode
admin.site.unregister(User)
admin.site.register(User)
add these codes to admin.py, it works.
If you need to override these, chances are you would need more customizations later on.
The cleanest practice would be using a user profile models instead of touching the User model
Create a proxy User class.
class UserProxy(User):
class Meta:
proxy = True
ordering = ['last_name', 'first_name']
def __unicode__(self):
return u'%s, %s' % (self.last_name, self.first_name)
I just found this simple method on django 1.5
def __unicode__(self):
a = self.last_name
b = self.first_name
c = a+ "-" +b
return c
it will return what you want

Django m2m 'through' with a generic foreignkey

I have the follow code example, which is a simplified abstraction of a real world project I'm working on:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class FeatureSet(models.Model):
"""
Feature Set
"""
name = models.CharField(max_length=255)
def __unicode__(self):
return u"%s" % self.name
class GenericObjectAlpha(models.Model):
title = models.CharField(max_length=255)
feature_sets = models.ManyToManyField(FeatureSet, through='Feature')
def __unicode__(self):
return u"%s" % self.title
class GenericObjectBeta(models.Model):
title = models.CharField(max_length=255)
feature_sets = models.ManyToManyField(FeatureSet, through='Feature')
def __unicode__(self):
return u"%s" % self.title
class Feature(models.Model):
"""
Feature
"""
# FK to feature set
feature_set = models.ForeignKey(FeatureSet)
# FK to generic object, Generic object alpha or beta... or others
content_type = models.ForeignKey(
ContentType,
default='article',
limit_choices_to={ 'model__in': ('genericobjectalpha', 'genericobjectbeta') },
related_name="play__feature_set__feature")
object_id = models.PositiveIntegerField(
"Feature object lookup")
content_object = generic.GenericForeignKey(
'content_type',
'object_id')
# Extra fields on a m2m relationship
active = models.BooleanField()
order = models.PositiveIntegerField()
def __unicode__(self):
return u"%s::%s" % (self.feature_set, self.content_object)
This line causes an error:
feature_sets = models.ManyToManyField(FeatureSet, through='Feature')
Obviously because the 'through' model lacks a corresponding FK to each side of the m2m. What I'd like to achieve here, is that one side of the m2m relationship is generic, and, that I can specify my own intermediary join table, to do the usual adding of custom fields etc.
What are my options for accomplishing this?
Note, its currently an important requirement to include the feature_sets = models.ManyToManyField(FeatureSet, through='Feature') line in the generic model, mostly for admin UI purposes. The reason why its generic is that its not yet determined how many models this line will be placed upon.

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

Resources