How to set initial value of ForeignKey dynamically in CreateView? - python

I want to set dynamically initial value of ForeignKey in CreateView. But is there any simple way to do this ?
And I tried like this (as answer of this link). But it is not working.
How can I pass the album(ForeignKey) to the field in CreateView?
models.py
class Album(models.Model):
credit = models.CharField(max_length=250)
album_title = models.CharField(max_length=100)
logo = models.FileField()
def get_absolute_url(self):
return reverse('picture:detail', kwargs={'pk': self.pk})
def __str__(self):
return self.album_title + ' - ' + self.credit
class Item(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(choices=TYPE_CHOICES, max_length=1)
caption = models.CharField(max_length=100)
class Meta:
ordering = ('upload_date', 'caption')
def get_absolute_url(self):
return reverse('picture:item-detail', kwargs={ 'id': self.album_id , 'pk': self.pk})
def __str__(self):
return self.caption
views.py
class ItemCreate(CreateView):
model = Item
fields = ['album', 'file_type', 'caption']
def get_initial(self):
album = get_object_or_404(Album, pk=self.kwargs.get('album.pk'))
return {
'album': album,
'file_type': 't',
}
urls.py
urlpatterns = [
# /picture/<album_id>/
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
# /picture/<album_id>/<pic_id>
url(r'^(?P<id>[0-9]+)/(?P<pk>[0-9]+)/$', views.ItemDetailView.as_view(), name='item-detail'),
# /picture/<album_id>/pic/add
url(r'^(?P<id>[0-9]+)/pic/add/$', views.ItemCreate.as_view(), name='item-add'),
]

If you want to get the object(album) where album.pk == id ( id an URL parameter of 'item-add' ) then try this,
class ItemCreate(CreateView):
model = Item
fields = ['album', 'file_type', 'caption']
def get_initial(self):
album = get_object_or_404(Album, pk=self.kwargs['id'])
return {
'album': album,
'file_type': 't',
}

Related

django inline_formset get pk from foreign key item before save to make a form validation

django noob here, well i´ve be dealing with this for over a day and i cant figure out, so decide to post, any help, thanks!
have this project and i want to validate this formset, this formset have a select with product list, and quantiy, i need to validate if when saving new data, that the product selected have o not stock enough and raise a form validation error, but i cant figure out how to get the pk from the related model, already read several articles but cant make it work
this models.py
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
description = models.CharField(max_length=50)
stock = models.IntegerField(default='0')
def __str__(self):
return self.description + '(' + str(self.stock)+')'
def save(self, *args, **kwargs):
self.description = self.description.title()
super(Product, self).save(*args, **kwargs)
class Invoice(models.Model):
invoice_id = models.AutoField(primary_key=True)
client_id = models.ForeignKey(Client, on_delete=models.CASCADE)
date = models.DateTimeField()
status = models.BooleanField(default=True)
def __str__(self):
return str(self.invoice_id)
class InvoiceItem(models.Model):
invoice_id = models.ForeignKey(Invoice, on_delete=models.CASCADE)
product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
qty = models.IntegerField(default='0')
price = models.DecimalField(max_digits=10, decimal_places=2, default=0)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['invoice_id', 'product_id'], name='unique invoiceitem')
]
these are my forms.py
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoice
exclude = ['status']
labels = {
'client_id': ('Cliente'),
'date': ('Fecha'),
}
widgets = {
'date':forms.DateInput(
attrs={'type': 'date'},
),
}
class InvoiceItemForm(forms.ModelForm):
class Meta:
model = InvoiceItem
fields = ['product_id', 'qty', 'price', 'price']
labels = {
'product_id': ('Producto'),
'qty': ('Cantidad'),
'price': ('Precio'),
}
widgets = {
'price': forms.NumberInput(attrs={'step': '0.01'}),
}
my view.py
def create(request):
forminvoice = InvoiceForm(request.POST or None)
formset = inlineformset_factory(
Invoice, InvoiceItem, form=InvoiceItemForm, min_num=1, extra=0, can_delete=True)
if request.method == "POST":
if forminvoice.is_valid():
forminvoice = forminvoice.save(commit=False)
forminvoice.date = datetime.datetime.now()
forminvoice.save()
formset = formset(request.POST, instance=forminvoice)
if formset.is_valid():
formset.save()
return redirect('/create_order')
context = {
"forminvoice": forminvoice,
"formset": formset,
}
return render(request, "partials/create.html", context)
alredy tried official inline and yt, and want to find a way to do it
also tried the clean() in forms.py or through the views
def clean(self): cdata = super().clean() Product.objects.get(product_id=cdata.get("product_id_id")).stock product_id = cdata.get("product_id_id") stock = Product.objects.get(product_id=product_id).stock if qty > stock: raise forms.ValidationError("No")
forms.py
product = Product.objects.get(product_id=form.product_id_id)

