Django ModelForm ForeignKey query - python

I want to have a form which only offers the user to post a question for a project he is participating in.
models.py:
class Project(models.Model):
project_name = models.CharField(max_length=255, unique=True, blank=False)
def __str__(self):
return str(self.project_name)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
project = models.ManyToManyField(Project)
def __str__(self):
return str(self.user)
class Question(models.Model):
title = models.CharField(max_length=255, blank=False)
content = tinymce_models.HTMLField(blank=False)
author = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
...
def __str__(self):
return str(self.title)
class QuestionForm(ModelForm):
class Meta:
model = Question
fields = ['title', 'content', 'project']
in views.py:
form = QuestionForm()
form.fields["project"].queryset = Project.objects.filter(project_name__in=request.user.profile.project.all())
But somehow the result of the query always stays empty.
Does somebody maybe have an idea what I am missing?

Your query is over complicated. You should just use the user's projects directly:
form.fields["project"].queryset = request.user.profile.project.all())

Related

How to get specific objects based on ManyToMany field match

I'm doing a cookbook app, which help users find meal thay can do with their ingridients. I'm using Django RestFramework, and i need to return list of avaliable meals that user can do, but don't know how to do search by ingridients
My models.py:
#models.py
class Meal(models.Model):
name = models.CharField(max_length=250)
description = models.TextField(blank=True, null=True)
recipe = models.TextField()
is_published = models.BooleanField(default=False)
category = ForeignKey('Category', on_delete=models.CASCADE, null=True)
user = ForeignKey(User, verbose_name='User', on_delete= models.CASCADE)
difficulty = ForeignKey('Difficulty', on_delete=models.PROTECT, null=True)
ingridients = models.ManyToManyField('Ingridient')
class Ingridient(models.Model):
name = models.CharField(max_length=100, db_index=True)
ico = models.ImageField(upload_to="photos/%Y/%m/%d/", blank=True, null=True)
category = ForeignKey('CategoryIngridients', on_delete=models.CASCADE, null=True)
def __str__(self):
return self.name
class CookBookUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
ingridients = models.ManyToManyField('Ingridient')
serializer.py
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = Meal
fields = "__all__"
views.py
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
return Meal.objects.filter(ingridients=CookBookUser.objects.filter(user_id = self.request.user.id).ingridients)
CraftWithUsersIngridientsListAPIView isn't working and I get AttributeError 'QuerySet' object has no attribute 'ingridients', can someone help fix this?
I tried building different serializer but it doesn't help
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
user_ingredients = CookBookUser.objects.get(user=self.request.user).ingredients.all()
return Meal.objects.filter(ingredients__in=user_ingredients)
This way, you first get the CookBookUser instance for the current user, then get all of their ingredients, and finally, filter the Meal objects that contain those ingredients. The __in query lookup is used to check if the meal ingredients are in the user's ingredients.

Django Admin upload image with foreign key

