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.
Related
I have made a Django model form but the problem is in my logic I am using something else and now I want to figure out a way to validate it by either defining a Meta class and choosing the fields that I want to display to the user but of course this won't validate the form.
Now I want to know if there is a way to validate the form without touching the models and pass the data required for the logic and after take care of the information needed for the data of the model to be saved.
Here is the models:
from django.db import models
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class RoomCategory(models.Model):
name = models.CharField(max_length=59)
price = models.IntegerField()
beds = models.PositiveIntegerField()
capacity = models.PositiveIntegerField()
size = models.CharField(max_length=59)
def __str__(self):
return self.name
class Room(models.Model):
room_number = models.CharField(max_length=60)
room_category = models.ForeignKey(RoomCategory, on_delete=models.CASCADE)
def __str__(self):
return f"The room {self.room_number} {self.room_category} has a maximum of {self.room_category.capacity} person and cost {self.room_category.price}/night "
class Booking(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(RoomCategory, on_delete=models.CASCADE)
check_in = models.DateField()
check_out = models.DateField()
adults = models.PositiveSmallIntegerField()
children = models.PositiveSmallIntegerField()
def __str__(self):
return f"{self.customer} has booked for {self.room} from {self.check_in} to {self.check_out}"
Here is the form:
class BookingForm(forms.ModelForm):
class Meta:
model = Booking
fields = ['room', 'check_in', 'check_out', 'adults', 'children']
here is the views.py
data = form.cleaned_data
roomlist = Room.objects.filter(room_category__name=data['room'])
available_rooms = []
for room in roomlist:
if data['adults'] + data['children'] > room.room_category.capacity:
return HttpResponse(f'Sorry !! But this category of room cannot handle more than {room.room_category.capacity}')
else:
if check_availability(room.room_category.name, data['check_in'], data['check_out'], data['adults'], data['children']):
available_rooms.append(room)
if len(available_rooms) > 0:
room = available_rooms[0]
new_booking = Booking.objects.create(
customer=self.request.user,
room=room,
check_in=data['check_in'],
check_out=data['check_out'],
adults=data['adults'],
children=data['children']
)
new_booking.save()
return HttpResponse(new_booking)
else:
return HttpResponse('All the rooms of this type are not available')
It is not printing the data means that the form is not valid and it fall down to the else statement.
You can validate any field in the form by writing a method in this way : def clean_(field_name) i.e def clean_room(self) read more:
https://docs.djangoproject.com/en/3.1/ref/forms/validation/#cleaning-a-specific-field-attribute
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.
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.
I am trying to get all users (excepted request.user) and order them by datetime of last message they received.
Maybe I am doing it wrong.
#login_required
def get_users(request):
if request.method == 'POST':
users = list(User.objects.filter(~Q(username = request.user))
.order_by('personal_messages__sent_date').values())
return HttpResponse(dumps({'users': users}))
return redirect('message:index')
dumpsis from json_tricks.
Data are received by a Vue.js object with JS fetch
My models.py
from django.db import models
from django.conf import settings
class PersonalMessage(models.Model):
text = models.TextField()
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='personal_messages', null=True, on_delete=models.SET_NULL)
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)
sent_date = models.DateTimeField('sent date', auto_now_add=True)
The thing is if I only do users = list(User.objects.filter(~Q(username = request.user)).values()) it works well but if I add the order_by users = list(User.objects.filter(~Q(username = request.user)) .order_by('personal_messages__sent_date').values()) I get duplicates for each user. Seems it returns each user n times if user is linked with n messages.
Maybe there is another way.
Any Idea?
You need to use aggregation and the query looks like this:
User.objects.filter(
~Q(username = request.user)
).annotate(
last_message_sent_date=Max('personal_messages__sent_date')
).order_by(
'last_message_sent_date'
)
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'