Recipe creation and modification not working correctly

Please help! I'm trying to implement a recipe creation function. The data is created and then you can get it, with a post request, changes are also made. But when creating a site, a redirect does not occur and gives such an error.
AttributeError: Got AttributeError when attempting to get a value for field amount on serializer AmountIngredientForRecipePostSerializer. The serializer field might be named incorrectly and not match any attribute or key on the Ingredient instance. Original exception text was: 'Ingredient' object has no attribute 'amount'.
view
class RecipesViewSet(viewsets.ModelViewSet):
queryset = Recipe.objects.all().order_by('id')
filter_backends = (DjangoFilterBackend,)
filter_class = RecipeFilter
pagination_class = PagePagination
permission_classes = (OwnerOrAdminOrSafeMethods,)
def get_serializer_class(self):
if self.request.method == 'GET':
return RecipeGetSerializer
return RecipePostSerializer
#staticmethod
def post_or_delete(request, model, serializer, pk):
if request.method != 'POST':
get_object_or_404(
model,
user=request.user,
recipe=get_object_or_404(Recipe, id=pk)
).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
serializer = serializer(
data={'user': request.user.id, 'recipe': pk},
context={'request': request})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
serialaizer
class AmountIngredientForRecipePostSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=Ingredient.objects.all())
amount = serializers.IntegerField(min_value=1)
class Meta:
model = AmountIngredient
fields = ('id', 'amount')
class RecipePostSerializer(serializers.ModelSerializer):
author = CostomUserSerializer(read_only=True)
ingredients = AmountIngredientForRecipePostSerializer(many=True)
tags = serializers.PrimaryKeyRelatedField(
queryset=Tags.objects.all(), many=True)
image = Base64ImageField()
class Meta:
model = Recipe
fields = ('id', 'author', 'ingredients', 'tags',
'image', 'name', 'text', 'cooking_time')
#staticmethod
def create_ingredients_tags(recipe, ingredients, tags):
for ingredient in ingredients:
AmountIngredient.objects.create(
recipe=recipe,
ingredient=ingredient['id'],
amount=ingredient['amount']
)
for tag in tags:
recipe.tags.add(tag)
def create(self, validated_data):
ingredients = validated_data.pop('ingredients')
tags = validated_data.pop('tags')
recipe = Recipe.objects.create(
author=self.context.get('request').user,
**validated_data
)
self.create_ingredients_tags(recipe, ingredients, tags)
return recipe
def update(self, recipe, validated_data):
recipe.tags.clear()
AmountIngredient.objects.filter(recipe=recipe).delete()
ingredients = validated_data.pop('ingredients')
tags = validated_data.pop('tags')
self.create_ingredients_tags(recipe, ingredients, tags)
return super().update(recipe, validated_data)
def validate(self, data):
ingredients = self.initial_data.get('ingredients')
ingredients_list = []
for ingredient in ingredients:
ingredient_id = ingredient['id']
if ingredient_id in ingredients_list:
raise serializers.ValidationError({
'ingredient': 'already have'
})
ingredients_list.append(ingredient_id)
return data
def to_representation(self, object):
data = super().to_representation(object)
data["image"] = object.image.url
return data
models
class Recipe(models.Model):
tags = models.ManyToManyField(Tags, verbose_name='Теги')
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='author',
)
ingredients = models.ManyToManyField(
Ingredient,
through='AmountIngredient',
through_fields=('recipe', 'ingredient'),
related_name='ingredients',
)
name = models.CharField(
max_length=150,
db_index=True,
)
image = models.ImageField(
upload_to='recipes/',
text = models.TextField()
cooking_time = models.PositiveSmallIntegerField(
validators=[MinValueValidator(
1,
message='min 1 minute'
)],
verbose_name='time to cook'
)
def __str__(self):
return self.name
class AmountIngredient(models.Model):
recipe = models.ForeignKey(
Recipe,
on_delete=models.CASCADE,
)
ingredient = models.ForeignKey(
Ingredient,
on_delete=models.CASCADE,
)
amount = models.PositiveSmallIntegerField(
validators=(
MinValueValidator(
1, 'Min 1.'
),
),
verbose_name='Ingredients count'
)
class Meta:
constraints = (
models.UniqueConstraint(
fields=['ingredient', 'recipe'],
name='unique_ingredient'
),
)
class Ingredient(models.Model):
name = models.CharField(
max_length=200,
db_index=True,
)
measurement_unit = models.CharField(
max_length=200,
)
def __str__(self):
return self.name
I tried to solve it by changing the field in the serializer, but it didn't work

Cant filter by category

I am trying to make a filtering system by category. Whenever I try to click one of my category it always shows all the products but I want to show filter wise category list if I click Smart Phone it will only show me smartphone category products.
Here is my Models.Py:
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
#staticmethod
def get_categories():
return Category.objects.all()
class Brand(models.Model):
name= models.CharField(max_length=100)
def __str__(self):
return self.name
def get_brands():
return Brand.objects.all()
class Product(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE, default='UNCATEGORIZED')
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, default='NoBrand')
price = models.FloatField()
#staticmethod
def get_all_products():
return Product.objects.all()
#staticmethod
def get_products_by_category(category_id):
if category_id:
return Product.objects.filter(category=category_id)
else:
return Product.get_all_products()
Here Is my Views.py:
from django.shortcuts import render
from .models import *
# Create your views here.
def index(request):
products = None
cats = Category.get_categories()
brands = Brand.get_brands()
categoryID = request.GET.get('category')
if categoryID:
products = Product.get_products_by_category(categoryID)
else:
products = Product.get_all_products()
args = {
'products':products,
'cats': cats,
'brands': brands
}
return render(request, 'Home/index.html', args)
Please help I am very confused here and also got stuck :(
Try this filter in your views.py
if categoryID:
products=Product.objects.filter(category__name=categoryID)
else:
products = Product.get_all_products()
Here's a possible answer for your problem. I have slightly modified your models.py and views.py file. Here's the result :
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'cat'
verbose_name_plural = 'cats'
def __str__(self):
return self.name
class Brand(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'brand'
verbose_name_plural = 'brands'
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=100, db_index=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, default='UNCATEGORIZED')
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, default='NoBrand')
price = models.FloatField()
slug = models.SlugField(max_length=100, db_index=True)
class Meta:
ordering = ('name',)
index_together = (('id', 'slug'),)
def __str__(self):
return self.name
By creating a slug field that is unique, you are creating an index. Now let's look at the modified views.py file :
from django.shortcuts import render, get_object_or_404
from .models import *
def product_list(request, cat_slug=None):
cat = None
cats = Category.objects.all()
brand = None
brands = Brand.objects.all()
if cat_slug:
cat = get_object_or_404(Category, slug=cat_slug)
products = products.filter(category=cat)
args = {'products': products,
'cats': cats,
'cat': cat,
'brands': brands
}
return render(request, 'Home/index.html', args)
We use the optional cat_slug parameter to optionally filter products by a given category. The idea is the same if you want to filter by Brand. Just don't forget to add a brand in your context.

