Adding to List Style Entries in Django Admin - django

I would like to create a model where the user can add objects of a model to a list in Django.
For example:
class Receipt(models.Model):
items = #many to many maybe? but their is only one receipt for each item object
#other fields
class Item(models.Model):
name = model.CharField()
#otherfields
Class ItemPurchase(models.Model):
receipt = model.ForeignKey(Receipt)
item = model.ForeignKey(Item)
quantity = model.IntegerField()
#other fields specific to this Receipt
Then in the admin, I want to allow the user to add Item objects to their current Receipt objects in the admin panel, and create an ItemPurchase record, but how would I best do this? The Receipt cannot be associated until the Receipt is made...

Turns out Django's inline feature combined with custom queryset returns is exactly what I needed to do everything I wanted, thanks #Hedde for the tip!
Read about inlines:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects
This helped in multiple ways, I just needed a push in the right direction:
formfield_for_foreignkey and Inline Admin

Related

How can I access a value from one model and pass to another model in Django?

I have one model called Weight (filled by User input/choice) and another called Enterprise.
class Weight(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="weights")
weight_of_history = models.IntegerField(null=True, blank=True)
class Enterprise(models.Model):
...
The weight is saved, one per user, and replaced everytime the user choose new one.
Inside the Enterprise class, I am creating an property that must get the "weight_of_history" (depending on the user, who has chosen the weight) from Weight class, but the models have no Foreign key or related name between them.
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = <-- HERE I NEED TO TAKE WEIGHT_HISTORY FROM THE FIRST MODEL
THEN I COULD CALCULATE
How could I do that? Thank you!
You can use django's powerful query functionality and fetch the required objects from the db. Here are the docs that might help you with that. Django docs are amazing, so I would recommend that you read up on queries, models, and forms to have easier time with you project.
For your example we can fetch all the weights for the user in one query by filtering the weights by user. In fact, django ORM allows for chaining filters and you can create really sophisticated queries
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = Weight.objects.filter(user=some_user)
If you do not know the user beforehand, then you can do inside the view and grab the user that makes the request and filter using this user:
#views.py
user_making_request = request.user
weight_of_history = Weight.objects.filter(user=user_making_request)

Django: List of users in a model's field

I have a User model and PromoCode model. In the latter, I want to list users that have inputed and matched with one of the promocodes i put in the admin view.
What field type should I use in the PromoCode model to create a list of users, to which I can add more users over time in my views?
You want a ManyToManyField.
In the model:
class PromoCode(models.Model):
# Assuming you have other fields here, followed by:
users = models.ManyToManyField(User, related_name="promocodes")
Then in the views you can do things like:
if promocode:
pc = PromoCode.objects.get(code=promocode) # Get the PromoCode object
pc.users.add(user) # Add the M2M relationship
...or (because you used related_name) you could do it the other way around:
if promocode:
pc = PromoCode.objects.get(code=promocode) # Get the PromoCode object
user.promocodes.add(pc) # Add the M2M relationship
You have many PromoCodes that can have many Users, so you want a ManyToManyField.

Django: How to create an instance of a list of multiple objects and display on admin page

So say for example, I have a model Student:
class product(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length = 200)
price = models.PositiveIntegerField(default=0)
def _str_(self):
return self.name
And I want to create a recommendation list (a list that contains product objects) that allow super user to select products from the built in admin page.
My question is, is creating a separate model (class recommendation(models.Model))and using ForeignKey a correct approach to this situation? Because I do not consider recommendation a model, but I do want super user to be able access and manipulate the list on admin page.
Thanks in advance!
I think the correct approach in this situation would be to set up a recommendation model, but with a many to many relationship. This will allow you to add many products to a specific recommendation, while allowing a product to be used in many recommendations. The set up for this will look something like this:
class Recommendation(models.Model):
products = models.ManyToManyField('Product')
Setting up the model like this will also allow you to explore other features such as adding an owner of a recommendation

django is there a way to annotate nested object?

I have the following situation. I have three models, Post, User and Friends.
class User(models.Model):
name = models.CharField(max_length=100)
class Friend(models.Model):
user1 = models.ForeignKey(User,related_name='my_friends1')
user2 = models.ForeignKey(User,related_name='my_friends2')
class Post(models.Model):
subject = models.CharField(max_length=100)
user = models.ForeignKey(User)
Every time I bring users, I want to bring the number of his friends:
User.objects.filter(name__startswith='Joe').annotate(fc=Count('my_friends1'))
This works fine.
However, I want to make this work when I bring the users as nested objects of Post. I'm using there select_related to minimized DB calls, so I want to do something like:
Post.objects.filter(subject='sport').select_related('user').annotate(user__fc=Count('user__my_friends1'))
However, this creates field user__fc under post, and not field fc under post.user.
Is there a way to achieve this functionality?
You can make use of Prefetch class:
from django.db.models import Count, Prefetch
posts = Post.objects.all().prefetch_related(Prefetch('user', User.objects.annotate(fc=Count('my_friends1'))))
for post in posts:
print(post.subject)
print(post.user.fc)
NB : this does two database queries (Django does the join between Post and User in this case) :
'SELECT "myapp_post"."id", "myapp_post"."subject", "myapp_post"."user_id" FROM "myapp_post"
'SELECT "myapp_user"."id", "myapp_user"."password", "myapp_user"."last_login", "myapp_user"."is_superuser", "myapp_user"."username", "myapp_user"."first_name", "myapp_user"."last_name", "myapp_user"."email", "myapp_user"."is_staff", "myapp_user"."is_active", "myapp_user"."date_joined", COUNT("myapp_friend"."id") AS "fc" FROM "myapp_user" LEFT OUTER JOIN "myapp_friend" ON ("myapp_user"."id" = "myapp_friend"."user1_id") WHERE "myapp_user"."id" IN (3, 4) GROUP BY "myapp_user"."id", "myapp_user"."password", "myapp_user"."last_login", "myapp_user"."is_superuser", "myapp_user"."username", "myapp_user"."first_name", "myapp_user"."last_name", "myapp_user"."email", "myapp_user"."is_staff", "myapp_user"."is_active", "myapp_user"."date_joined"
You can define a custom manger for your models, as described here and then override its get_queryset() method to add the custom column to your model upon query.
In order to use this manager for a reverse relation, you should set the base manager as described in the docs.
Another approach would be something like this, which you specify the manager of the related model with a hard-coded attribute.

Which Django model field goes with a CheckboxSelectMultiple form field?

I have a django form that allows a user to select multiple options:
CARDS = (
("visa", "Visa"),
("mastercard", "MasterCard"),
)
class PaymentForm(forms.ModelForm):
credit_cards = forms.MultipleChoiceField(choices=CARDS, widget=forms.CheckboxSelectMultiple)
# ... etc.
I have the form's associated model setup as:
class Payment(models.Model):
user = models.OneToOneField(User)
credit_cards = models.CharField(choices=CARDS, max_length=100)
# ... etc.
But I'm thinking that a CharField with the choices parameter can only accept a single choice because my form never validates and I get an error like:
Value u"[u'visa']" is not a valid choice.
And it sure looks like a valid choice.
I've seen that some people get this working with a ManyToManyField on the model side (which I'd expect) but building a model just for a static list of credit card types seems overkill.
So: is there a specific model field type or different form configuration I should be using to support multiple selections from a pre-defined list of options?
Thanks.
http://djangosnippets.org/snippets/1200/