I have a Trip
model which can have many participants subscribed for a given trip and one owner. The participans are users registered on the site, but I also want to be able to add 'offline' users to the trip, users who do not have accounts on the site, so that I could keep track of all the users coming.
The owner and participatns are linked to Userena user profile (side question: maybe linking directly to User
would be better? But how would I get full_name to see as selection in inline admin then?)
class Trip(models.Model):
name = models.CharField('trip name', max_length=200)
type = models.ForeignKey(Category, related_name='categories')
.
.
.
slug = models.SlugField('trip slug', max_length=100)
owner = models.ForeignKey(UserProfile, related_name='owner')
participants = models.ManyToManyField(UserProfile, blank=True, null=True, related_name='participants')
is_public = models.BooleanField("is visible?",db_index=True)
class ParticipationInline(admin.TabularInline):
model = Trip.participants.through
extra = 3
class TripAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name in ('desc',):
return db_field.formfield(widget=TinyMCE(
attrs={'cols': 100, 'rows': 20},
mce_attrs={'external_link_list_url': reverse('tinymce.views.flatpages_link_list')},
))
return super(TripAdmin, self).formfield_for_dbfield(db_field, **kwargs)
inlines = [
ParticipationInline,
]
exclude = ('participants',)
prepopulated_fields = {"slug": ("name",)}
list_display = ('name', 'type', 'date', 'dest','owner', 'is_public')
list_filter = ['date', 'type']
search_fields = ['name', 'dest', 'desc']
date_hierarchy = 'date'
class Media:
js = ('js/tiny_mce/tiny_mce.js',
'js/tiny_mce/textareas.js',)
admin.site.register(Trip, TripAdmin)
So when I add a Trip
through Admin interface I want to first select a participant from existing registered users, and if I don't find them there, I want to be able to inline add a new 'offline' participant. What would be the best way to achieve this?
UserProfile
?Trip
?Edit after Hedde's comment.
I created OfflineUser
as suggested with GenericRelation to my Trip
:
class OfflineUser(models.Model):
first_name = models.CharField(_('first'), max_length=30)
last_name = models.CharField(_('last'), max_length=30)
...
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey("content_type", "object_id")
class Trip(models.Model):
...
owner = models.ForeignKey(UserProfile, related_name='owner')
participants = models.ManyToManyField(UserProfile, blank=True, null=True, related_name='participants')
offline_users = generic.GenericRelation(OfflineUser)
and after adding OfflineUserInline
I am able to add registered users and offline users to my Trip
!
I can then list the Trip
participants of both types like this:
{% if request.user.is_staff %}
<ul>
{% for participants in object.participants.all %}
<li> {{ participants.full_name }}
</li>
{% empty %}
No registered users!
{% endfor %}
{% for participants in object.offline_users.all %}
<li> {{ participants.full_name }}
</li>
{% empty %}
No offline users!
{% endfor %}
</ul>
{% endif %}
So it works to a point and now I have a strange feeling that I did not completely understood Hedde's answer...
Everytime I want to do something with the participants (count them, list them, etc) I will need to do that twice?
Using the contenttypes framework could make this easier. You can filter/hide contenttypes from the admin and clean forms or override saves where needed. For the 'offline' participants I wouldn't create a profile, but mimic, e.g.:
class OfflineUser(models.Model):
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=30)
email = models.EmailField(_('e-mail address'))
# field extensions
... = generic.GenericRelation(...)
def get_profile(self):
pass
def get_full_name(self):
"""
Add some default User methods so you can call them on
the related_object without raising attribute errors
"""
full_name = u'%s %s' % (self.first_name, self.last_name)
return full_name.strip()
Now you can do things like:
{{ some_model.content_object.get_profile.get_full_name }}
There are plenty of stackoverflow and google results to help you out, e.g.
Generic many-to-many relationships
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With