I am developing a simple restaurant app in django and mysql and after days of googling and research, i wasn't able to find a suitable answere for this particular problem, here is my django Model
class MenuItem(models.Model):
menu_category = models.ForeignKey(MenuCategory, to_field='slug', on_delete=models.CASCADE)
name = models.CharField(max_length=30)
image = models.ImageField(upload_to='uploads/menu/')
slug = models.SlugField(null=True, blank=True, unique=True)
price = models.DecimalField(max_digits=9, decimal_places=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
and here is the problem:
for example i have a menuItem "MEXICAN BURGER" i would like to ask the user their choice of meat.. ie either chicken or beef, or their choice of bread, white or brown,
or i might be having a MenuItem "OMELETTE COMBO" and i would like to ask the user the type of omellete they'd like to have eg ('spanish omelete', 'spinach and mushroom omelete')
or i might be having a MenuItem "ESPRESSO" and i would like them to choose between ('single', 'double')
*one menuitem can have multitple choices related to it, ie burger item can have choice of bread as well as choice of meat
for a better understanding of my problem visit this
link
*
and this another link
You can create another model as needed e.g. MeatOption and add to it a ForeignKey to MenuItem:
class MeatOption(models.Model):
meat_type = models.CharField(max_length=200)
class MenuItem(models.Model):
meat_type = models.ForeignKey(MeatOption, null=True, blank=True)
# rest of fields
Ideally you should think of categorizing your items and reflect that categorization into your models. i.e. you could have class Burgers, class Beverages and so on, so that you only include the relevant options.
And if there is common functionality among all those categories you could inherit that from a Base MenuItem class like so:
class MenuItem(models.Model):
# common fields across all items go here
class Burger(MenuItem):
# burger-specific fields here
meat_type = models.ForeignKey(MeatOption)
class Omelette(MenuItem):
# omelette-specific fields here
ingredient = models.ManyToManyField(Ingredient)
class Ingredient(models.Model):
name = models.CharField(max_length=200)
the details depend on your use-case of course
There are different solutions to this.
Code Based: Inheritance
You create Mixins for each of your choice type and subclass MenuItem and these mixins.
from django.db.models import CharField, TextChoices, Model
class MeatChoices(TextChoices):
CHICKEN = 'chi'
BEEF = 'bee'
class MeatMixin(Model):
meat_choices = CharField(max_length=3, choices=MeatChoices.choices, default=MeatChoices.CHICKEN)
class MeatMenuItem(MeatMixin, MenuItem):
pass
This will require code changes whenever more choices are added to the menu or the menu is changed in that matter.
Data Based: Generic Models
To allow the admin user to create and add choices to the menu items via the Django Admin, you need to create a model structure that enables specifying choices:
from django.contrib.postgres.fields import ArrayField
from django.db.models import ManyToManyField, CharField, Model
class Ingredient(Model):
name = CharField(max_length=50, unique=True)
class IngredientChoiceGroup(Model):
name = CharField(max_length=50, unique=True)
# simple solution for postgres only:
# ingredients = ArrayField(CharField(max_length=50))
# if not postgres or you need more attributes to ingredient:
ingredients = ManyToManyField(Ingredient)
class MenuItem(models.Model):
menu_category = models.ForeignKey(MenuCategory, to_field='slug', on_delete=models.CASCADE)
name = models.CharField(max_length=30)
image = models.ImageField(upload_to='uploads/menu/')
slug = models.SlugField(null=True, blank=True, unique=True)
price = models.DecimalField(max_digits=9, decimal_places=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
ingredient_choices = ManyToManyField(IngredientChoiceGroup)
def __str__(self):
return self.name
This method would allow to configure multiple choice groups per menu item, e.g. "BREAD" and "MEAT". And you can do that all via the Django Admin.
You might need to work out the details. This is just a draft.
Note about ArrayField: it is a simpler structure in the DB, but for the Admin you will need to add a specific widget via 3rd party library or at least write your own parser. In the end, M2M field might be the better choice.
Related
After reading all the docs and answers I can find, and burning a whole day, I still can't make this work. Using Django Tables2, I want to show a list of instruments; the instruments table includes a foreign key to an instrumentsType table. When I list the instruments and their attributes, I want to use the foreign key to substitute the textual instrument type description from the other table. I have tried every combination of double underscores and other accessor techniques, but so far all I get is the dreaded -- in the column. (Displaying just the record ID works).
from .models import Instrument
from django_tables2 import A
from instrumenttypes.models import InstrumentType
class InstrumentTable(tables.Table):
id = tables.LinkColumn('instrument_details', args=[A('station_id')])
class Meta:
model = Instrument
template_name = "django_tables2/bootstrap.html"
fields = ("id", "instrument", "nickname", "serialNo",
"instrument__instrumenttype_id__instrumenttypes__id_instrumentType" )
The models involved are:
Instruments model.py
from django.db import models
from instrumenttypes.models import InstrumentType
from stations.models import Station
# Create your models here.
class Instrument(models.Model):
instrument = models.CharField(max_length=40)
instrumenttype = models.ForeignKey(InstrumentType, on_delete=models.CASCADE, null=True)
station = models.ForeignKey(Station, on_delete=models.CASCADE, default=1)
serialNo = models.CharField(max_length=60, null=True, blank=True)
dateAdded = models.DateTimeField("Date Added", null=True, blank=True)
dateRemoved = models.DateTimeField("Date Removed", null=True, blank=True)
status = models.CharField(max_length=10, null=True, blank=True)
nickname = models.CharField(max_length=40, null=True, blank=True)
InstrumentTypes model.py
from django.db import models
class InstrumentType(models.Model):
instrumentType = models.CharField(max_length=40)
Resulting output:
ID Instrument Nickname SerialNo Instrumenttype
4 instr2 nock2 123 —
The most relevant online references I have found are here and here; but having tried the suggestions, no luck. What am I missing?
I've been struggling to get something working too (but I finally did), and I found the examples too brief.
I think you want to get rid of this stuff in the Meta class
"instrument__instrumenttype_id__instrumenttypes__id_instrumentType"
I think Meta.fields should just be a list of field names, and that you refer to the attribute in the other table from the point of view of the type of object you will later pass in to the IntrumentTable constructor (and that is named in the Meta.model attribute:
from django_tables2.utils import Accessor
class InstrumentTable(tables.Table):
instrument_type = tables.Column(accessor=Accessor('instrumenttype.name'))
class Meta:
model = Instrument
template_name = "django_tables2/bootstrap.html"
fields = ("id", "instrument", "nickname", "serialNo", "insrument_type")
Then, in view, make an instance of InstrumentTable
def myview(request):
table_to_render = InstrumentTable(Instrument.objects)
return render(request, sometemplate, {table: table_to_render})
You didn't show your view, and I know there may be a different way. If you have the whole thing in a repo somewhere, leave a link.
I have a model with an attribute that is connected to another model as follow:
class Book(models.Model):
synced = models.OneToOneField('SyncedBook'
related_name='internal',
on_delete=models.CASCADE)
# some more attributes here...
#property
def book_address(self)
return self.synced.book_address
However, the book_address is a also a FK in the SyncedBook table as follow:
book_address = models.ForeignKey('Address', db_index=True, null=True, blank=True,
related_name='address_book', on_delete=models.PROTECT)
I don't know and understand how to be able to edit the book_address through the Django admin page in class BookingAdmin(admin.ModelAdmin), even though I have read over the documentation. At first I have the attribute as readonly, but now I want to be able to edit it and save the new address from the Address table. Is there a way to make it happen through the class BookingAdmin(admin.ModelAdmin) and how? Any example and solution would be appreciate
Model properties are typically used for presenting logically defined data for a particular model instance and not necessarily storing data on the model instance itself.
An example of when to use a model property is as follows:
# Defines a product instance
class Product(model.Models):
name = models.CharField(max_length=100)
description = models.TextField()
active = models.BooleanField(default=True)
cost = models.DecimalField(max_digits=5, decimal_places=2)
price = models.DecimalField(max_digits=5, decimal_places=2)
# calculate profits on product
#property
def profit(self)
p = self.price - self.cost
return p
In your case, you are trying to actually be able to modify data against a related model instance within the django admin. To me this sounds like more specifically an Inline (click here for documentation)
So in your case, you would need to create something like the following to your admin.py file:
class SyncedBookInline(admin.TabularInline):
model = BookInline
#admin.Register(Book)
class BookAdmin(admin.ModelAdmin):
# all your model admin settings
inlines = [SyncedBookInline]
Additional Info:
The Inline solution should still work for you. Please see the working code listed below:
models.py:
from django.db import models
class Hero(models.Model):
name = models.CharField(max_length=50)
class HeroAcquaintance(models.Model):
name = models.CharField(max_length=50)
hero = models.OneToOneField(Hero, on_delete=models.CASCADE)
admin.py:
from django.contrib import admin
from .models import *
class HeroAcquaintanceInline(admin.TabularInline):
model = HeroAcquaintance
#admin.register(Hero)
class HeroAdmin(admin.ModelAdmin):
list_display = (
'name',
)
inlines = [HeroAcquaintanceInline]
#admin.register(HeroAcquaintance)
class HeroAcquaintanceAdmin(admin.ModelAdmin):
list_display = (
'name',
)
Screenshot:
I'm creating a simple contacts app in django and I want to allow everyone to have more than a single phone number.
My models.py looks like this:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
birthday = models.DateField(null=True, blank=True)
def __str__(self):
return ' '.join([self.first_name, self.last_name])
class Phone(models.Model):
phone_number = models.CharField(max_length=12)
description = models.CharField(max_length=25)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
def __str__(self):
return self.phone_number
I need to create a form where I can add the core contact info and as many phone numbers as wanted.
I have a ModelForm like
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = '__all__'
How do I create a phone_number field which allows to insert the phone number?
Here is a nice tutorial that is perhaps a bit more helpful than the documentation if you're struggling:
http://whoisnicoleharris.com/2015/01/06/implementing-django-formsets.html
It goes through using formsets which allow you to have and use more than one form of the same type on a page.
And also shows you a JQuery plugin that allows you to add and remove forms dynamically.
I am a novice in Django and I'm learning the ropes of the admin interface. I have a model with several foreign keys. These foreign keys then reference other foreign keys. On the admin website after I register the Property model and then try to add it I am given a dropdown box for each foreign key model. However this dropdown box only lists existing foreign keys. (http://i.stack.imgur.com/e5LCu.png)
What would be great is if instead of a dropdown box there were extra fields so I could add the foreign key models as I add the property model. That way I wouldn't have to manually add foreign keys and then go back and add some more, and then go back and finally add the property data.
How can I do this? This feels like a simple enough question but after intense Googling I still can't find the answer, so I apologize in advance.
Example of two of my models:
class Address(models.Model):
state = models.ForeignKey('State')
address1 = models.CharField(max_length=200)
address2 = models.CharField(max_length=200)
city = models.CharField(max_length=200)
postal_code = models.CharField(max_length=200)
class Property(models.Model):
address = models.ForeignKey('Address', blank=True, null=True)
borrower = models.ForeignKey('Person', blank=True, null=True)
company = models.ForeignKey('Company', blank=True, null=True)
contract = models.ForeignKey('Contract', blank=True, null=True)
loan_balance = models.IntegerField()
name = models.CharField(max_length=200)
primary_email = models.CharField(max_length=200)
primary_phone = models.CharField(max_length=200)
property_no = models.IntegerField()
Example of my admin.py:
# Register your models here.
class PropertyAdmin(admin.StackedInline):
model = Property
class PersonAdmin(admin.StackedInline):
model = Person
class CompanyAdmin(admin.StackedInline):
model = Company
class ContractAdmin(admin.StackedInline):
model = Contract
class CompletePropertyAdmin(admin.ModelAdmin):
inlines = [PropertyAdmin, PersonAdmin, CompanyAdmin, ContractAdmin]
admin.site.register(Property)
One solution to the problem can be, to create a custom form with fields from both the models and at the time of saving the values, first create the instance of Address model and then with that instance save your final Property model.
Is there a way in Django to have multiple objects stored and manageable (in Django admin) inside another object?
Example, I have two models: Items and RMA. The RMA may have multiple Items inside of it. Each Item is unique in the sense that it is an inventoried part, so I can't just reference the same item multiple times with foreignKey (though maybe I'm misunderstanding its use/implementation).
So for now, I have an Item model:
class Item(models.Model):
serial_number = models.CharField(max_length=200)
name = models.CharField(max_length=200)
part_number = models.CharField(max_length=200)
location = models.CharField(max_length=200)
def __unicode__(self):
return self.name
And an RMA model:
class RMA(models.Model):
number = models.AutoField(primary_key=True)
items = ?????
Ultimately I'd like to be able to maintain use of the Django admin functionality to add/remove items from an RMA if necessary, so I've been staying away from serializing a list and then deserializing on display. Any help would be much appreciated.
You're modeling a has-many relationship.
This would be modeled with a Foreign Key on Item to RMA:
class Item(models.Model):
serial_number = models.CharField(max_length=200)
name = models.CharField(max_length=200)
part_number = models.CharField(max_length=200)
location = models.CharField(max_length=200)
rma = models.ForeignKey(RMA)
def __unicode__(self):
return self.name
To make it accessible in the admin of RMA you need djangos InlineAdmin functionality.
You can find examples in the django tutorial part2.
You are effectively describing a Many-To-One relation and to do this you are going to have to add the ForeignKey reference to the Item model, not to the RMA model.
You can also add a related_name to give the RMA model an attribute that you can call.
For example:
class Item(models.Model):
rma = models.ForeignKey(RMA,related_name="items")
serial_number = models.CharField(max_length=200)
# etc...
To manage the creation of these, you'll need an InlineModelAdmin form, so your admin.py file will need to look like this:
from django.contrib import admin
class ItemInline(admin.TabularInline):
model = Item
class RMAAdmin(admin.ModelAdmin):
inlines = [
ItemInline,
]