New ManyToManyField object is not adding - python

I am building a BlogApp AND i made a feature of Favorite Users in the ManyToManyField.
It means user_1 can add multiple favorite users in one field. I build a view to add users.
BUT when i create an instance to store favorite users from Admin before adding favorite users from site AND then if i add favorite users from site then they are adding. BUT if there is not already a instance of request.user's FavouriteUsers in Admin then it is not adding and creating a new object.
So, A new object for storing favorite users of request.user is not adding, AND if object is already there then they are adding.
models.py
class FavoriteUsers(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
favorite_users = models.ManyToManyField(User, related_name='favorite_users', blank=True)
views.py
def AddFavUsers(request,user_id):
obj = FavoriteUsers.objects.filter(user=request.user)
user = get_object_or_404(User,id=user_id)
for ob in obj:
ob.favorite_users.add(user)
ob.user.add(request.user)
ob.save()
return redirect('home')
Image of already created object
When object is already , manually created then favorite users are adding BUT if it is not then new object is not creating.
Any help would be much Appreciated.
Thank You in Advance.

Your view is basically adding the user to all FavoriteUsers that are linked to the User. But it is not said at all that there are such FavoriteUsers.
We thus can construct a FavroiteObject with:
def AddFavUsers(request,user_id):
obj = FavoriteUsers.objects.create(
user=request.user
)
obj.favorite_users.add(user_id)
# …
the modeling is also a bit odd, since we here create a third table, it makes more sense to construct a model Favorite with two ForeignKeys that thus acts as a junction table. So this should look like:
from django.conf import settings
class Favorite(models.Model):
user_to = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='favorites_from'
)
user_from = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='favorites_to'
)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user_from', 'user_to'], name='favorite_only_once')
]
If you then want to make a user_id a favorite of the logged in user, you can work with:
from django.contrib.auth.decorators import login_required
#login_required
def AddFavUsers(request, user_id):
Favorite.objects.create(user_from=request.user, user_to_id=user_id)
# …
You can then obtain the favorite users of a user with:
User.objects.filter(favorites_from__user_from=my_user)
where my_user is the user from which you want to obtain the favorite users.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

The ManyToMany field already handles this. You can add a favorite_users property to your User model, which will point to the User model and Django will create the connecting table. Beware of the symmetrical parameter, if you leave it out it'll be a bidirectional relation.
class MyUser(models.Model):
...
favorite_users = models.ManyToManyField("MyUser", symmetrical=False, blank=True)
If you still want to write the connecting model yourself, check out the through parameter.

Related

How can you add to a ManyToManyField extension of the default Django User model?

For my app, I want to add one extra ManyToManyField to the default User model (django.contrib.auth.models.User). This extra field is called 'favorites' and the posts favorited by a user should go there. This is what I have:
class Favorite(models.Model):
user = models.OneToOneField(User, related_name='favorites', on_delete=models.CASCADE)
favorites = models.ManyToManyField(Recipe, related_name='favorited_by')
This is what I get when trying to add to 'favorites' from the shell.
# imported Recipe, Favorite, User(default)
>>> recipe1 = Recipe.objects.all()[0]
>>> me = User.objects.all()[0]
>>> me.favorites.add(recipe1)
django.contrib.auth.models.User.favorites.RelatedObjectDoesNotExist: User has no favorites.
# Just checking if the the User object, me, has a 'favorites' attribute
>>> 'favorites' in dir(me)
True
What is the correct way to add a Recipe object to this 'favorites' field?
For more reference, I did something similar how I handled Friendships between users, but it was a bit simpler since I wasn't extending the User model. The code for that is below and works fine:
class Friend(models.Model):
users = models.ManyToManyField(User)
current_user = models.ForeignKey(User, related_name='owner', null=True, on_delete=models.CASCADE)
#classmethod
def make_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user=current_user
)
friend.users.add(new_friend)
#classmethod
def lose_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user=current_user
)
friend.users.remove(new_friend)
Resolved. My solution is below, but I'm not sure if this is good practice.
django.contrib.auth.models.User.favorites.RelatedObjectDoesNotExist: User has no favorites.
The User model may have the 'favorites' field, but I needed to actually fill it with a 'Favorite' object. I did this by writing a function in my views.py:
def add_favorite(request, pk):
# Check if the user has a favorites field. If not create one and add. If yes, just add
user_favorites, created = Favorite.objects.get_or_create(
user=request.user
)
recipe = get_object_or_404(Recipe, pk=pk)
user_favorites.favorites.add(recipe)
This seems to work and I can access a user's favorites now, but I maybe this isn't good practice. With my method, new models that are created do not have a 'Favorite' object within it. That will only get created when a user decides to add a favorite recipe and the above view will create one if it doesn't already exist.

