I suddenly am having a problem with my django admin panel.
I have the following models:
class Role(models.Model):
name = models.CharField("Name", max_length=32)
class Person(models.Model):
name = models.CharField("Name", max_length=64)
role = models.ForeignKey(Role)
class Team(models.Model):
rep = models.ManyToManyField(
Person,
related_name="rep_on",
limit_choices_to={'role__name': 'Sales Rep'})
eng = models.ManyToManyField(
Person,
related_name="eng_on",
limit_choices_to={'role_id__name': "Engineer"})
(The two options in the limit_choices_to dictionaries are the two methods I've tried. In the past it seemed like role_id__name worked, but now it doesn't.)
If I create roles for the Sales Rep and Engineer, and create a bunch of people and attach roles, when I create a Team in the admin, I get dropdowns like I expect:
There are two problems. Each dropdown contains every Person object, so limit_choices_to doesn't seem to work at all, and of course these relationships are generic "TEAM-PERSON RELATIONSHIPS" and I'd like to be able to at least label those correctly.
I swear this worked before, and now it's not working. Any ideas as to what could be causing this?
EDIT:
I created a toy application to explore this and tried to slowly recreate the full issue. In my real app I am using two Inlines in the admin interface for the Team object and excluding the model fields. I added them into my test code and managed to recreate the issue.
class RepInline(admin.TabularInline):
model = Team.rep.through
class EngInline(admin.TabularInline):
model = Team.eng.through
class TeamAdmin(admin.ModelAdmin):
inlines = [RepInline, EngInline]
admin.site.register(Role)
admin.site.register(Person)
admin.site.register(Team, TeamAdmin)
And my admin screen looks like:
The given HTML Select fields are filtered, but the dropdowns are not, So the issue lies in the TabularInline, so I have to decide if I want to keep them or not.
Related
I'm struggling to display a manytomany field in the admin with the related model in a user-friendly manner. The project is already up and running so adding a through table is not preferred.
The set-up is something along these lines;
class User(AbstractUser):
is_member_of_organization = models.ManyToManyField(Organization, blank=True, verbose_name=_("is member of organization(s)"), related_name='orgmembers')
class Organization(models.Model):
name = models.CharField(max_length=60, verbose_name=_("organization name"))
the only reasonable way I manage to display the related users with organization admin is via a TabularInline
admin.py
class UserOrgAdminInLine(admin.TabularInline):
model = User.is_admin_for_organization.through
extra = 0
#admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
inlines = (UserOrgAdminInLine,)
However, looking up users is not convenient as soon as their number increases. I would like something similar to filer_horizontal but I am not sure how to include it directly in the OrganizationAdmin admin class. Furthermore, I am using fieldsets (which I believe should have no special rules or syntax to it compared to ordinary fields = .
One little subquestion - in the tabular inline, when I use only model = User django throws an error that there is no foreign key to it, but when I use the additional .is_admin_for_organization.through it works, but there is no through table and I though that this work just in that case. Why is that?
Any help would be much appreciated.
Try adding
class UserOrgAdminInLine
raw_id_fields = ("is_member_of_organization",)
I have a setup like in the following (simplified) example:
class Pizza(models.Model):
name = models.CharField(max_length=100)
class Favorite(models.Model):
user = models.ForeignKey(User, related_name='favorites')
pizza = models.ForeignKey(Pizza, related_name='favorites')
class Meta:
unique_together = (('user', 'pizza'),)
I know that I can filter the favorites property on a Pizza model instance by the user property, but I'd like to abstract this.
In my application, a user should only have access to its personal Favorite model instances. To ensure this, I find myself having to filter all the time and do a lot of ugly and inefficient stuff.
I want to abstract this so that when a user is logged in, I should be able to access pizza.favorite, instead of pizza.favorites, which is automatically mapped to the current user's Favorite model for this particular Pizza model. Ideally, I should also be able to filter on this property (no possible with the #property annotation). Basically, it should act like the ForeignKey is now a OneToOne field.
Any ideas on how could I achieve this behaviour? I should note that un-authorized users do not concern me. The application does not provide anonymous access, so that edge case can be disregarded.
I am using Django 1.7 and I am also open to using the development version, if that would help.
In my Django app, I want to allow users to see which profiles they view and which profiles view them. In my Profile model I have created 2 fields that accomplish this.
viewed = models.ManyToManyField('self', null=True, blank=True, related_name='viewed_profiles', symmetrical=False)
visitors = models.ManyToManyField('self', null=True, blank=True, related_name='visitors_profiles', symmetrical=False)
I also have the code set up in my views.py file to add profiles to these fields as necessary. However, I would like to only track and display the most recent 25 or so viewed and visitor profiles. Is there a way to query these fields ordered by date added and delete everything past the first 25 results? Is this possible without creating another field to track the order of the profiles viewed?
Take a look at the documentation on Querysets for details of how to do this. You can use order_by to order your objects by date, and use Python's array slicing syntax to limit the number of results.
An example of showing the most recently added items in your view might look something like this:
viewed = Profile.objects.order_by("-date_added")[:25]
This doesn't delete everything after 25 - it just fetches the 25 most recent objects (assuming your Profile model has a field called date_added).
EDIT: Oops, I think I misread your question.
I think what you'd need to do is have an intermediate model - Django allows you to use a third model as an intermediate one between two different models in a many-to-many relationship. Then you could add the time viewed to that model and store it that way. There's a good example in the documentation.
I wouldn't really bother deleting the old ones unless database space was likely to be an issue, but if you need to for any reason, I guess you could set up a signal that was triggered by a new view being created and have that call a function that deletes all but the 25 most recent.
Django doesn't track the date added for a ManyToMany relationship, so it's not possible to do this reliably without adding a field. To achieve this you'll need to do is add a date field on your ManyToMany intermediary table, then order by that - for example
class ProfileViewed(models.Model):
viewed = models.ForeignKey('Profile')
viewer = models.ForeignKey('Profile')
date_added = models.DateField(auto_now_add=True)
class Profile(models.Model):
...
viewed = models.ManyToManyField('self', null=True, blank=True, related_name='viewed_profiles', symmetrical=False, through=ProfileViewed)
Then you can order your results like so:
profile = Profile.objects.get(...)
views = ProfileViewed.objects.filter(viewed=profile).order_by('date_added')
I'm coming from a Rails background, and am having a bit of trouble making use of the "Association Methods" provided in Django. I have two models (which have been simplified for the sake of brevity), like so:
class User(models.Model):
username = models.CharField(max_length=100, unique=True)
companies = models.ManyToManyField('Company', blank=True)
class Company(models.Model):
name = models.CharField(max_length=255)
According to the Django documentation:
"It doesn't matter which model has the ManyToManyField, but you should only put it in one of the models -- not both.".
So I understand that if I have an instance of a User, called user, I can do:
user.companies
My question is how do I do the reverse? How do I get all users that belong to a Company instance, let's say Company:
company.users # This doesn't work!
What's the convention to do this? The documentation that I've read doesn't really cover this. I need the association to work both ways, so I can't simply move it from one model to the other.
company.user_set.all()
will return a QuerySet of User objects that belong to a particular company. By default you use modelname_set to reverse the relationship, but you can override this be providing a related_name as a parameter when defining the model, i.e.
class User(models.Model):
companies = models.ManyToManyField(Company, ..., related_name="users")
> company.users.all()
here is the relevant documentation
This may be difficult to explain.
I'm a little new to django and the whole idea of models.
Let's say I'm making an article app, where each article has a creator, but other users can edit the article at will. I'm having a little difficult on how to create the models for this.
Firstly,
I extend the user profile with the following:
class UserProfile(models.Model):
#Required field:
user = models.OneToOneField(User)
#Other Fields:
headline = models.CharField()
industry = models.CharField()
article= models.ForeignKey(articleModel.article)
Here is the first place I'm getting confused, do I put the foreignkey field in the user model? My reasoning for it being placed here is because each article can have many editors.
Now here is my article model:
class article(models.Model):
#primary key is already true
creator = models.ForeignKey(userModel.UserProfile)
title = models.CharField()
text = models.TextField()
Over here, I put the ForeignKey field so it would relate back to the creator, because every article has a single creator. (As a side note, I do want to make it so an article can have multiple creators, but I don't know what to do in this scenario).
I'm finding it a bit odd that the UserProfile model is referencing the article model, and the article is referencing it back. Can someone please help me unjumble my brain?
Thank you.
:)
As simple as possible
from django.db.models import *
from django.contrib.admin.models import User
# UserProfile should be provided by django-profiles
class UserProfile(User): # Subclassing user creates an automatic 1-1 called user
headline = CharField()
industry = CharField()
class Article(Model):
# ALWAYS primary key to User, not UserProfile
creator = ForeignKey(User, related_name='articles_created')
contributors = ManyToManyField(User, related_name='articles_edited')
created = DateTime(auto_now_add=True)
modified = DateTimeField(auto_now=True)
title = CharField()
text = TextField()
class Meta:
order = ['created', 'title']
fun stuff:
creator = Article.objects.all()[:1][0].creator.getUserProfile().headline
considder using django-versions if you want to keep track of edits.
class Article(VersionedModel)
EDIT: actually subclasses user
Nothing "weird" here. This is no such a django problem than a database structure problem. You need to read about 1 to 1, 1 to n and n to n relationships between tables.
Do you really need to record all editors of an article ? An article has many editors, and a user can edit many articles, so this is a many to many relationship. Here's how do do it in django.
Perhaps another field in your article model for last editor would provide you with the information you need.
lastEditor = models.ForeignKey(userModel.UserProfile)
If you really want to keep all editors you will need to implement another model which records something like: article_id, editor and edit time (maybe even the article text if you are interested in changes). You could then query this medel based on the current article to obtain a list of all editors.
you could do the same with: article_id and creator to obtain a list of creators of an article (this would replace the article field in your UserProfile class)