admin inlines over one2one field - django

I have three django models and I want to edit item's instances on order's page. Is it possible?
#models.py
class Item(models.Model):
name = models.CharField(max_length = 128)
cart = models.ForeignKey('Cart')
class Cart(models.Model):
number = models.IntegerField()
class Order(models.Model):
cart = models.OneToOneField('Cart')
#admin.py
ItemInline(admin.TabularInline):
model = Item
CartInline(admin.TabularInline):
model = Cart
Order(ModelAdmin):
inlines = (CartInline,) # I need ItemInline here...

Make it so Order is an inline of Cart, rather than the other way around?

Related

Django admin how to order by model property?

I have a model with property and I want to be able to sort instances in the admin panel by that property.
My model with _points property:
class CustomUser(models.Model):
inviter = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)
#property
def _points(self):
res = CustomUser.objects.filter(inviter_id=self.id).count()
return res
My admin:
class CustomUserAdmin(admin.ModelAdmin):
list_display = ['inviter', '_points']
class Meta:
model = CustomUser
the _points field is displayed in the admin panel, but I cannot sort entries by it
It is not possible to order a queryset by a property. You can only order it by database fields

How to add an extra field for an existing model in case of many to many relationships in django

So I have a product Model which say looks like this :
class ProductModel(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
and I also have a cart model which looks like this :
class CartModel(models.Model):
customer = models.ForeignKey(User, on_delete= models.CASCADE, related_name="cart")
products = models.ManyToManyField(ProductModel)
the thing is I want to add a quantity field to the product so the user can add multiple products from the same product in the cart But I only want it when the product is in a cart (I don't want to add it in the ProductModel) Instead I want to add it to the product fields in the many to many relationship. I've done a bit of research and most of the answers aren't clear enough on how I should be doing this.
You can create new fields in the intermediate relation table between Products and Cart. You have to define a new class for this intermediate table and to use it with the through attribute of the M2M field.
from django.db import models
from django.contrib.auth.models import User
class ProductModel(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Product"
class CartModel(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="cart")
products = models.ManyToManyField(ProductModel, through='ProductCart')
def __str__(self):
return "Cart nÂș {} - {}".format(self.pk, self.customer)
class Meta:
verbose_name = "Cart"
class ProductCart(models.Model):
product = models.ForeignKey(ProductModel, on_delete=models.CASCADE)
cart = models.ForeignKey(CartModel, on_delete=models.CASCADE)
quantity = models.IntegerField()
def __str__(self):
return ' '
One way for displaying it in the admin can be to use TabularInline for the products of the cart:
from django.contrib import admin
from .models import CartModel
class ProductsInline(admin.TabularInline):
model = CartModel.products.through
extra = 0
exclude = ()
verbose_name = 'Product'
class CartAdmin(admin.ModelAdmin):
list_display = ('customer',)
list_filter = ('customer',)
inlines = [
ProductsInline,
]
admin.site.register(CartModel, CartAdmin)

how to create django form with multiplechoicefield and add those value to database

what I want to achieve is user will submit 3 inputs in the form 1) name 2) dropdown to select technician, 3) multiselect dropdown to select multiple products. Once the user submit the details
it will generate one lead in database with value like name,foreignkey of selected technician and id of selected products in different table. I don't know how to achieve this below I have mentioned my approch to achieve what I want. Please let me know if the models need any changes and how I can write a view for the same.
models.py
class product(models.Model):
name = models.CharField(max_length=20)
class technician(models.Model):
name = models.CharField(max_length=20)
class lead(models.Model):
name = models.CharField(max_length=20)
technician = models.ForeignKey(technician,on_delete=models.SET_NULL,null=True) #only single selection
products = models.ManyToManyField(product) #user can select multiple product in dropdown
form.py
class leadForm(form.ModelForm):
products = forms.MultipleChoiceField(queryset=Product.objects.all())
technician = forms.CharField(max_length=30,choices=[(i.id,i.name) for i in Technician.objects.all().values('id','name')
class Meta:
model = lead
fields = ('name','technician')
You should use a ModelMultipleChoiceField [Django-doc] here. The But in fact you do not need to implement the models yourself. You can simply let the Django logic do the work for you.
In order to give a textual representation at the HTML end, you can override the __str__ functions of the models:
class Product(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Technician(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Lead(models.Model):
name = models.CharField(max_length=20)
technician = models.ForeignKey(Technician, on_delete=models.SET_NULL, null=True)
products = models.ManyToManyField(Product)
Then we can simply define our form with:
class LeadForm(form.ModelForm):
class Meta:
model = Lead
fields = '__all__'
Note: usually classes are written in PamelCase and thus start with an Uppercase.
You can here use a class-based CreateView [Django-doc] for example:
from django.views.generic.edit import CreateView
from app.models import Lead
from app.forms import LeafForm
class LeadCreateView(CreateView):
model = Lead
form_class = LeadForm
template_name = 'create_lead.html'

Display the object related set objects in the admin

I have three models for Movie, NowShowing and UpComingMovie. NowShowing and UpComingMovie has foreignkey relationship with the Movie.
class Movie(models.Model):
name = models.CharField(max_length=254, unique=True)
synopsis = models.TextField()
release_date = models.DateField()
director = models.ManyToManyField(MovieDirector)
writer = models.ManyToManyField(MovieWriter)
actor = models.ManyToManyField(MovieActor)
censor_rating = models.PositiveIntegerField(choices=CENSOR_TYPE)
#property
def is_screening(self):
if self.nowshowing_set.all().count() > 0:
return True
else:
return False
class NowShowing(models.Model):
movie = models.ForeignKey(Movie)
show_time = models.DateTimeField()
class UpComingMovie(models.Model):
movie = models.ForeignKey(Movie)
Each three of the models can be accesed in the admin:
class MovieAdmin(admin.ModelAdmin):
list_display = ('name', 'release_date', 'censor_rating', 'is_screening')
class Meta:
model = Movie
admin.site.register(Movie, MovieAdmin)
admin.site.register(NowShowing)
admin.site.register(UpComingMovie)
The problem is that I have to go to NowShowing or UpComingMovie admin page to create/change object. Is it possible to display each movies related set fields (NowShowing or UpComingMovie) to display in the Movie object detail admin page itself, so that its related field can be created/changed from the Movie obj directly without going to NowShowing or Upcoming admin page?
Yes, it's quite possible thanks to TabularInline (or StackedInline)
class UpcomingInline(admin.TabularInline):
model = UpComingMovie
class NowShowingInline(admin.TabularInline):
model = NowShowing
class MovieAdmin(admin.ModelAdmin):
list_display = ('name', 'release_date', 'censor_rating', 'is_screening')
inlines = [UpcomingInline,NowShowingInline]
class Meta:
model = Movie

Django get_or_create on reverse relationship

I'd like to use get_or_create instead of doing this:
cart = client.cart
cartitems_cart = cart.__cartitem_set
if not cartitems_cart.filter(item=stockitem).exists():
cartitem = CartItem.objects.create(item=stockitem)
else:
cartitem = cartitems_cart.objects.get(item=stockitem)
is it possible somehow?
The models look like this:
class CartItem(models.Model):
item = models.ForeignKey(StockItem, blank=True)
quantity = models.IntegerField(default=1, null=True)
class Cart(models.Model):
items = models.ManyToManyField(CartItem, blank=True)
So, I need to get or create a CartItem that is related with a Cart. I'm not sure how to write that query.
First off, your design is flawed. M2M relation allows a cart item to have more than one cart when it shouldn't. You should add a FK field to CartItem model instead of adding a M2M field to Cart model:
class Cart(models.Model):
user = models.ForeignKey(User)
class CartItem(models.Model):
item = models.ForeignKey(StockItem, blank=True)
quantity = models.IntegerField(default=1, null=True)
cart = models.ForeignKey(Cart, related_name="items")
so you can do the following:
cartitem, created = client.cart.items.get_or_create(item=stockitem)
or
cartitem, created = CartItem.objects.get_or_create(cart=client.cart, item=stockitem)
Please look at the documentation for more information regarding what other parameters get_or_create takes.