Django - Create a User instance from another model that uses User as a OneToOne

I think an example will explain it better.
Lets say I am making an application for various Libraries to show what books they have available.
The site will have Users that are registered through the built-in user registration system and User model. These Users (think of it like library members) can visit the Libraries and browse and checkout the available books.
The site will also allow Libraries to register themselves, and part of that registration is declaring a "Librarian," a person who controls what books are available in their particular Library.
I want to create a Library Registration Form that takes the information of this Library and its Librarian and not only creates an instance of the Library model, but also an instance of the User model. The Librarian automatically becomes a User.
This is my current models.py:
class Library(models.Model):
name = models.CharField(max_length=200)
website = models.URLField()
street = models.CharField(max_length=200)
city = models.CharField(max_length=200)
state_or_province = models.CharField(max_length=200)
postal_code = models.CharField(max_length=200)
date_registered = models.DateField(auto_now_add=True)
librarian = models.OneToOneField(User, on_delete=models.CASCADE)
#receiver(post_save, sender=Library)
def create_user(sender, instance, created, **kwargs):
if created:
User.objects.create(user=instance)
instance.user.save()
I am currently lost as to how to build views.py and forms.py. I am not even sure that model is built correctly, since I need the form to include not only the Library information, but also User information (first_name, last_name, email, password...). Do I need to duplicate that information in the Library model in order for it to pass to the form?
Basically, I don't have a good grasp of how to models connect to one another via Django tools and files. If anyone can point me in the right direction, I would appreciate it. Thanks!
You can do this with standard django, however it is quite long.
Or you can use django-extra-views, to make your life nice and easy.
class LibrarianInline(GenericInlineFormSet):
model = User
fields = '__all__'
class LibraryInline(CreateWithInlinesView):
model = Library
inlines = [LibrarianInline]
fields = '__all__'
There is also a simpler way of doing it with standard django. Force the librarian to be created first and only then allow them to create a Library.
urls.py
urlpatterns = [
url(r'^/create-librarian$',
LibrarianCreateView.as_view(), name='create_librarian'),
url(r'^/create-library/for/(?P<librarian_id>\d+)$',
LibraryCreateView.as_view(), name='create_library'),
]
views.py
from django.shotcuts import reverse
from django.generic.views import CreateView
class LibrarianCreateView(CreateView):
model = User
def form_valid(self, form):
librarian = form.save(commit=True)
return redirect('create_library', {'librarian_id': librarian.id})
class LibraryCreateView(CreateView):
model = Library
def form_valid(self, form):
library = form.save(commit=False)
librarian_id = self.kwargs['librarian_id']
# You can do validation here if you fancy
library.librarian_id = librarian_id
library.save()
return self.get_success_url()
By requiring the id of the Librarian to create the Library, it prevents it being created without a librarian.

Incorporating "Like Post" feature

