I'm learning Django and I'm trying to make a sort of wiki type app. In this wiki there are different type of models: Characters, Items, Spells and Adventures. Each model has some fields that are the same (like name, author, date_created, etc.) and some that are unique to the model, like duration for adventures, alignment for characters, etc. The problem that I have is that if they are different models then every time I want to make something that is common to all of the models (like being able to like, favorite, create, edit, etc.) then I have to code for each model individually. Is there a way of creating a sort of Content model that contains every character, item, spell and adventure so that every time I want to make a form or a function I just make a Content form or Content function?
Here's some of the code, some parts are in spanish but I translated the important parts:
class Character(models.Model):
ALIGNMENT= (
('Legal Bueno', 'Legal Bueno'),
('Legal Neutral', 'Legal Neutral'),
('Legal Malvado', 'Legal Malvado'),
('Neutral Bueno', 'Neutral Bueno'),
('Neutral', 'Neutral'),
('Neutral Malvado', 'Neutral Malvado'),
('Caótico Bueno', 'Caótico Bueno'),
('Caótico Neutral', 'Caótico Neutral'),
('Caótico Malvado', 'Caótico Malvado')
)
name = models.CharField(max_length=50)
author = models.ForeignKey(Usuario, null=True, on_delete=models.CASCADE, editable=False, related_name='personajes')
alignment = models.CharField(max_length=50, choices=ALIGNMENT)
description= models.CharField(max_length=200, null=True)
likes = models.ManyToManyField(Usuario, blank=True, related_name='personaje_likes')
favorites = models.ManyToManyField(Usuario, blank=True, related_name='personaje_favoritos')
class Item(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Usuario, null=True, on_delete=models.CASCADE, editable=False, related_name='items')
description= models.CharField(max_length=200, null=True)
likes = models.ManyToManyField(Usuario, blank=True, related_name='item_likes')
favorites = models.ManyToManyField(Usuario, blank=True, related_name='item_favoritos')
class Spell(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Usuario, null=True, on_delete=models.CASCADE, editable=False, related_name='hechizos')
description= models.CharField(max_length=200, null=True)
likes = models.ManyToManyField(Usuario, blank=True, related_name='hechizo_likes')
favorites = models.ManyToManyField(Usuario, blank=True, related_name='hechizo_favoritos')
class Adventure(models.Model):
DURATION = (
('Corta', 'Corta'),
('Mediana', 'Mediana'),
('Larga', 'Larga')
)
name = models.CharField(max_length=50)
author = models.ForeignKey(Usuario, null=True, on_delete=models.CASCADE, editable=False, related_name='aventuras')
duration = models.CharField(max_length=50, choices=DURATION)
description = models.CharField(max_length=200)
likes = models.ManyToManyField(Usuario, blank=True, related_name='aventura_likes')
favorites = models.ManyToManyField(Usuario, blank=True, related_name='aventura_favoritos')
I think you can create a base model and then use a OneToOneField to this model in your other models.
class BaseContent(models.Model):
name = models.CharField(max_length=500)
author= models.CharField(max_length=500)
(...)
class Characters(models.Model):
base_content = models.OneToOneField(BaseContent, on_delete=models.CASCADE)
(...)
Related
Just a fool question I have a model Exam which contains a field Subject which I want to connect with 3 or 4 or even 5 subjects like foreign key connect one with it.
# 1 type
class Math(models.Model):
id = models.CharField(primary_key=True, max_length=200, blank=True)
chapter = models.ForeignKey(Chapters, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
marks_contain = models.IntegerField(default=10)
question = RichTextUploadingField()
hint = RichTextUploadingField()
created_at = models.DateTimeField(auto_now_add=True, blank=True)
# 2 type
class Science(models.Model):
id = models.CharField(primary_key=True, max_length=200, blank=True)
chapter = models.ForeignKey(Chapters, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
marks_contain = models.IntegerField(default=10)
question = RichTextUploadingField()
hint = RichTextUploadingField()
created_at = models.DateTimeField(auto_now_add=True, blank=True)
# 3 type
class Computer(models.Model):
id = models.CharField(primary_key=True, max_length=200, blank=True)
chapter = models.ForeignKey(Chapters, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
marks_contain = models.IntegerField(default=10)
question = RichTextUploadingField()
hint = RichTextUploadingField()
created_at = models.DateTimeField(auto_now_add=True, blank=True)
class Exam(models.Model):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
name = models.CharField(max_length=255)
subject = models.ForeignKey([object.Math or object.Science or object.Computer]) # I want to do something like this
I know this is not possible with foreign-key but what is the way to do things like this?
It's possible with ManyToMany, but you have to create new model:
from django.utils.module_loading import import_string
class Subject(models.Model):
class_name = models.CharField(...)
def get_class(self):
return import_string(f"app_name.models.{self.class_name}")
class Exam(...):
...
subject = models.ManyToManyField(Subject, default=None, blank=True)
Then simply create Subject object for each model you want to be with class_name exactly as you have your subject __class__ name, i.e. Subject.objects.create(class_name="Math"). Then replace app_name with name of your app that models.py is inside.
If you need real class from Subject class just call subject.get_class(), and you will get object: <class 'app_name.models.Math'>.
I am a Django newbie. I cannot figure out how to create a form that properly displays my model, which has two ForeignKey fields and three ManytoManyFields. I am familiar with creating forms from more simple models, but I'm stuck on this one. So far, I've tried ModelForm and used ModelChoiceField for ForeignKey relationships, but that did not work. When viewing the form, the fields options did not render. I then tried inlineformset_factory but I could not find helpful examples. Any help is appreciated.
I am trying to create CreateView, UpdateView, and DeleteView options for the model.
models.py
class Animal(models.Model):
name = models.CharField(max_length=500, blank=False, null=False)
**atype = models.ForeignKey(Type, on_delete=models.SET_NULL, blank=False, null=True)**
**ageGroup = models.ForeignKey(AgeGroup, max_length=300, on_delete=models.SET_NULL, blank=False, null=True)**
ageYears = models.PositiveIntegerField(blank=False, null=False)
ageMonths = models.PositiveIntegerField(blank=True, null=True)
sex = models.CharField(max_length=100, choices=SEX, blank=False, null=False, default='NA')
city = models.CharField(max_length=200, blank=True, null=True)
state = models.CharField(max_length=200, blank=True, null=True)
country = models.CharField(max_length=250, blank=True, null=True)
**breedGroup = models.ManyToManyField(BreedGroup, blank=False)**
**breed = models.ManyToManyField(Breed, blank=False)**
tagLine = models.CharField(max_length=300, blank=False, null=False)
goodWithCats = models.BooleanField(blank=False, null=False, default='Not Enough Information')
goodWithDogs = models.BooleanField(null=False, blank=False, default='Not Enough Information')
goodWKids = models.BooleanField(null=False, blank=False, default='Not Enough Information')
profilePic = ResizedImageField(size=[300, 450], quality=100, upload_to='media/', default='', null=True, blank=True, keep_meta=False)
**contact = models.ForeignKey(ContactDetails, on_delete=models.SET_NULL, blank=False, null=True)**
forms.py
class AnimalDetailsForm(ModelForm):
ftype = ModelChoiceField(queryset=Type.objects.all()) #doesn't work
ageGroup = ModelChoiceField(queryset=AgeGroup.objects.all()) #doesn't work
#breed = what method to use?
#breedGroup = what method to use?
class Meta:
model = Animal
exclude = ['ftype', 'ageGroup', 'breed', 'breedGroup']
Also in the Meta of your form you are excluding the fields you are trying to get data for. It should say
class Meta:
model = Animal
fields = ['type', 'ageGroup', 'breed', 'breedGroup']
Docs consulted: https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/
https://docs.djangoproject.com/en/3.1/ref/models/fields/
**edit, removed comment about using type as a variable name.
Suppose I have 3 models:- Address, Country, State
Address Model:
class AddressModel(BaseModel):
country = models.ForeignKey(CountryModel, null=True, blank=True, on_delete=models.PROTECT)
state = models.ForeignKey(StateModel, null=True, blank=True, on_delete=models.PROTECT)
city = models.CharField(max_length=200, null=True, blank=True)
pincode = models.CharField(max_length=6, null=True, blank=True)
address_line_1 = models.TextField(max_length=200, null=True, blank=True)
address_line_2 = models.TextField(max_length=200, null=True, blank=True)
Country Model:
class CountryModel(BaseModel):
name = models.CharField(max_length=100)
code = models.CharField(max_length=30)
and State Model:
class StateModel(BaseModel):
country = models.ForeignKey(CountryModel, on_delete=models.PROTECT)
name = models.CharField(max_length=100)
code = models.CharField(max_length=30)
While adding a new address in django admin, I want to show the list of only those states which belong to the selected country i.e I want to implement something like dependent foreign key list in django-admin.
I would like to achieve it without using jquery or ajax
How can I do that?
I have a Place Model:
class Place(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
country = models.CharField(max_length=100, null=True, blank=True)
postal_code = models.CharField(max_length=100, null=True, blank=True)
region = models.CharField(max_length=1000, choices=REGION, null=True, blank=True)
longitude = models.CharField(max_length=20, null=True, blank=True)
latitude = models.CharField(max_length=20, null=True, blank=True)
date_created = models.DateTimeField(_('date created'), default=timezone.now)
date_modified = models.DateTimeField(_('date_modified'), auto_now=True)
Originally I create place to save information about a city, like San Francisco or New York.
Now I want to create a new model called Bar:
class Bar(Place):
location = models.OneToOneField(Place, verbose_name=_('location'), related_name='bar', blank=True, on_delete=models.PROTECT, parent_link=True)
date_inception = models.DateField(null=True, blank=True)
date_closed = models.DateField(null=True, blank=True)
I would like to link the bar to a particular city in the Place model. So I'm linking one row of the an inherited model with its parent. Can I avoid creating a city model and the Bar should Foreignkey into? Is this doable? If so, how do I do it?
When you set parent_link=True in your OneToOneField, the joined models are treated as the same model when working with the ORM, even though they are two separate database tables.
There is no need to link Bar to a particular Place; you can use the Bar model to create both the Bar instance and the Place instance at the same time:
bar = Bar.objects.create(name='Blackbird', city='San Fransisco',
country='US', date_inception='10-17-2019', ...
)
Based on your comments, I'm guessing you don't want this at all. Instead, you probably want a ForeignKey relationship between Place and the Bar model, since a place (eg San Fransisco) can have many bars, but a bar can only have one place.
Update
From my understanding of your comments, this is what I would suggest:
class PlaceMixin(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
longitude = models.CharField(max_length=20, null=True, blank=True)
latitude = models.CharField(max_length=20, null=True, blank=True)
class Meta:
abstract = True
def save(self, *args, **kwargs):
latitude = self.latitude
longitude = self.longitude
do_stuff(latitude, longitude)
super().save()
class Location(PlaceMixin):
country = models.CharField(max_length=100, null=True, blank=True)
postal_code = models.CharField(max_length=100, null=True, blank=True)
region = models.CharField(max_length=1000, choices=REGION, null=True, blank=True)
class Bar(PlaceMixin):
location = models.ForeignKey(Location, related_name='bars', on_delete=models.CASCADE)
class Store(PlaceMixin):
location = models.ForeignKey(Location, related_name='stores', on_delete=models.CASCADE)
Now you can access both the lat/long of the Place, and of the Location:
>>>location = Location.objects.create(name='San Fransisco', latitude=1, longitude=1)
>>>bar = Bar.objects.create(name='Blackbird', latitude=2, longitude=2, location=location)
>>>
>>>bar.latitude
2
>>>bar.location.latitude
1
To query all bars in San Fransisco:
location = Location.objects.select_related('Bar').get(name='San Fransisco')
bars = location.bars.all()
I am trying to learn django by creating a blog on my own, and I've tried some real simple steps before, but now I want to make something slightly more complex. Currently, I am thinking of dividing the blogs' 'Stories' into 'Blocks'. My idea is to have two child classes 'TextBlock' and 'ImageBlock', and my current models look like this.
class Story(models.Model):
writer = models.CharField(max_length=189)
title = models.CharField(max_length=189)
class Block(models.Model):
story = models.ForeignKey(Story, related_name='+', on_delete=models.CASCADE)
block = EnumField(choices=[
('TXT', "text"),
('IMG', "image"),
])
serial = models.IntegerField(default=0)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
class TextBlock(Block):
type = models.CharField(max_length=128, blank=True, null=True, default='paragraph')
content = models.TextField(blank=True, null=True)
class ImageBlock(Block):
src = models.URLField()
type = models.CharField(max_length=128, blank=True, null=True, default='full')
title = models.CharField(max_length=189, blank=True, null=True)
photographer = models.CharField(max_length=128, blank=True, null=True)
What I'd like to do now is to create blog entries from the django admin interface. Is it possible to create both types from the main Block? Or do I need to go to both TextBlock and ImageBlock? Any ideas on how I should proceed from here? Thanks.