How to get object from previous view(CBV) in Django?

I tried to get the object value in CreateView from previous DetailView. But Failed. Is there any simple way to do this?
In this code, how can I replace this '???'(in CreateView) by an album object where album.pk == id according to 'item-add'(url(r'^(?P<id>[0-9]+)/pic/add/$', views.ItemCreate.as_view(), name='item-add'))
models.py
class Album(models.Model):
credit = models.CharField(max_length=250)
album_title = models.CharField(max_length=100)
logo = models.FileField()
def get_absolute_url(self):
return reverse('picture:detail', kwargs={'pk': self.pk})
def __str__(self):
return self.album_title + ' - ' + self.credit
class Item(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(choices=TYPE_CHOICES, max_length=1)
caption = models.CharField(max_length=100)
class Meta:
ordering = ('upload_date', 'caption')
def get_absolute_url(self):
return reverse('picture:item-detail', kwargs={ 'id': self.album_id , 'pk': self.pk})
def __str__(self):
return self.caption
views.py
class DetailView(generic.DetailView):
model = Album
template_name = 'picture/detail.html'
class ItemCreate(CreateView):
model = Item
fields = ['album', 'file_type', 'caption']
def get_initial(self):
album = ???
return {
'album': album,
'file_type': 't',
}
urls.py
urlpatterns = [
# /picture/<album_id>/
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
# /picture/<album_id>/<pic_id>
url(r'^(?P<id>[0-9]+)/(?P<pk>[0-9]+)/$', views.ItemDetailView.as_view(), name='item-detail'),
# /picture/<album_id>/pic/add
url(r'^(?P<id>[0-9]+)/pic/add/$', views.ItemCreate.as_view(), name='item-add'),
]
The primary key is passed as an id URL parameter, so you can access this with self.kwargs:
from django.shortcuts import get_object_or_404
class ItemCreate(CreateView):
model = Item
fields = ['album', 'file_type', 'caption']
def get_initial(self):
album = get_object_or_404(Album, pk=self.kwargs['id'])
return {
'album': album,
'file_type': 't',
}

Django ListView filter objects

I have a simple structure Shop_list --> Product_list --> Product_detail
I want to filter Product class object by slug field, but I see zero products.
I think that the problem in get_queryset()
views.py
class HomePageView(ListView):
model = Shop
template_name = 'blog/shop_list.html'
page_kwarg = 'shop'
context_object_name = 'shops'
class ProductListView(ListView):
model = Product
template_name = 'blog/product_list.html'
page_kwarg = 'product'
context_object_name = 'products'
def get_queryset(self):
pattern = str(self.request)
pattern = pattern[1:]
slug = self.model.shop
return Product.objects.filter(shop__slug=pattern)
def produt_detail(request, **kwargs):
print(request)
product = get_object_or_404(Product, pk=kwargs["pk"])
return render(request, 'blog/product_detail.html', {'product': product})
models.py
class Shop(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(blank=True)
slug = models.SlugField(null=False, default="Shop")
def get_absolute_url(self):
return reverse('product_list', kwargs={'slug': self.slug})
class Product(models.Model):
shop = models.ForeignKey(Shop, on_delete=models.CASCADE, related_name="shop")
title = models.CharField(max_length=200)
price = models.CharField(max_length=200)
period_start = models.DateTimeField(blank=True, null=True)
period_end = models.DateTimeField(blank=True, null=True)
def get_absolute_url(self):
return reverse('product_detail', kwargs={'slug': self.shop.slug, 'pk': self.pk})
urls.py
urlpatterns = [
path('', HomePageView.as_view(), name='shop_list'),
path('<slug:slug>', ProductListView.as_view(), name='product_list'),
path('<slug:slug>/<int:pk>/', views.produt_detail, name='product_detail'),
]
product_list.html
{% for product in products %}
<a href="{% url 'product_detail' product.shop.slug product.shop.pk %}">
...
You filter with:
class ProductListView(ListView):
model = Product
template_name = 'blog/product_list.html'
page_kwarg = 'product'
context_object_name = 'products'
def get_queryset(self):
return Product.objects.filter(shop__slug=self.kwargs['slug'])

Categories