I have a model Product with a User and ProductImages as foreign key.
models.py
class User(AbstractBaseUser):
...
class ProductImages(models.Model):
image_type = models.CharField(max_length=33,default='image_type')
image_file = models.ImageField(
upload_to='images/',
null=True,
blank=True,
default='magickhat-profile.jpg'
)
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
productimages = models.ForeignKey(ProductImages, on_delete=models.CASCADE)
product_title = models.CharField(max_length=255, default='product_title')
product_description = models.CharField(max_length=255, default='product_description')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
product_view = models.IntegerField(default=0)
def __str__(self):
return self.product_title
def get_absolute_url(self):
return reverse('product_change', kwargs={'pk': self.pk})
forms.py
class ProductForm(ModelForm):
productimages = forms.ImageField()
CHOICES_STATUS = (('Pronto', 'Pronto'),('Em obras', 'Em obras'),('Lançamento', 'Lançamento'),)
product_status = forms.ChoiceField(choices=CHOICES_STATUS)
product_title = forms.CharField()
product_description = forms.CharField()
class Meta:
model = Product
fields = '__all__'
admin.py
class AdminProductModel(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.filter(user_id=request.user)
kadmin.register(User, UserAdmin)
kadmin.register(Product, AdminProductModel)
But in the admin Product model the field for image is redering as select field no ImageField
My purpose is add a upload image field on django model administration.
If i use ImageField direct on Product model the field is redering ok, but i need a external table to store that image becouse is a multimage upload, so i need a foreing key.
How is the right way to that purpose.
I see other questions about that, but the majority is old versions, and is not for custom AdminSite, like me.
Django 3.2 version Class View Based
As suggested in comments i change the relationship between models like:
uptade
models.py
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product_title = models.CharField(max_length=255, default='product_title')
product_description = models.CharField(max_length=255, default='product_description')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
product_view = models.IntegerField(default=0)
def __str__(self):
return self.product_title
def get_absolute_url(self):
return reverse('product_change', kwargs={'pk': self.pk})
class ProductImages(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
image_type = models.CharField(max_length=33,default='image_type')
image_file = models.ImageField(
upload_to='images/',
null=True,
blank=True,
default='magickhat-profile.jpg'
)
forms.py
class ProductForm(ModelForm):
image_file = forms.ImageField()
CHOICES_STATUS = (('Pronto', 'Pronto'),('Em obras', 'Em obras'),('Lançamento', 'Lançamento'),)
product_status = forms.ChoiceField(choices=CHOICES_STATUS)
product_title = forms.CharField()
product_description = forms.CharField()
class Meta:
model = Product
fields = '__all__'
My question now is, how bring that field image_file from ProducImages to ProductForm?
Am guessing you want to be able to post multiple images to your database in that case you should use StackedInline to merge the two models together then you can have multiple fields in the database to upload more images. You do that through the admin.py like so:
class ProductImagesAdmin(admin.StackedInline):
model = ProductImages
class ProductAdmin(admin.ModelAdmin):
# The field your want to display
list_display = ['','']
# Here you link the models together
inlines = [ ProductImagesAdmin]
To upload multiple images from the frontend you will need a form to handle
class ProductImagesForm(forms.ModelForm):
class Meta:
model = ProductImages
fields = ['image_file']
widget = forms.ClearableFileInput(attrs={'multiple':True})
View to handle multiple images
def upload_product_images(request):
form = ProductImagesForm(request.POST, request.FILES)
files = requests.FILES.getlist['image_file']
title = request.POST['product_title']
description = request.POST['descritpion']
product = Product(product_title=title,product_description=description)
product.save()
# You would have to make some iterations through the list images in order topost
# them to your database
if form.is_valid:
for file in files:
prod_image_data = ProductImages(product=product, image=file)
prod_image_data.save()
return redirect(# redirect to anywhere you)

Is there a way to add custom fields in Django Rest Framework

I am creating a rest API for my Django blog project and I have models Post and PostLike models as you below:
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
text = models.TextField()
approved = models.BooleanField(default=False)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField( default=timezone.now, blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.text[0:100]
class PostLike(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
created_date = models.DateTimeField(default=timezone.now)
And I have a Post serialiser like
class PostSerializers(ModelSerializer):
likes_count = serializers.IntegerField(read_only=True)
class Meta:
model= Post
fields = ['id','text','author', 'approved','created_date', 'likes_count' ]
I wish the likes_count to be count for the PostLike objects with the post of the queried post. What is the right way to implement it?
The SerializerMethodField allows you to return a value based on the return value of a class method.
EDIT:
Note that the method accepts the object as a parameter. Therefore to achieve what you want, you can return:
def like_count(self, obj):
return obj.postlike_set.count()

Accessing other model field when validating model field in Django

So I have a Django auctions app, which has 4 models: Users, Listings, Bids, Comments.
When a user tries to place a bid on some listing, I want to check whether bid_amount field in Bid model is smaller than start starting_bid field in Listing model. Also, I wanted to ask, what is the best practice for this kinda stuff? AFAIK, you can validate a form field in forms.py. Thanks!
models.py
class Listing(models.Model):
"""Auction listing"""
user = models.ForeignKey(User, verbose_name='user owner', on_delete=models.CASCADE, related_name="usr_listings")
title = models.CharField(max_length=64)
description = models.TextField(max_length=160)
starting_bid = models.PositiveIntegerField()
bids_number = models.PositiveIntegerField(default=1)
img_url = models.URLField("Image URL", max_length=200, blank=True)
category = models.CharField(max_length=64, blank=True)
date_listed = models.DateTimeField(default=timezone.now)
class Meta:
verbose_name = 'auction listing'
ordering = ['-date_listed']
def __str__(self):
return self.title
def get_absolute_url(self):
print('loading... get_absolute_url')
return reverse('listing_detail', kwargs={'pk': self.pk})
class Bid(models.Model):
"""Bids made on auction listing"""
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="listing_bids")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_bidder")
bid_amount = models.PositiveIntegerField(default=None)
class Meta:
verbose_name = 'Bid'
def __str__(self):
return f'{self.bid_amount} by {self.user} on {self.listing}'
def clean(self):
super().clean()
# do something to access Listing.starting bid, and Listing.user
adding this to the clean method of Bid solve the problem for you.
from django.core.exceptions import ValidationError
...
if self.bid_amount < self.listing.starting_bid:
raise ValidationError("bid_amount must be greater than or equal to starting_bid of the listing")

How can I check whether a person is included in a model to make a Job/Post

I have created a School System-like system, that creates a job and sends them to employees/users. I'm almost done making this system however I can't seem to know what do to check if the user is included in the manager model that I created to create a job.
Also, how can a user just see all their job that was assigned to them. All I know is to use objects.allbut that might only seem to show all of the jobs that was posted, I just want the user to see the job included to them.
Here is my model.py:
from django.db import models
from profiles.models import User
# Create your models here.
class Points (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}Profile'
class Manager (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Member (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Job (models.Model):
manager = models.OneToOneField(Manager, on_delete=models.CASCADE)
member = models.OneToOneField(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField (auto_now = True)
file = models.FileField(null=True, blank=True,upload_to='job_files')
def __str__(self):
return self.title
And Views.py:
from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import Job
from profiles.models import User
# Create your views here.
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
class createjob (CreateView):
model = Job
fields = ['member','title', 'description', 'file']
How can I proceed?
Use get_queryset to filter job by user
Ex:
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
def get_queryset(self):
return Job.objects.filter(member__member=self.request.user)

Categories