I want to create a webapp for managing a library .i create the book and the category model.the category is the class of the book 'history literature ..ect' ,i want the category appears as options when adding the book .so i put it in ModelChoiceField,but when i try to save the value of ModelChoiceField in database, it does not.
here is the code.
models.py
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
class Livre(models.Model):
titre = models.CharField(max_length=30,null=True)
category=models.CharField(max_length=30,null=True)
num_category=models.ForeignKey(Category, on_delete=models.CASCADE,null=True)
auteur=models.CharField(max_length=30,null=True)
nombre_copie=models.IntegerField(default=0,null=True)
publisher=models.CharField(max_length=30,null=True)
forms.py
from django import forms
from . import models
from project.models import Category
class Ajouterlivre(forms.Form):
titre = forms.CharField(max_length=100)
category = forms.ModelChoiceField(queryset=Category.objects.values_list('name', flat=True))
auteur = forms.CharField(max_length=100)
nombre_copie = forms.IntegerField()
publisher = forms.CharField(max_length=100)
views.py
def Ajoutlivre(request):
if request.method== 'POST':
form=forms.Ajouterlivre(request.POST)
if form.is_valid():
objt=Livre()
objt.titre = form.cleaned_data['titre']
objt.category= form.cleaned_data['category']
objt.auteur = form.cleaned_data['auteur']
objt.nombre_copie = form.cleaned_data['nombre_copie']
objt.publisher = form.cleaned_data['publisher']
objt.save()
return redirect('home')
else:
form=forms.Ajouterlivre()
return render(request,'livre/ajout-livre.html',{'form':form})
ModelchoiceField requires queryset returning dictionary and not tuples, when you use values_list its returns a tuples.
so you have to change the category (**) line in your code to work.
class Ajouterlivre(forms.Form):
titre = forms.CharField(max_length=100)
**category = forms.ModelChoiceField(queryset=Category.objects.all())**
auteur = forms.CharField(max_length=100)
nombre_copie = forms.IntegerField()
publisher = forms.CharField(max_length=100)
Hope this solves your problem.
Related
I'm trying to accomplish a three-level stacked inline form in Django. Suppose these models:
class Anuncio(models.Model):
title = models.CharField(max_length=200)
delivery = models.CharField(max_length=100)
class Product(models.Model):
anuncio = models.ForeignKey(Anuncio, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
quantity = models.PositiveIntegerField(default=1)
price = models.PositiveIntegerField()
class Image(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
image = models.ImageField()
There is a relation Anuncio-Product and another relation Product-Image. With this Django package, I accomplished exactly what I want in the Django admin: when creating an Anuncio object, I can add as many Products as I want, and those products can have as many Images as I want. I'm trying to accomplish this in the front end.
I think the way to go is with Django formsets, but I'm facing some problems. All the resources I've been able to find online are only 'two-level' formsets or in 'three-level' cases all the foreign keys point to the same parent model.
With this forms.py file:
class ProductForm(ModelForm):
class Meta:
model = Product
fields = ['name', 'quantity', 'price']
class ImageForm(ModelForm):
class Meta:
model = Imagen
fields = ['image']
class AnuncioForm(ModelForm):
class Meta:
model = Anuncio
fields = ['title', 'delivery']
And this views.py function:
def anunciocreateview(request):
form = AnuncioForm(request.POST or None)
ProductFormSet = inlineformset_factory(Anuncio, Product, form=ProductForm)
ImageFormSet = inlineformset_factory(Product, Image, form=ImageForm)
if all([form.is_valid(), ProductFormSet.is_valid(), ImageFormSet.is_valid()]):
parent = form.save(commit=False)
parent.anunciante = request.user
parent.save()
for form in ProductoFormSet:
child = form.save(commit=False)
child.anuncio = parent
child.save()
for form in ImagenFormSet:
imagen = form.save(commit=False)
imagen.product = form.product
imagen.save()
context = {
'form_1' : form,
'form_2' : ProductFormSet,
'form_3' : ImageFormSet,
}
But I think I'm missing important points when it comes to add the proper relations between models. This set-up gives an AttributeError of: 'ProductForm' object has no attribute '__name__'
The, for example, 'add (extra) Product' that appears in AdminStackedInLine I guess it can be accomplished with JavaScript, playing with hidden forms and changing attributes on click events.
Anyone has experience doing something similar or can guide me through the correct direction? Also on how to manage the data and the relations of the submitted forms?
I think your problem is you have tried to validate a class Form instead of instanciate your formset and validate them.
Your code would be look like to something like that :
def anunciocreateview(request):
ProductFormSet = inlineformset_factory(Anuncio, Product, form=ProductForm)
ImageFormSet = inlineformset_factory(Product, Image, form=ImageForm)
anuncio_form = AnuncioForm(request.POST or None)
product_formset = ProductFormSet(request.POST or None)
image_formset = ImageFormSet(request.POST or None)
if all([form.is_valid(), product_formset.is_valid(), image_formset.is_valid()]):
...
The function inlineformset_factory just create a Form class, not a instance of form.
More information and example on the documentation : https://docs.djangoproject.com/fr/4.1/topics/forms/formsets/
I have the following problem: I have a manytomanyfield (in model Toppings) and I can't populate it. I first tried using a list and set() and then I tried using just one object and add() in views.py but neither will return anything else than none. I have been looking at documentation and other forum questions but I just can't figure it out.
Any help is greatly appreciated!
views.py
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.core import serializers
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.shortcuts import render
from django.urls import reverse
from orders.models import Meal, Topping, Order
def order(request):
# Request should be ajax and method should be POST.
if request.is_ajax and request.method == "POST":
# Get IDs of meal, topping(s) and user
idmeal = request.POST["idmeal"]
idmeal = Meal.objects.get(pk = idmeal)
# Topping[] is a list of numbers representing IDs for Topping database
topping = request.POST.getlist('topping[]')
for i in range(0, len(topping)):
topping[i] = int(topping[i])
user = request.user
userID = User.objects.get(username=user.username)
topping = Topping.objects.filter(pk__in=topping)
print(topping)
# Create object in Order table
order = Order.objects.create(customerID = userID, mealID = idmeal, price = 12, status = "pending")
# Add values to ManyToManyField
order.toppingsID.set(topping)
print(order.toppingsID)
return JsonResponse({"success": ""}, status=200)
else:
# some error occured
return JsonResponse({"error": ""}, status=400)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Meal(models.Model):
meal = models.CharField(max_length=64)
classname = models.CharField(max_length=64)
price = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return f"{self.meal} ({self.classname}) ({self.price}) (id: {self.id})"
# Create your models here.
class Topping(models.Model):
topping = models.CharField(max_length=64)
classname = models.CharField(max_length=64)
price = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
def __str__(self):
return f"{self.topping} ({self.classname}) ({self.price}) (id: {self.id})"
class Order(models.Model):
customerID = models.ForeignKey(User, on_delete=models.CASCADE)
mealID = models.ForeignKey(Meal, on_delete=models.CASCADE)
toppingsID = models.ManyToManyField(Topping, blank=True)
price = models.DecimalField(max_digits=5, decimal_places=2)
status = models.CharField(max_length=64)
def __str__(self):
return f"{self.customerID} has ordered {self.mealID} with {self.toppingsID} which costs {self.price} (status : {self.status})"
The problem is not setting or adding to your field. The problem is printing your field.
In order to print the members of a ManyToManyField, you need to all .all() (or .filter() or any other function you add to a manager), like:
print(order.toppingsID.all())
If you print a manager, it will indeed print ModelName.None. For example Meal.objects will do the same. It is by using Meal.objects.all() that you construct a QuerySet.
I am using a custom user model and when i am trying to reference it in other model i am getting an error.
Exception Value:
NOT NULL constraint failed: send_appdata.product_id_id
views.py
from django.contrib.auth import get_user_model
AppOnboarding = get_user_model()
# get data from json
#api_view(['POST'])
def index(request):
product_id = AppOnboarding.objects.get(pk=request.data['product_id'])
product_name = request.data['product_name']
product_url = request.data['product_url']
subject = request.data['subject']
body = request.data['body']
recipient_list = request.data['recipient_list']
sender_mail = request.data['sender_mail']
email_type = request.data['email_type']
broadcast_mail = request.data['broadcast_mail']
email_status = status.HTTP_200_OK
location = request.data['location']
# make an object of AppData
app_data = AppData(product_id=product_id, product_name=product_name, product_url=product_url,
subject=subject, body=body, recipient_list=recipient_list, sender_mail=sender_mail, email_type=email_type, broadcast_mail=broadcast_mail, email_status=email_status, location=location)
# save it to DB
app_data.save()
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.contrib.auth import get_user_model
AppOnboarding = get_user_model()
class AppData(models.Model):
# app_data_id = models.IntegerField(primary_key=True)
product_id = models.ForeignKey(AppOnboarding, on_delete=models.PROTECT)
product_name = models.CharField(max_length=100)
product_url = models.URLField()
subject = models.CharField(max_length=100)
body = models.TextField()
recipient_list = models.TextField()
sender_mail = models.EmailField(max_length=254)
email_type = models.CharField(max_length=50)
broadcast_mail = models.BooleanField()
email_status = models.CharField(max_length=50)
date_time = models.DateTimeField(auto_now_add=True)
location = models.CharField(max_length=100)
AppOnboarding is a custom user model in a different app.
I explored the similar questions but could not resolve the issue.
Any help is highly appreciated.
Have added this foreign key product_id recently (after the rest of model fields)?
If yes, you need to make it nullable (null=True) and run makemigrations then migrate
Found the error, when I manually checked using python shell, Apponboarding.objects.get(id=1) was returning Does not exits but Apponboarding.objects.get(id=2) and others it was returning email address instead of id. It is still not clear how the id started from 2 instead of 1 (since it is auto field) and why email is getting returned instead of id.
Im newbie use python and django, I have problem in django admin site.
My plan is to give a different url to any existing data from many to many relationships that appear on the admin site table. When click data siswa will lead to the edit page.
# model.py
class WaliSiswa(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=11, choices=TITLE)
nama_lengkap = models.CharField(max_length=125)
jenis_kelamin = models.CharField(max_length=1, choices=GENDER_CHOICES)
relations = models.CharField(max_length=50, choices=RELATIONS)
tempat_lahir = models.CharField(max_length=255)
tanggal_lahir = models.DateField()
alamat_ktp = models.CharField(max_length=500)
alamat_tinggal_saat_ini = models.CharField(max_length=500)
profesi = models.CharField(max_length=225)
nomer_telepon = models.CharField(max_length=25)
nomer_seluler = models.CharField(max_length=25)
email = models.CharField(max_length=125)
siswa = models.ManyToManyField(Siswa)
# admin.py
class WaliSiswaAdmin(admin.ModelAdmin):
list_display = ('getTitleNamaLengkap', 'relations', 'getSiswa', )
def getSiswa(self, obj):
return ', '.join([d.nama_lengkap for d in obj.siswa.all()])
getSiswa.short_description = 'Siswa'
Like the picture above, I managed to display the data but confused to add its url. So I am very grateful for you who can provide the best solution.
Django docs have you covered about how you can reverse admin urls.
Also, we'll need the pretty handy format_html_join method.
# admin.py
from django.core.urlresolvers import reverse # django 1.9-
from django.urls import reverse # django 1.10+
from django.utils.html import format_html_join
class WaliSiswaAdmin(admin.ModelAdmin):
list_display = ('getTitleNamaLengkap', 'relations', 'getSiswa', )
def getSiswa(self, obj):
# Signature: format_html_join(sep, format_string, args_generator)
return format_html_join(
', ',
'{}',
[(reverse('admin:<your_app_name>_siswa_change', args=(d.id,)), d.nama_lengkap) for d in obj.siswa.all()]
)
getSiswa.short_description = 'Siswa'
If you're using Python 3.6 then use f-strings (!):
from django.core.urlresolvers import reverse # django 1.9-
from django.urls import reverse # django 1.10+
from django.utils.html import mark_safe
class WaliSiswaAdmin(admin.ModelAdmin):
list_display = ('getTitleNamaLengkap', 'relations', 'getSiswa', )
def getSiswa(self, obj):
return mark_safe(
', '.join([f'{d.nama_lengkap}' for d in obj.siswa.all()])
)
getSiswa.short_description = 'Siswa'
How to create an object for a Django model with a many to many field?
From above question i come to know we can save Many to Many field later only.
models.py
class Store(models.Model):
name = models.CharField(max_length=100)
class Foo(models.Model):
file = models.FileField(upload_to='')
store = models.ManyToManyField(Store, null=True, blank=True)
views.py
new_track.file = request.FILES['file']
new_track.save()
And file uploading working fine then later i modify my code to add store then i am here...
Now i am sure db return id's here. Then i tried with my below code but that's given me error only
x = new_track.id
new = Foo.objects.filter(id=x)
new.store.id = request.POST['store']
new.save()
ok so the error here is 'QuerySet' object has no attribute 'store'
And also i tried with add that's now working either.
So the question is how to save()
the right way of saving objects with manytomany relations would be:
...
new_track.file = request.FILES['file']
new_track.save()
new_store = Store.objects.get(id=int(request.POST['store']))
new_track.store.add(new_store)
As of 2020, here's my approach to saving ManyToMany Field to a given object.
Short Answer
class HostingRequestView(View):
def post(self, request, *args, **kwargs):
form = VideoGameForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.updated_by = request.user
obj.save()
selected_categories = form.cleaned_data.get('category') #returns list of all selected categories e.g. ['Sports','Adventure']
#Now saving the ManyToManyField, can only work after saving the form
for title in selected_categories:
category_obj = Category.objects.get(title=title) #get object by title i.e I declared unique for title under Category model
obj.category.add(category_obj) #now add each category object to the saved form object
return redirect('confirmation', id=obj.pk)
Full Answer
models.py
class Category(models.Model):
title = models.CharField(max_length=100, null=True, unique=True)
class VideoGame(models.Model):
game_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50, blank=False, null=False)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, on_delete=models.CASCADE)
category = models.ManyToManyField(Category) #ManyToMany Category field
date_added = models.DateTimeField(auto_now_add=True, verbose_name="date added")
forms.py ModelForm
class VideoGameForm(forms.ModelForm):
CATEGORIES = (
('Detective', 'Detective'),
('Sports', 'Sports'),
('Action', 'Action'),
('Adventure', 'Adventure'),
)
category = forms.MultipleChoiceField(choices=CATEGORIES, widget=forms.SelectMultiple())
class Meta:
model = VideoGame
fields = ['name', 'category', 'date_added']
views.py on POST
class HostingRequestView(View):
def post(self, request, *args, **kwargs):
form = VideoGameForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.updated_by = request.user
obj.save()
selected_categories = form.cleaned_data.get('category') #returns list of all selected categories e.g. ['Sports','Adventure']
#Now saving the ManyToManyField, can only work after saving the form
for title in selected_categories:
category_obj = Category.objects.get(title=title) #get object by title i.e I declared unique for title under Category model
obj.category.add(category_obj) #now add each category object to the saved form object
return redirect('confirmation', id=obj.pk)
URL path for redirect
urlpatterns = [
path('confirmation/<int:id>/', Confirmation.as_view(), name='confirmation'),
]
I hope this can be helpful. Regards
new.stores.all()
returns all stores linked to the object.
Maybe:
Change Foo to Tracks
Tracks.objects.filter(id=x) to Tracks.objects.get(id=x)
Let me know how it goes
why this confusion so much.. you are getting the id there then, call the store like
new_track.save()
new_track.store.add(request.POST['store'])