Hey so I am making a color scheme posting site where people can register and post color schemes they come up with. So far everything is working great, the only thing I have left to do is add a "Like Post" feature. I'm wondering what the best way to implement this would be.
I have two ideas on how this could be done, the first is add an additional field to both the ColorSet (posts) and the User models (for the user model I would set up a new model with a OneToOne relationship to add onto the User model) which would record users that have each single post, and which posts each user has liked to keep track of everything.
So this could look something like this:
from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from django.contrib.auth import get_user_model
User = get_user_model()
# Create your models here.
class ColorSet(models.Model):
user = models.ForeignKey(User,related_name='colorset')
published_date = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=50,blank=False)
color_one = models.CharField(max_length=6,blank=False,default='cccccc')
color_two = models.CharField(max_length=6,blank=False,default='ffffff')
color_three = models.CharField(max_length=6,blank=False,default='e5e5e5')
color_four = models.CharField(max_length=6,blank=False,default='f0f0f0')
color_five = models.CharField(max_length=6,blank=False,default='bababa')
liked_by = models.IntegerField(blank=True)
def publish(self):
self.save()
def get_absolute_url(self):
return reverse('index')
def __str__(self):
return self.name
user model:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserStats(models.Model):
user = models.OneToOneField(User)
liked_sets = models.IntegerField(blank=True)
def __str__(self):
return self.user.username
In this first option I would have the new model fields (liked_sets and liked_by) be equal to lists containing the ok's of all the Color Sets each user has liked and all the users who have liked each post respectively.
The other way that I'm thinking about would be to just create an entirely new model that tracks the likes for each color set post (not totally sure how this model would look yet exactly).
Aside from which is easier, I wondering which makes more sense from a technical standpoint? Will one of these two options take up more space or create heavier server load?
Thanks for the help.
As far as I understand your problem, it can be broken in two parts.
Maintaining the total number of likes on a model ColorSet.
Keeping the track of all those users who liked a single instance of ColorSet.
Now if I understand your problem correctly(correct me if I'm wrong), when you say:
new model fields (liked_sets and liked_by) be equal to lists containing the ok's of all the Color Sets each user has liked and all the users who have liked each post respectively.
you intend to create a field in your database which would simply store a list of pks of all the people who've liked a ColorSet model instance. Even if you don't intend to do that, still an IntegerField to store such information is(in my humble opinion) somewhat wrong.
Now why you wouldn't want to do that? It's because relational databases are made to recognize the relations between tuples of information and enhance the processing by creating relations. That is why we use relations like OneToOneField and ForeignKey. They make the processing way faster. If we were to simply store the pk values in a Field, further search them in our database to retrieve information, that would be something really slow.
Now I suppose what you are looking for is ManyToManyField.
In your problem, you will simply map the ManyToManyField it to the User model.
It would look something like:
class ColorSet(models.Model):
user = models.ForeignKey(User,related_name='colorset')
published_date = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=50,blank=False)
color_one = models.CharField(max_length=6,blank=False,default='cccccc')
color_two = models.CharField(max_length=6,blank=False,default='ffffff')
color_three = models.CharField(max_length=6,blank=False,default='e5e5e5')
color_four = models.CharField(max_length=6,blank=False,default='f0f0f0')
color_five = models.CharField(max_length=6,blank=False,default='bababa')
liked_by = models.IntegerField(blank=True)
#add a simple ManyToManyField which will hold all the users who liked this colorset
likers = models.ManyToManyField(User , related_name = 'liked_colorsets')
def publish(self):
self.save()
def get_absolute_url(self):
return reverse('index')
def __str__(self):
return self.name
and remove your UserStats model to
Now use the following code outline structure to access the information from the database.
1) To get the ColorSets liked by a User:
#obtain any user model object; for example: user_object = User.objects.get(...)
user_object.liked_colorsets.all()
#a queryset with all the liked colorsets is returned.
2) To get the Users who liked a ColorSet:
#obtain any colorset model object; for example: colorset_object = ColorSet.objects.get(...)
colorset_object.likers.all()
#a queryset with all the Users who liked this colorset is returned.
One more thing that I would like to add here. After a User likes a ColorSet, you would obviously want to add this User to the likers field in your ColorSet model(and increment the liked_by field; I assume you'll manage that). To add a User in the likers field:
#obtain any colorset model object; for example: colorset_object = ColorSet.objects.get(...)
#obtain the user model object of the user who liked this colorset in user_object
#and do
colorset_object.likers.add(user_object)
Read more about adding the models in ManyToManyField here in docs.
Hope this helps. Thanks.

How to check if user is in a certain table

I have my user table in django, and to differ all the users I created two tables, (Teacher and Student).
Both tables are getting an fk from user
So, in order to make authorization how do I check if one's user is in a certain table.
I need to check it this way
def test_func(self):
return self.request.user.check..if..it..exists..in..table
My models are like this.
class Teacher(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL)
This depends on how your models are set up.
If your Teacher model looks something like this;
class Teacher(models.Model):
user = models.ForeignKey(User)
Then you should be able to check if the user is a teacher by using the implicit backref;
self.request.user.teacher_set.exists()
As the question has been updated to show that the model is slightly different than I anticipated, here is an update.
class Teacher(models.Model):
user = models.OneToOneField(User)
Which means that the backref will be a little different.
hasattr(self.request.user, "teacher")
As you've mentioned that you are doing this inside a django template, I'm pretty sure that the following will work:
{% if user.teacher %}
Since you haven't posted your models, I am giving you a rough idea how to do it.
in your views.py -
from .models import Teacher,Student
def test_func(request):
user = request.user
if (Teacher.objects.filter(user=user).count() > 0) or (Student.objects.filter(user=user).count > 0):
#do your stuffs here..
One way is to query both tables:
teacher = Teacher.objects.filter(user=self.request.user)
student = Student.objects.filter(user=self.request.user)
if teacher or student:
# do what you want.
If you put in your relation the argument "related_name" you can do it using inverse relationship
class SomeTable(models.Model):
user = models.ForeignKey(
User, #Your user model or Django one
verbose_name = "User",
related_name = "inverse_relation_name"
)
Then you have to call using keyword arguments for the filters:
SomeTable.inverse_relation_name.filter(id=self.request.user.id) #You will get a queryset
Or
SomeTable.inverse_relation_name.get(id=self.request.user.id) # You will get the object or a exception

Login form for custom users in django

I have created a custom User SignUp Class.
class SignUp(models.Model):
userId = models.CharField(max_length=8, blank=False, unique=True)
Name = models.CharField(max_length=200)
VehicleNumber= models.CharField(max_length=12)
ContactNum = models.IntegerField(default=0)
def __unicode__(self):
return smart_unicode(self.Name)
I have used this to create a Sign up form. Now, I am not getting a way for creating user login. Note: I can't use django in-built users because they don't have a field for images.
You can extend the built-in django user, by adding OneToOneField.
YourCustomUser(models.Model):
user = models.OneToOneField(User,related_name='profile')
image = models.ImageField()
//put here your others attributes
If you have YourCustomUser instance and want to access to User built-in instance
your_custom_instance.user
If you have User built-in instance and want to retrieve e.i the image
user.profile.image
You can use and extend the built-in model User. The shortest path is
from django.contrib.auth.models import User
from django.db import models
class UserWithPhoto(User):
image = models.ImageField()
but is better practice to use User Profiles, you can read about it in: User authentication in Django
You can read about this in Django user profile and here Extending the User model with custom fields in Django.
Why is better user profile over extending the User model directly?
If you extend the User model you will have the changes applied to all you users. Think about this, you could have Administrators, Developers, Reviwers, even Guests, all of them might have some field that others don't, so a different profile for each one is the better solution than subclassing User for each one, or even worst create a single class with all fields you need for all kinds of users (only think about it hurts ).

Categories

Resources