Relationships with Django and rest framework add replace fields - django

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

Related

How to define models in django that provides custom values based on pre-selection for a field?

Given the following model that stores the user's wish list for reading books:
class ReadingList(models.Model):
user_id = models.ForeignKey(UserInfo, on_delete=models.DO_NOTHING, null=False, blank=False, default=None, db_column='user_id')
book= models.CharField(max_length=255, blank=False)
creation_time = models.DateTimeField(blank=True)
class Meta:
unique_together = (('user_id', book),)
I want to create a model that helps in tracking the time spent in the reading the book on different days which looks something like this:
class ReadingTracker(models.Model):
user_id = models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='user', blank=False, db_column='user_id')
book= models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='book-to-read', blank=False, db_column='book')
time = models.DateTimeField(blank=True)
time_spent = models.floatfield()
On the client-side (corresponding to ReadingTracker) for both the fields user_id and book
I see that ReadingList object (1), ReadingList object (2), ... are listed. But, this is not working as expected.
What I want to achieve are the following:
For user_id field I want to see the something like dummy_uid1, dummy_uid2, ... to be listed.
Consider dummy_uid1 wants to read book1 and book2 whereas dummy_uid2 wants to read book1 and book3.
When dummy_uid1 is selected as user_id, I want only book1 and book2 to be listed for selection.
How do I define the model in django rest framework to achieve this?
Any suggestions related to the above would be much appreciated and thank you in advance.
There are two parts to this question:
If you want to see a different value than ReadingList object (1) then you need to define the __str__ value of your model, you can do this like so:
class ReadingList(models.Model):
...
def __str__(self):
return f'{self.user_id}' # return whatever string you want to display
If you want to just display the books for a particular user then you can use a filter() (see the Django documentation):
reading_list = ReadingList.objects.get(...)
ReadingTracker.objects.filter(user_id=reading_list)
However, I would add that you have a user_id on your ReadingList object which does seem to connect to a User model, but your user_id on ReadingTracker is a ForeignKey relation to ReadingList, which is confusing. I would suggest renaming the field or actually making it link to the User model (though this is unnecessary as you can still filter by User through the ReadingList model).

How to add custom filed to Django User Model

I am working on the project using django 1.9.
I need to add a field to the user model 'Auth_user' table, the field which i want can be another primary key and act here as foreign key in the 'auth_user'.
I searched a lot but fails. Can any buddy provide me some example how to achieve this like how to to add fields to 'auth_user'
You can substitute the user model entirely as described in doc. Here is an example:
AUTH_USER_MODEL = 'myapp.MyUser'
to your settings.py, and add following to your model:
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
another_object = models.ForeignKey(OtherModel..
just make a new moel with a user foreign key
class Post (models.Model):
title = models.CharField(max_length=80)
slug= models.SlugField(unique=True)
content = models.TextField()
user_creator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
there you can use as primary key the id of the post, or the slug (unique), and it can be linked to a user, if you need one to one relationship see this or many to many relationship see this
Maybe you just need to extend de model user
https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#extending-the-existing-user-model

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.

Django user audit

I would like to create a view with a table that lists all changes (created/modified) that a user has made on/for any object.
The Django Admin site has similar functionality but this only works for objects created/altered in the admin.
All my models have, in addition to their specific fields, following general fields, that should be used for this purpose:
created_by = models.ForeignKey(User, verbose_name='Created by', related_name='%(class)s_created_items',)
modified_by = models.ForeignKey(User, verbose_name='Updated by', related_name='%(class)s_modified_items', null=True)
created = CreationDateTimeField(_('created'))
modified = ModificationDateTimeField(_('modified'))
I tried playing around with:
u = User.objects.get(pk=1)
u.myobject1_created_items.all()
u.myobject1_modified_items.all()
u.myobject2_created_items.all()
u.myobject2_modified_items.all()
... # repeat for >20 models
...and then grouping them together with itertool's chain(). But the result is not a QuerySet which makes it kind of non-Django and more difficult to handle.
I realize there are packages available that will do this for me, but is it possible to achieve what I want using the above models, without using external packages? The required fields (created_by/modified_by and their timefields) are in my database already anyway.
Any idea on the best way to handle this?
Django admin uses generic foreign keys to handle your case so you should probably do something like that. Let's take a look at how django admn does it (https://github.com/django/django/blob/master/django/contrib/admin/models.py):
class LogEntry(models.Model):
action_time = models.DateTimeField(_('action time'), auto_now=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.TextField(_('object id'), blank=True, null=True)
object_repr = models.CharField(_('object repr'), max_length=200)
action_flag = models.PositiveSmallIntegerField(_('action flag'))
change_message = models.TextField(_('change message'), blank=True)
So, you can add an additional model (LogEntry) that will hold a ForeignKey to the user that changed (added / modified) the object and a GenericForeignKey (https://docs.djangoproject.com/en/1.7/ref/contrib/contenttypes/#generic-relations) to the object that was modified.
Then, you can modify your views to add LogEntry objects when objects are modified. When you want to display all changes by a User, just do something like:
user = User.objects.get(pk=1)
changes = LogEntry.objects.filter(user=user)
# Now you can use changes for your requirement!
I've written a nice blog post about that (auditing objects in django) which could be useful: http://spapas.github.io/2015/01/21/django-model-auditing/#adding-simple-auditing-functionality-ourselves

Django :Suggestion for django model

I am using django models to create my database .
here is my User Class
class User(models.Model):
user_name = models.CharField(max_length=100,null = False)
first_name = models.CharField(max_length=100)
middle_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
tags = here what to do ?
now i am planning to add tags for User so that user can select the tags (it can be more then one also )
Here is my Tags Class
Class Tags(models.Model)
tag = models.CharField()
my question is which relation should i use for the reference Tags from User table (Foreign key or Manytomany )
Note: In future i will search the users based on tags so please suggest me the better way to do this
Use a ManytoMany relationship: different users may use the same tags and a single User will have several tags:
tags= models.ManyToManyField(Tags, verbose_name="list of tags")
Anyway, you don't have to implement a Model for the User, there is a User model that comes with django. See the docs:
Django docs
Django book