*I'm trying to figure out how to populate fields in my model based on previous field selection.
For example, if FIELD_CHOICES = 3
Create 3x TextField()
class Post(models.Model):
STATUS_CHOICES = (('published','Published'),
('draft','Draft '))
FIELD_CHOICES = (('1','1 Title and body field'),
('2','2 Title and body fields'),
('3','3 Title and body fields'),
('4', '4 Title and body fields'),
('5', '5 Title and body fields'))
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='blog_post')
title = models.CharField(max_length=100)
sub_title = models.TextField(max_length=50,default="")
title_and_body_fields = models.IntegerField(choices=FIELD_CHOICES,
default=1)
**/// create number of title and body Textfields based on what was
/// selected in title_and_body_fields**
created = models.DateField()
publish = models.DateTimeField(default=timezone.now)
slug = models.SlugField(max_length=250,
unique_for_date='created')
status = models.CharField(max_length=250,
choices=STATUS_CHOICES,
default='draft')
object = models.Manager()
postManager = PostManager()
class Meta():
ordering = ('publish',)
def __strd__(self):
return self.title
def get_absolute_url(self):
return reverse('my_blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.publish.day,
self.slug])
In the end i decided to do the following.
I added 5 seperate TextFields for Title and Body and added blank=True
title_5 = models.CharField(max_length=100,null=True,blank=True)
title_5_body = models.TextField(null=True,blank=True)
I'm afraid this is not possible.
I think you misunderstand how Models work. Have a look at the Django docs for models here.
Basically the way Django saves your models, is through an ORM (Object-Relational-Mapping).
This means that the model you write, with the fields contained within it, are transformed into a database query, generating a table.
In the docs for models, you can see this piece of code:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
is transformed to this SQL query:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
This means that Django, under the hood, creates database tables for each Model you have in your app.
So how does work in Django?
Well, these SQL statements are generated when you run python manage.py makemigrations. The actual tables are created when you run python manage.py migrate.
This means that you only run these commands once (For every change to your model), and there will be only one table created for your model.
So why can't I add extra TextFields to an object?
This is because for each model there is only one table in the database, and your model would be stored like this:
id | first_name | last_name
----------------------------------
1 | John | Doe
2 | Jane | Doe
... | ... | ...
If you were to add an extra field (for instance phone_number) to John Doe, you'd need to add that field to the entire table.
So in your case, your choice is between no extra body and title fields, or a set amount extra fields for each object.
Ok, what now?
Well, there are a few ways to do this. Your best bet would be to create a ManyToMany relationship to a Model called something like PostBody, which would allow you to create an arbitrary amount of bodies for a set post.
You could modify the save method of you Post model to automatically create a set amount of PostBody objects for that object.
You can read read more about ManyToManyField here.
Related
In Django there is a method get_or_create guaranteeing the uniqueness of the object. But when records for adding a lot more 1000 processing takes a lot of time (as 1000 requests for the creation of objects). I know about bulk_create, but it does not check on the uniqueness of the input attributes of the model. How do I speed up the addition of unique objects to the database? If possible in 1 request.
Example model:
models.py
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
admin.py
# Create only one element (What I want to get)
_, created = Person.objects.get_or_create(first_name='Leon', last_name='Mariano')
_, created = Person.objects.get_or_create(first_name='Leon', last_name='Mariano')
# Create 2 objects with different ID
Person.objects.bulk_create(Person(first_name='Leon', last_name='Mariano'),
Person(first_name='Leon', last_name='Mariano'))
Thanks to Ivan for the help. The solution is:
models.py
from django.db.models import UniqueConstraint
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Meta:
constraints = [
UniqueConstraint(fields=['first_name', 'last_name'], name='unique person')
]
admin.py
Person.objects.bulk_create((
Person(first_name='fname', last_name='lname'),
Person(first_name='fname', last_name='lname'),
Person(first_name='fname2', last_name='lname2'),
), ignore_conflicts= True)
I am trying to write a query that returns Vehicle objects. The query should filter by a particular Garage object (i.e., garage__name = ) and by a particular Category object (i.e., category__name = ), and where the Vehicle object's available field is True (available = True). These are the models:
class Garage(models.Model):
name = models.CharField (max_length = 30, blank=False)
zip = models.IntegerField (blank=False)
area = models.CharField (max_length = 30, blank=False)
pic = models.ImageField (upload_to ='static/images/garages')
class Vehicle(models.Model):
car_no = models.CharField (max_length = 20, blank=False)
photo = models.ImageField (upload_to ='static/images/vehicles')
car_model = models.ForeignKey (Car_model, on_delete=models.CASCADE)
garage = models.ForeignKey (Garage, on_delete=models.CASCADE)
category = models.ForeignKey (Category, on_delete=models.CASCADE)
available = models.BooleanField(default=True)
class Category(models.Model):
name = models.CharField (max_length = 15, blank=False)
What I've tried in the corresponding view function is this:
def carSelectView(request, type, grg):
cars=Vehicle.objects.filter(category__name=type, garage__name=grg, available=True)
return render(request, 'carphotoselectpage.html', {'ca':cars})
But it's returning an empty page. Before this approach, i tried to get the cars of a particular category only and it worked:
def carSelectView(request, type):
cars = Vehicle.objects.filter(category__name = type).filter(available=True)
I can't understand where the problem lies. I want to show vehicles by 1. selecting a particular Garage, and then 2. selecting the vehicles from that Garage that matches the Category name. 3. Whose available field is True.
Is the Vehicle model not fetching the Garage model in the query?
Your code looks fine, so this is likely a problem with what's being passed in the type and grg variables rather than a problem with your query.
To debug, try the following:
Use print() commands to output the values stored within the type and grg variables to your terminal. Check to ensure that they are as expected.
User $ python manage.py shell to boot up your terminal, then manually run your query to ensure that it returns the expected output. from .models import Vehicle, then Vehicle.objects.filter(category__name='REAL CATEGORY', garage__name='REAL GARAGE', available=True). Ensure that you get results back. if you don't, try removing criteria one by one until you can isolate the source of the problem.
Ensure that your template properly displays Car instances when provided with them. Try passing it an instance of a Car that you know exists (e.g., Car.objects.all()) and make sure that it is displaying proper output.
I have a situation where I need to do something similar to rendering a formset within a formset. But I'd rather focus on the problem before jumping to a solution.
In English first:
I'm creating a shipment from a warehouse.
Each shipment can contain multiple lines (unique combinations of product_type and package_type) with an item_count
However for each line there could be multiple "Packages" - a package_type of a product_type that has an item_count. Think of this as a batch.
The customer is only interested in seeing one line for each product_type/package_type
But we need to pull out the stock and correctly attribute the particular units from each batch to allow stock control, recall control etc to function. Therefore the dispatch staff IS interested in exactly which Packages are shipped.
Add to this the sales staff enter a SalesOrder that only specifies the product_type/package_type. They aren't interested in the Packages either. (Think putting in a forward order for next month - who knows what will be in stock then?).
Now the models (simplified for clarity):
class Package(models.Model):
create_date = models.DateField()
quantity = models.FloatField()
package_type = models.ForeignKey(PackageType, on_delete=models.PROTECT)
product_type = models.ForeignKey(ProductType, on_delete=models.PROTECT)
class CheckOut(models.Model):
package = models.ForeignKey(Package, on_delete=models.PROTECT)
create_date = models.DateField()
quantity = models.FloatField()
class Shipment(models.Model):
sales_order = models.ForeignKey(SalesOrder, null=True, blank=True)
ship_date = models.DateField(default=date.today,
verbose_name='Ship Date')
class ShipmentLine(models.Model):
shipment = models.ForeignKey(Shipment, null=True, blank=True)
sales_order_line = models.ForeignKey(SalesOrderLine, null=True, blank=True)
quantity = models.FloatField(verbose_name='Quantity Shipped')
checkout = models.ManytoManyField(CheckOut)
I currently have it working well with the constraint of a 1:M relationship of CheckOut:ShipmentLine. However when changing this to a M:M, things get knarly form-wise.
In the 1:M version the Shipment form (plus formset for the ShipmentLines) looks like this:
class CreateShipmentForm(forms.ModelForm):
class Meta:
model = om.Shipment
contact = forms.ModelChoiceField(
queryset=om.Contact.objects.filter(is_customer=True, active=True),
label='Customer')
customer_ref = forms.CharField(required=False, label='Customer Reference')
sales_order = forms.ModelChoiceField(queryset=om.SalesOrder.objects.all(),
required=False, widget=forms.HiddenInput())
number = forms.CharField(label='Shipment Number', required=False,
widget=forms.TextInput(attrs={'readonly': 'readonly'}))
class CreateShipmentLineForm(forms.ModelForm):
class Meta:
model = om.ShipmentLine
widgets = {
'checkout': forms.HiddenInput()
}
fields = ('package', 'quantity', 'id',
'sales_order_line', 'checkout')
id = forms.IntegerField(widget=forms.HiddenInput())
sales_order_line = forms.ModelChoiceField(
widget=forms.HiddenInput(), required=False,
queryset=om.SalesOrderLine.objects.all())
package = forms.ModelChoiceField(required=True, queryset=None) # queryset populated in __init__, removed for brevity
So for the 1:M, I could select a package, set the quantity and done.
For M:M, I will need to select product_type, package_type, and then 1 or more packages, AND for each package a quantity. (I'll be using JS in the form to filter these)
In my mind's eye I have a few possibilities:
create a (child) formset for the Packages and quantities and include in each line of the (parent) formset
create some sort of multi-field, multi-value matrix custom form field and use that
construct a modal dialog where the M:M stuff happens and somehow save the result to the form where validation, saving happens.
I hope I have explained it correctly and clearly enough. It's the most complex application of Django forms I've encountered and I'm not sure what the limitations/pros/cons of each of my options is.
Has anyone encountered this situation and have a solution? Or any words to the wise?
My thanks in advance,
Nathan
I have a similar situation, I am doing something like your second and third options:
I have overridden __init__() and, after calling super, I have a loop that adds a value selector for every field (of course you could use a single custom element here)
Then override save() and after calling super I process the extra field adding all the values.
Let's say I have these:
class Publication(models.Model):
title = models.CharField(max_length=128)
author = models.ManyToManyField(Author, through='Authorship')
class Author(models.Model):
first_name = models.CharField(db_index=True, max_length=64)
last_name = models.CharField(db_index=True, max_length=64)
How can I get ALL the publications AND their author(s) in one query. I want to list each publication and its authors on a page.
But I don't want to hit the authors table for every publication.
The only way I know to do it is with select_related in the view and authorship_set.all() on the template. But that's one query for every publication. I could easily do it with raw sql, but that's yucky.
*BTW, I'm using the through model because I have to keep some extra data in there, like author_display_order.
EDIT:
Turns out authorship_set was doing all the querying.
When I run it this way from console only one query gets fired:
pubs = Publication.objects.all().prefetch_related('author')
for p in pubs:
print p.title
for a in p.author.all():
print a.last_name
I imported my (PHP) old site's database tables into Django. By default it created a bunch of primary key fields within the model (since most of them were called things like news_id instead of id).
I just renamed all the primary keys to id and removed the fields from the model. The problem then came specifically with my News model. New stuff that I add doesn't appear in the admin. When I remove the following line from my ModelAdmin, they show up:
list_display = ['headline_text', 'news_category', 'date_posted', 'is_sticky']
Specifically, it's the news_category field that causes problems. If I remove it from that list then I see my new objects. Now, when I edit those items directly (hacking the URL with the item ID) they have a valid category, likewise in the database. Here's the model definitions:
class NewsCategory(models.Model):
def __unicode__(self):
return self.cat_name
#news_category_id = models.IntegerField(primary_key=True, editable=False)
cat_name = models.CharField('Category name', max_length=75)
cat_link = models.SlugField('Category name URL slug', max_length=75, blank=True, help_text='Used in URLs, eg spb.com/news/this-is-the-url-slug/ - generated automatically by default')
class Meta:
db_table = u'news_categories'
ordering = ["cat_name"]
verbose_name_plural = "News categories"
class News(models.Model):
def __unicode__(self):
return self.headline_text
#news_id = models.IntegerField(primary_key=True, editable=False)
news_category = models.ForeignKey('NewsCategory')
writer = models.ForeignKey(Writer) # todo - automate
headline_text = models.CharField(max_length=75)
headline_link = models.SlugField('Headline URL slug', max_length=75, blank=True, help_text='Used in URLs, eg spb.com/news/this-is-the-url-slug/ - generated automatically by default')
body = models.TextField()
extra = models.TextField(blank=True)
date_posted = models.DateTimeField(auto_now_add=True)
is_sticky = models.BooleanField('Is this story featured on the homepage?', blank=True)
tags = TaggableManager(blank=True)
class Meta:
db_table = u'news'
verbose_name_plural = "News"
You can see where I've commented out the autogenerated primary key fields.
It seems like somehow Django thinks my new items don't have news_category_ids, but they definitely do. I tried editing an existing piece of news and changing the category and it worked as normal. If I run a search for one of the new items, it doesn't show up, but the bottom of the search says "1 News found", so something is going on.
Any tips gratefully received.
EDIT: here's my ModelAdmin too:
class NewsCategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {"cat_link": ("cat_name",)}
list_display = ['cat_name', '_cat_count']
def _cat_count(self, obj):
return obj.news_set.count()
_cat_count.short_description = "Number of news stories"
class NewsImageInline(admin.TabularInline):
model = NewsImage
extra = 1
class NewsAdmin(admin.ModelAdmin):
prepopulated_fields = {"headline_link": ("headline_text",)}
list_display = ['headline_text', 'news_category', 'date_posted', 'is_sticky'] #breaking line
list_filter = ['news_category', 'date_posted', 'is_sticky']
search_fields = ['headline_text']
inlines = [NewsImageInline]
The answer you are looking for I think would lie in the SQL schema that you altered and not in the django models.
It could probably have something to do with null or blank values in the news_category_id, or news that belongs to a category that doesn't exist in the news_category. Things I'd check:
You have renamed the primary key on the News category from news_category_id to id. Does the foreign key on the News also map to news_category_id and not anything else?
Are all the values captured in the news.news_category also present in news_category.id
Also, as an aside, I don't see any reason why you need to rename the primary keys to id from something that they already are. Just marking them primary_key=True works just fine. Django provides you a convenient alias pk to access a model's integer primary key, irrespective of what the name of the field actually is.