I'm still relatively new to programming, Django, and creating apps so please bear with me. I'm working on a dietary app and I'm having a hard time visualizing and understanding why my specific use case of a ManyToManyField for one of my models is not showing up in the admin console. I tried reading the Django docs for the ManyToManyField relationship but I am still having troubles understanding it, so hopefully someone can explain this to me like I am a happy golden retriever.
I have three models:
class Product(models.Model):
product_name = models.CharField(verbose_name='Product name', max_length=100)
product_description = models.TextField(verbose_name='Product description', max_length=500)
product_id = models.UUIDField(default=uuid.uuid4(), unique=True)
def __str__(self):
return self.product_name
#-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
class Recipe(models.Model):
recipe_name = models.CharField(verbose_name='Recipe name', max_length=100)
ingredients = models.ManyToManyField(Product, related_name='Ingredients', through='IngredientQuantity', through_fields=('recipe','ingredient'))
class Meta:
ordering = ['recipe_name']
def __str__(self):
return self.recipe_name
#-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------#
class IngredientQuantity(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.DecimalField(verbose_name='Quantity', decimal_places=2, max_digits=99, null=False)
What I was trying to do with this was create an Intermediary with IngredientQuantity which will give me the quantity along with a selected Product that I can then associate with Recipe.
However I am not seeing the ingredients input for Recipe when I attempt to create a new entry for Recipe in the Django admin console, is this supposed to be the case?
In your app admin.py file add these lines:
from django.contrib import admin
from .models import Product, Recipe, IngredientQuantity
admin.site.register(Product)
admin.site.register(Recipe)
admin.site.register(IngredientQuantity)
Then you should see your models in your admin interface.
Related
I have 4 models: Products (the list of products: freezers, microwaves, tvs and pcs), ProductType (entertainment and home appliances), Credit (a credit is registered on each purchase) and PurchaseReason (the reason why the customer has bought the product).
The PurchaseReason depend on the productType, so the purchaseReason has a foreignKey field productType.
In addition, each credit has a product as foreignKey and a purchaseReason as foreignKey.
Also, I have the ProductReason field as a choice field in the credit model, and I want the options to be set dynamically based on the product field of the credit model.
I'm creating an API so I think this cant be handle with modelForms, but i'm not sure. The hard work would be with the serializers (DRF) and with the django-admin (specially this one because in my product the django admin plays an important role)
What would be the best approach to manage my models in Django?
Here are my models. In credit I'm not sure how to implemente the purchase reason:
class Credit(models.Model):
client = models.ForeignKey('clients.Client', on_delete=models.SET_NULL)
name = models.CharField(max_length=30, null=False, blank=True)
product = models.ForeignKey('product',on_delete=models.SET_NULL)
reason_purchase = models.ChoiceField(????)
class PurchaseReason(models.Model):
product_type = models.ForeignKey(product_type, on_delete=models.CASCADE)
reason = models.CharField(max_length=30, null=False, blank=True)
class ProductType(models.Model):
name = models.CharField(max_length=30, null=False, blank=False)
class Product(models.Model):
model = models.CharField(max_length=30, default=None, null=True)
product_type = models.ForeignKey(product_type, on_delete=models.CASCADE)
When we use the foreign key, we need to mention the model name of that particular model so that we can integrate that particular model in that model as a reference entity. Have a look at this example.
from django.db import models
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self):
return self.headline
class Meta:
ordering = ['headline']
you've not mentioned the model name properly. it should be Product in place of 'product' in the Credit class, product field.
use this reference https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_one/
i think you should be able to use the Foreignkey field properly after this. Although, if you can't, you can share the actual objective. i will help you to write the correct model.
Best wishes :)
I searched through stackoverflow about this particular scenario, but could not find a concrete answer, so i'm posting this.
So my problem is that i need to display specific records to a specific user in Django Admin. I'm aware that i can get the concrete logged in user through the get_queryset method extracting it from the request object. But the issue is i need to look through 6 tables to get to the information about the user of the recommendations so i could know which recommendation to display to him.
For example, if the records i need to display come from a Recommendation table, it has a reference to TableA, which has a reference to TableB .... which has a reference to TableF which has a reference to the User.
I'm aware i could do this by executing a plain SQL query with multiple joins, but my guess is that there must be a pythonic or Django sophisticated solution to this. But i may be wrong.
The model is unfortunately not in my control, nor i can change it, so i'm left to work with the state of the model that there is.
Thanks in advance.
EDIT: Unfortunately, i can't share details of it, but i can share the general look of it. So i think this should be enough to have a picture of my problem.
from django.db import models
from django.contrib.auth.models import User
class TableF(models.Model):
information = models.CharField(max_length=256, null=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class TableE(models.Model):
information = models.CharField(max_length=256, null=False)
tableF = models.ForeignKey(TableF, on_delete=models.CASCADE)
class TableC(models.Model):
information = models.CharField(max_length=256, null=False)
tableEs = models.ManyToManyField(TableE, through='TableD')
class TableD(models.Model):
information = models.CharField(max_length=256, null=False)
tableC = models.ForeignKey(TableC, on_delete=models.CASCADE)
tableE = models.ForeignKey(TableE, on_delete=models.CASCADE)
class TableA(models.Model):
information = models.CharField(max_length=256, null=False)
tableCs = models.ManyToManyField(TableC, through='TableB')
class TableB(models.Model):
information = models.CharField(max_length=256, null=False)
tableA = models.ForeignKey(TableA, on_delete=models.CASCADE)
tableC = models.ForeignKey(TableC, on_delete=models.CASCADE)
class Recommendation(models.Model):
information = models.CharField(max_length=256, null=False)
tableA = models.ForeignKey(TableA, on_delete=models.CASCADE)
you can use a middleware to include de user to the thread locals and catch this user from get_queryset in the model manager.
from threading import local
_thread_locals = local()
def get_current_user():
return getattr(_thread_locals, 'user', None)
class ThreadLocals(object):
#staticmethod
def process_request(request):
_thread_locals.user = getattr(request, 'user', None)
in the settings
MIDDLEWARE = [
...
'path.to.file.ThreadLocals',
]
from your.path import get_current_user
class TableFManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(creator=get_current_user())
class TableF(models.Model):
information = models.CharField(max_length=256, null=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
objects = TableFManager()
another less invasive option could be to rewrite the get_queryset in the admin class. there you already have the user in the request
def get_rec_user(user):
tes = TableE.objects.filter(tableF__in=TableF.objects.filter(user=user))
aes = TableB.objects.filter(tableE__in=tes).values_list('tableA_id', flat=True)
return Recommendation.objects.filter(
tableA__in=TableA.objects.filter(id__in=aes)
)
I try to figure a clever way out for my models.
I have two models where i want the Legend to have 4 different skills(Skill Model), but I cant seem to get the fitting model relation for it
class Skill(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
title = models.CharField(max_length=100)
description = models.CharField(max_length=300)
image = models.ImageField(upload_to='skills/', blank=True, null=True)
class Legend(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
title = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
image = models.ImageField(upload_to='legends/%Y/', blank=True, null=True)
skill_1 = models.(Skill, on_delete=models.SET_NULL, null=True)
skill_2 = models.OneToOneField(Skill, on_delete=models.SET_NULL, null=True)
skill_3 = models.OneToOneField(Skill, on_delete=models.SET_NULL, null=True)
skill_4 = models.OneToOneField(Skill, on_delete=models.SET_NULL, null=True)
The problem is I cant rly make a OneToOneField because it want´s a related_name for each, which would make No sense here, since they are all skills and I dont want to call for the owner (Legend) of the skill in 4 different ways
I also tried to make a legend field in the Skill model with a foreignkey on the Legend, but that didnt turned out how i wanted it to be.
thanks for the help ^.^
Moving my answer here, so I can format code
So... do it as I've said. Add FK in Skill pointing to Legend. Afterwards in your admin.py create admin class which inherits from StackedInline or TabularInline. Your file should look like this:
from django.contrib import admin
from apps.legends.models import Skill, Legend
class InlineAdminSkill(admin.TabularInline):
model = Skill
extra = 4
max_num = 4
class LegendAdmin(admin.ModelAdmin):
inlines = [InlineAdminSkill]
admin.site.register(Legend, LegendAdmin)
This should resolve problem in admin - your skill will be visible in your admin legend view. Try it out.
In your views in the other hand you just have to add a logic which uses e.g. formsets and enables you adding max 4 skills.
What I currently have in my models is this:
class Project(models.Model):
project_name = models.CharField(max_length=255, unique=True, blank=False)
def __str__(self):
return str(self.project_name)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(choices=ROLE_CHOICES, max_length=255, default='Agent')
Now my question is: Users should be able to have multiple Projects - so I obviously can't use a OneToOne-Field in the Profile-Model.
Later I want to use it for example to just show a user news which are only related to the projects he participates in.
What would be the best strategy to make this possible? Any input is highly appreciated.
Use ManyToMany on project.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(choices=ROLE_CHOICES, max_length=255, default='Agent')
project = models.ManyToManyField(Project)
This way one profile can have as many project as he/she wants
On your view you can use this field to filter based on project
I have two models that have many to many relationship. One model consists of all possible choices and the other model can have some or all of those choices.
These are the two models:
class LanguageDomains(models.Model):
DOMAIN_CHOICES=(
('Choice1', _(u'Choice1')),
('Choice2', _(u'Choice2')),
('Choice3', _(u'Choice3')),
('Choice4', _(u'Choice4')),
)
# There is many more choices in the actual code
domains = models.CharField(max_length=255, choices=DOMAIN_CHOICES, default=None)
def __unicode__(self):
return self.domains
class Revitalization(models.Model):
code = models.ForeignKey(Codes, related_name ='revitalization')
program_name = models.CharField(max_length=255, null=True, blank=True)
year_founded = models.CharField(max_length=4, null=True, blank=True)
some_domains = models.ManyToManyField(LanguageDomains, related_name='revitalization')
def __unicode__(self):
return self.code.primary_name
My admin.py:
class RevitalizationAdmin(admin.ModelAdmin):
list_display = ('code','id')
filter_horizontal = ('language_domains',)
This is what the admin console looks like:
The question is, is there a way to populate the "Available language domains" list with all the DOMAIN_CHOICES from LanguageDomains model?
You could write a data migration that will populate the LanguageDomains model table with all the available choices.
Depending on your use-case, if the sole purpose of LanguageDomains is to present multiple choices and it's not going to be edited in runtime look into using django-multiselectfield.