Cannot add data into django ManyToManyfield - django

I have this two models:
class Posts(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="posts")
creation_date = models.DateTimeField(auto_now_add=True, blank=True)
content = models.TextField(null=True)
class User(AbstractUser):
follows = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='followed_by')
likes = models.ManyToManyField(Posts, related_name='liked_by')
pass
And I want to add a post to someone`s likes field, so i do:
def change_like(request, post_id):
post = Posts.objects.get(id=post_id)
current_user = User.objects.filter(username=request.user.username).first()
current_user.likes.add(post)
print(post.liked_by)
print(current_user.likes)
But it prints this:
network.User.None
network.Posts.None
Why is this happening? Am I adding the data correctly?

It is adding data into the ManyToMany Field. But you have printed using wrong method.
You can get all the likes of user by current_user.likes.all().
Django Docs: https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/

Related

How to use model functions in Views for multiple instances in Django?

I have a Blog Post Model and I have defined a function to calculate the no of likes.
The Model is as follows ->
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
title = models.CharField(max_length=255)
description = models.CharField(max_length=1000,null=True)
Tags = models.CharField(max_length = 255,null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
Likes = models.ManyToManyField(to=User, related_name='Post_likes')
def __str__(self):
return self.title
def likesCount(self):
return self.Likes.count()
Now I am querying the Post Model from the DB to get all the Posts as follows ->
posts = Post.objects.select_related().prefetch_related('images_set','comments_post').annotate(Count('comments_post')).all()
Here when I loop over the posts I can call the likesCount function and it gives me the correct result as well but I want to return the No of likes to the template.
How can I do that?
in your template, try this:
{{ post.likes_set.count }}
and please make the field names lowercase, they are not Classes

How to search for objects in the Django User model

I have a Profile model:
from django.contrib.auth.models import User
class Profile(models.Model):
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
birthday = models.DateField(null=True, blank=True)
bio = models.TextField(blank=True, max_length=1000)
location = models.CharField(max_length=100, blank=True)
...
And a search contacts view:
class SearchContactsView(ListView):
model = Profile
template_name = 'users/contact_search.html'
context_object_name = 'qs'
def get_queryset(self):
q1 = self.request.GET.get('contact_name')
q2 = self.request.GET.get('contact_location')
if q1 or q2:
return Profile.objects.filter(Q(first_name__icontains=q1) |
Q(last_name__icontains=q1),
location__icontains=q2)
return Profile.objects.all()
It is working fine but I would like to be able to search for contacts via the user field as well. Does anyone know a way to do that?
EDIT my user's username's are created by them when they sign up to the site and are currently uneditable. They are displayed on the admin page via a dropdown since they are a OneToOneField. I think my issue is that django recognises them only as an IntegerField('pk') but I need to somehow cast them as a string value. Am I right in thinking that, and if so how can this be achieved?
You can add to your template to allow user to input user_username and save that username to q3:
q3 = self.request.GET.get('user_username')
After that you can adjust your If condition accordingly, then change your return to something like:
Profile.objects.filter(Q(first_name__icontains=q1) |
Q(last_name__icontains=q1),
location__icontains=q2,
user__username=q3)

How can I show a dropdown in my form with the title of the objects in the table? Django ModelForm

Hi I've been trying to create a simple app for workflows or binary protocols (yes or no instructions, very helpful sometimes)
I have created a simple form with ModelForm:
class BlocForm(forms.ModelForm):
class Meta:
model = Bloc
fields = [
'description',
'loop_child'
]
and my model looks like this:
class Loopeable(models.Model):
protocol = models.ForeignKey(Protocol, on_delete=models.CASCADE, null=True)
description = models.TextField()
pointing_at = models.IntegerField()
class Bloc(models.Model):
description = models.TextField()
protocol = models.ForeignKey(Protocol, on_delete=models.CASCADE)
parent = models.ForeignKey('self',on_delete=models.CASCADE, null=True, blank=True)
loop_child = models.ForeignKey(Loopeable, on_delete=models.CASCADE, null=True, blank=True)
question = models.BooleanField(default=False)
end_bloc = models.BooleanField(default=False)
And my problem is that instead of having this loop_chile dropdown list of ugly objects I would like to get the description in the Loopeable Model, is there a way to get some data that is not just "Loopeable Object (id_number)". I didn't add my views.py in order to keep the post short, but I implemented the for by simply doing something like:
form = BlocForm(request.POST or None)
if form.is_valid(): ...rest of the code
If anyone has some ideas I will be grateful!! Thanks...

Django inline model formset with 2 models

First of all, please forgive for my newbie questions. I did copy most of the code, and try to understand from Django documents.
Code as below:
models.py
class Order(models.Model):
ORDER_CHOICES = (
('import', 'IMPORT'),
('export', 'EXPORT')
)
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
order_type = models.CharField(max_length=6, choices=ORDER_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
class Item(models.Model):
def random_barcode():
return str(random.randint(10000000, 99999999))
type = models.ForeignKey(Type, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE, null=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
item_name = models.CharField(max_length=50, help_text='Name of goods, max 50 characters')
barcode = models.CharField(max_length=8, default=random_barcode, unique=True)
production_date = models.DateField()
expired_date = models.DateField()
def __str__(self):
return self.item_type
forms.py
class ItemForm(ModelForm):
class Meta:
model = Item
exclude = ['order',]
fields = ['type', 'brand', 'item_name', 'production_date', 'expired_date']
ItemFormSet = inlineformset_factory(Order, Item, form=ItemForm, extra=1)
views.py
class CreatePO(CreateView):
model = Order
context_object_name = 'orders'
template_name = 'storages/create_po.html'
fields = ['order_type', 'storage',]
*#dun't know how to write below code....*
1st question: how to use inline formset to write the CreatePO view?
2nd question: I need my create PO template as below picture, how to add a "Quantity" field?
This kind of template need Javascript, right? Any alternative solution? I have no knowledge with javascript.
First of all, move the def random_barcode(): before def __str__(self): it looks so ugly formated code.
Then let's have a look in your pic, if you haven't proper experience with Javascript you can use Admin Views from Django, it's much more simple and supported by Django 2.1. Read more if you would like to give permission to everyone in a admin-views page https://docs.djangoproject.com/el/2.1/releases/2.1/#model-view-permission
So quantity will be just added inside Item class
quantity = models.PositiveSmallIntegerField(default=1)
Also for your form, in my opinion, you need modelform_factory, so I suggest to read this one https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#modelform-factory-function

Django composite unique on multiple model fields

Let us say I have a model for social network posts, users and likes:
class Post(models.Model):
submitter = models.ForeignKey(User, null=False, default=None)
content = models.CharField()
date = models.DateField()
with_likes = PostLikeCountManager()
objects = models.Manager()
class Like(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
time = models.DateTimeField(auto_now_add=True)
It would be helpful to think of Post model as representing a Facebook post. Now, I would like to limit one like per post per user. How do I achieve that? One way would be to create a composite primary key on (user, post) attributes of Like class. I don't know how to achieve that in Django. The other would be to use unique=True on two attributes simultaneously. Is that possible?
Thanks.
Yes, use unique_together:
class Like(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
time = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ('user', 'post')
unique_together will be deprecated in the future version, instead you could apply UniqueConstraint. This and this link gives example code.
class Like(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
time = models.DateTimeField(auto_now_add=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'post'], name='unique_user_post'),
]