Django Model for associating Favourites - django

Use case:
Want to let an admin create favourite relationships between users.
To do this, I am creating a model called Favourites.
class Favourite(models.Model):
user = models.ForeignKey(to=CustomUser, on_delete=models.CASCADE)
otheruser = models.IntegerField()
However, both user and otherusers are both objects in CustomUsers. In the admin console, when adding a favourite I get a list of users, but I do not get a list of other users obviously.
What model field can I use so that when adding a favourite I get a list of users, and when choosing the otheruser that is also a list of users?

It makes more sense here to add a ManyToManyField [Django-doc] in your CustomUser, so:
class CustomUser(models.Model):
# …
favorites = models.ManyToManyField(
'self',
symmetrical=False,
related_name='fans'
)

Related

Displaying a many-to-many relationship in Django

Background:
I have the following models for a visitor management app. Each site can have multiple visitors and each visitor can visit multiple sites. I am unable to find a way to show a list of visitors on each site or show a list of sites a visitor has visited. I have removed unnecessary fields.
.models.py
class Site(models.Model):
name = models.CharField(max_length=100, unique=True)
accomodation = models.BooleanField(default=False)
visitors = models.ManyToManyField('Visitor', blank=True)
class Visitor(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
email = models.EmailField(max_length=200, null=False, blank=False, unique=True)
...
admin.py
class AdminArea(admin.AdminSite):
vms_admin = AdminArea(name='vms_admin')
#admin.register(Site, site=vms_admin)
class SiteAdmin(admin.ModelAdmin):
fieldsets = (*removed*)
list_display = [*removed*]
list_filter = (*removed*)
#admin.register(Visitor, site=vms_admin)
class VisitorAdmin(admin.ModelAdmin):
fieldsets = (*removed*)
list_display = [*removed*]
list_filter = (*removed*)
Django Admin
This is how the list of sites looks:
Django Admin Site List
This is how the list of visitors look like:
Django Admin Visitor List
Question
How do I show the list of visitors for each site and vice versa?
For example:
If I click on Gingin Gravity Precinct, I want to see the list of visitors associated with it, in a table, below "site details". Similar to the list of visitors shown, but specific to the site.
Django Admin Specific Site
First of all, I would make the related_name explicit in model Site. This is not strictly necessary, there is a default backward reference created by Django, I just never remember the name of that, so I like to be explicit.
visitors = models.ManyToManyField('Visitor', blank=True, related_name='sites')
I assume you want to see the list of sites when you click a single Visitor, in other words, on the visitor detail admin page. In that case, all you need to do is to specify the field sites in the VisitorAdmin. Vice versa to display visitors in the SiteAdmin. You will get a list of all visitors then, in which the active ones are selected.
class SiteAdmin(Admin):
fieldsets = (
('Visitors', {'fields': ('visitors')})
)
If you want to display a (possibly long) list of sites in the visitor list admin page, what you can do is to define a property on the Visitor model, and add that property to the list_fields.
class Visitor(Model):
#property
def list_of_sites(self):
return self.sites.all().values_list(name, flat=True)
class SiteAdmin(Admin):
list_display = ['name', 'accomodation', 'list_of_sites']

Django: Building user Models with multiple relations. User -> Seller -> Buyer and User -> Buyer

I'm trying to create the following structure: I have Sellers and Buyers, both of which are Users of my website. I would like a person to be able to search for Sellers and based on user location, I show the closest Sellers.
I'm using the default Django User auth, and I can only see username and password fields. I would also like to save Seller name. Should I add it to the Seller model, or somehow incorporate in into User model? I've looked at a few apps such as Django Profiles and I'd like to figure out if it's the best way to go about it.
For this, I created a new app users and created a model for the Sellers in the /users/models.py
class Seller(models.Model):
user = models.ForeignKey(User, unique=True)
price = models.IntegerField(default=0)
availability = models.BooleanField(default=False)
verified = models.BooleanField(default=False)
class Buyer(models.Model):
user = models.ForeignKey(User, unique=True)
seller = models.ForeignKey(Seller)
Currently I can display the Sellers, but I don't have access to their name or their user id. Should I simply store their name and last name in the Seller model or should I use an Authentication app? Also, there is no __str__(self) method, since I don't have a sensible identifier such as Name.
I could add fir names to both seller and buyer but then, if a Buyer becomes a Seller, it will have 2 sets of names.
Use a OneToOneField:
user = models.OneToOneField(User, on_delete=models.PROTECT, related_name='buyer')
Then you can use user.buyer or user.seller to access the details. You should also check if they have a buyer or seller profile.

Django query using related_name through another related_name

I have several models that have a ForeignKey back to a model which has a ForeignKey back to auth User in Django.
models.py
class UserDetails(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='userdetail_related')
details = models.CharField(max_length=100)
email = models.EmailField(unique=True)
class UserInformation(models.Model):
user = models.ForeignKey(
UserDetails,
related_name='userinfo_related')
info = models.CharField(max_length=100, default='this')
EDIT
My actual code for related_name as per Django Documentation is: related_name='%(app_label)s_%(class)s_related'. I put 'userdetail_related' for ease of explanation here.
Only one UserDetail per User, but many UserInformation per UserDetail.
Where there is an unregistered user and we have captured their email, the email can have UserDetail and UserInformation associated with it for a shopping cart guest checkout system.
In my View I want to access the UserInformation model from self.request.user.
I can access UserDetails in my view via:
details = self.request.user.userdetail_related.filter(
user=self.request.user).first()
But I can't seem to access UserInformation via:
info = self.request.user.userdetail_related.filter(
user=self.request.user).first().userinfo_related.filter(
info='this').first()
The only way I can get this to work is:
details = self.request.user.userdetail_related.filter(
user=self.request.user).first()
info = details.userinfo_related.filter(
info='this').first()
But this surely hits the database twice which I don't want.
Does anyone have a better way of getting the info from UserInformation using the session user 'through' UserDetails?
You can use following:
user_info = UserInformation.objects.filter(user__user=self.request.user).first()
Additionally, when you access UserDetails you don't really need the filter since you are trying to access the related objects from the user itself. So following would work as well.
details = self.request.user.userdetail_related.first()
And as a side note, I think you need OneToOneField here since one user should have only one UserDetails.
As it suggested by #AKS you should use OneToOneField to connect your models to the User. You can do it like this:
class UserDetails(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
related_name='userdetail_related')
details = models.CharField(max_length=100)
class UserInformation(models.Model):
user = models.OneToOneField(
UserDetails,
related_name='userinfo_related')
info = models.CharField(max_length=100, default='this')
Then you can access UserInformation and UserDetails like this:
details = self.request.user.userdetail_related.details
info = self.request.user.userinfo_related.info
To add to the other answers, a few remarks about the layout.
For Model names, best to always use singular (UserDetails -> UserDetail), not plural. Then, for the related name of a ForeignKey, use the plural (because the reverse lookup may find more than one item that have the backwards relationship).
class UserDetail(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='details')
details = models.CharField(max_length=100)
class UserInformation(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='info')
info = models.CharField(max_length=100, default='this')
Makes it much simpler to access in the views
request.user.infos.all().first()
request.user.details.filter(info__startswith="something")
Also, if practical, add both onto the User object, because "flat is better than nested" .
If every User only has one UserDetail and one UserInformation then its best to use OneToOneFields instead.

Relationships with Django and rest framework add replace fields

My user object with rest framework has an avatar_id and a cover_id. But Instead of displaying that to the API, I want it to be the actual avatar URL and cover URL already.
My User model:
avatar_id = models.IntegerField()
cover_id = models.IntegerField()
My UserAvatar model:
id = models.IntegerField(primary_key=True)
user_id = models.IntegerField()
file_id = models.IntegerField()
My Files model:
id = models.IntegerField(primary_key=True)
filename = models.CharField(max_length=255)
Same concept with UserCover.
How do I remove the avatar_id from the results of /users/ and add a avatar field with the actual avatar filename?
I'm not sure I understand your question correctly, but here what I think the problems are. Reading your question, I assumed that you are a beginner, so I answered as such. Sorry if it's not the case.
You don't need to add the id fields, it's done automatically by Django because all tables need a primary key. You define a PK only when you need to name it something else than 'id'.
You should really read the Django tutorial which explains how to define models. User.cover_id and UserAvatar.file_id should be defined as ForeignKey. If you don't know what a foreign key is, then stop playing with Django and read a database tutorial before.
There's already a model and a set of classes to manage your users in Django. You should use them. For example, a "user profile" is the right way to extend the user model.
If you force the users to choose one avatar in a set of predefined avatars, then what you want to do is ok. If the users can choose any avatar (upload), then you should use OneToOneField or put it directly in the user model (or profile).
I don't know what is a UserCover, but here's what your models could look like:
from django.contrib.auth.models import User
class UserProfile(models.Model):
# Link to Django normal User (name, email, pass)
user = models.ForeignKey(User, unique=True)
# Any information that a user needs, like cover, wathever that is, age, sexe, etc.
avatar = models.CharField(max_length=255)
Or like this if a will be reused often :
class Avatar(models.Model):
# name = ...
# description = ...
path = models.CharField(max_length=255)
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
avatar = models.ForeignKey(Avatar, unique=True)
# other data

Taking relationships into account in Django admin

If I had a One-To-Many relationship in Django, like the Django example at http://docs.djangoproject.com/en/dev/topics/db/models/#fields, A musician can have many albums, unique to that musician.
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
How would I go about implementing the following:
In Django, have 'Musicians' as a section to manage. When you go to manage musicians, you can edit the musician, or you can go on to the albums and manage the albums only for that musician. When you make a new album, the system automatically creates it for the musician you are on.
At the moment, you would have to manage albums individually from a huge list and choose the musician in the edit screen.
This is too complicated for the django admin as is, so either you explore the customization that the docs offers for you or you might consider not using the django admin at all and just write it as a part of your web app.
Check out http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adminsite-objects.
Admin inlines is one solution - http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects - this will allow you to edit any Albums associated with the musician you are viewing or add a new one.