Do DocumentChooserBlocks have to have foreign key? - django-models

I am using a Wagtail streamfield to allow users to upload and link to documents in the editor interface. Originally, I tried to use a foreign key as referenced in the documentation and as all other examples I have seen. I kept getting an error when running migrations that wagtail document has not property "set name". So I decided to not use a foreign key because these documents do not necessarily need to be related on a one-to-many relationship for our purposes. So in my model, I do not use a foreign key for all the fields using DocumentChooserBlocks and everything seems to work fine. Am I misunderstanding "foreign key" and making a mistake(or practicing bad DB design). Here is my working model for this:
class AgendaPage(Page):
author= models.CharField(max_length=255)
date = models.DateField('Post date')
mtg_date = models.DateField(default=datetime.date.today)
mtg_time = models.CharField(max_length=255, default ='10:00 AM')
full_video_url-models.CharField(required =False)
###full_audio = DocumentChooserBlock(required=False)
###mtg_transcript = DocumentChooserBlock(required=False)
])
agenda = StreamField([
('agenda_item', blocks.StreamBlock([
('item_title', blocks.TextBlock()),
('item_text', blocks.TextBlock()),
('mtg_doc', blocks.StructBlock([
('mtg_doc_upload', DocumentChooserBlock(required=True)),
('submitted_late', blocks.BooleanBlock(required=False, help_text='Submitted Late')),
('heldover', blocks.BooleanBlock(required=False, help_text='Held Over')),
('heldover_from', blocks.DateBlock(required=False, help_text="Held Over From")),
])),
('item_audio', DocumentChooserBlock(required=False)),
]))
])
content_panels = Page.content_panels + [
FieldPanel('author'),
FieldPanel('date'),
FieldPanel('mtg_date'),
FieldPanel('mtg_time'),
StreamFieldPanel('agenda'),
]
Also, in the two commented-out lines in the model, I am trying to have a DocumentChooserBlock that is not inside a streamfield(without foreign key) I know this syntax is likely wrong, as all examples I see, define a forein key in the model definition, and then reference a DocumentChooser Panel in the panels definition. Is it is possible(or advisable) to do it without foreign key?

DocumentChooserBlock is never used with a foreign key. There are two distinct methods of attaching documents to pages, and you choose one or the other:
A ForeignKey to Document, with a DocumentChooserPanel in content_panels. This would be used when you have a one-to-one or many-to-one relation from pages to documents; for example, a ProductPage where a product has a PDF data sheet. This creates a formal link between the two objects at the database level.
A StreamField with a DocumentChooserBlock in it. This is used for more flexible arrangements, where the document link can appear at any position down a page. There's no formal association at the database level - from the database's point of view, a StreamField is just free text. This means there's no need for a ForeignKey.

Related

which particular field of the model is referred under the foreign key in django's orm?

i have two classes 'topics' and 'webpage' and i'm trying to assign webpage.category as a foreign key referencing to topics.top_name.
But unlike raw sql where a foreign key can reference to a particular field in another table, in django's orm we just provide the referenced class'(table's) name and not the particular field the FK is referrring to.
class Topic(models.Model):
top_name = models.CharField(max_length=264, unique=True)
top_author = models.CharField(max_length=264)
class Webpage(models.Model):
category = models.ForeignKey(Topic)
name = models.CharField(max_length=264)
url = models.URLField()
You can set the to_field=… [Django-doc] in the ForeignKey constructor:
class Topic(models.Model):
top_name = models.CharField(max_length=264, unique=True)
top_author = models.CharField(max_length=264)
class Webpage(models.Model):
category = models.ForeignKey(Topic, to_field='top_name', on_delete=models.CASCADE)
name = models.CharField(max_length=264)
url = models.URLField()
As specified in the documentation, the field to which you refer should be unique (which of course makes sense, since otherwise, it would be ambiguous).
Note that usually, the collation [mysql-doc] of the referencing column and the target column should be the same. Otherwise it is not completely clear when the two fields are equal.
If you do not specify the to_field, it will use the primary key of the target model.

How NamespaceManager and Query by key works together in objectify

I have two organisation in my datastore inside their own namespace. Lets say organisation1 present inside namespace1 and organisation2 present inside namespace2. I am retrieving organisation by its web-safe-key. lets say that web-safe-key of organisation1 is orgWebSafeKey1 and web-safe-key of organisation2 is orgWebSafeKey2. I am using following code to get an organisation:
NamespaceManager.set("namespace1");
Organisation organisation = (Organisation) ofy().load().key(Key.create(orgWebSafeKey1)).now();
above code works as I expected because organisation1 is present inside namespace1 and I am trying get that organisation in its namespace.
But if I just change the websafekey of the organisation then according to my expectaion below query should result "null" organisation because there is no organisation with key orgWebSafeKey2 inside namespace1. But practically it is giving me organisation2.
NamespaceManager.set("namespace1");
Organisation organisation = (Organisation) ofy().load().key(Key.create(orgWebSafeKey2)).now();
If the above query result is correct and expected according to objectify and datastore then can I assume that query by key works globally , across all the namespaces?
I also want confirmation that in this case Key.create(orgWebSafeKey2) will not change the namespace of the key? and query is running according to the namespace of the key not by NamespaceManager.set("namespace1")?
A Datastore Key contains the following components:
Project/App ID
Namespace
Entity Path (Ancestor Kind + ID/Name(zero or more), Final Entity Kind + ID/Name)
Since namespace is part of the key, lookup of an entity by Key always finds the right entity regardless of the namespace set by the NamespaceManager. In other words, a Key is a GUID that uniquely identifies an entity across all apps/projects.
Refer to the below link for more details/answers for your questions:
https://cloud.google.com/appengine/docs/java/multitenancy/multitenancy#Java_Using_namespaces_with_the_Datastore

django Charfield suitable for a primary key?

In my django model I would like to set the field unique_id below to be the primary key as this will be the field used in queries for the model. It satisfies unique=True and null=False. However as django sets an AutoField to primary key in the background I'm unsure whether a CharField (which uses a unique 3 character code) is suitable as a primary key or whether this will be sub-optimal?
class PaymentMethod(models.Model):
unique_id = models.CharField(max_length=3)
last_updated = models.DateTimeField(auto_now=True)
There is nothing wrong with setting the CharField to be a primary key, by changing the model to be:
class PaymentMethod(models.Model):
unique_id = models.CharField(max_length=3, primary_key=True)
last_updated = models.DateTimeField(auto_now=True)
In actual fact if the unique_id is the field you will be querying it makes perfect sense to use it. Your other options are to use your existing model but with unique=True:
class PaymentMethod(models.Model):
unique_id = models.CharField(max_length=3, unique=True)
last_updated = models.DateTimeField(auto_now=True)
In this case your primary key will be an auto incrementing integer as you previously stated.
Another option depending on the number of records you are looking to store in the PaymentMethod models; and where the data is used elsewhere within your application. Is too look into using a model choices field. The model choices field might be on your payments or order model (depends on your application and what you are trying to do). This removes the need for a foreignkey and potentially reduces the number of queries in your app.
It could look something like this:
class Payment(models.Model):
VISA = 'VIS'
CREDIT = 'CRE'
MASTER_CARD = 'MAS'
PAYPAL = 'PAL'
PAYMENT_OPTIONS= (
(VISA, 'Visa'),
(CREDIT, 'Credit Card'),
(MASTER_CARD, 'Master Card'),
(PAYPAL, 'Paypal')
)
items = models.ForeignKey(Item)
date = models.DateField(auto_now=True)
...
payment_method = models.CharField(max_length=3, choices=PAYMENT_OPTIONS, default=VISA)
The PAYMENT_OPTIONS can be used to render dropdown boxes on the forms when using django model forms. Otherwise the users selection is limited to the options listed within this model.
This method would be a lot more efficient if you only have a small subset of PaymentMethod(s).
It's possible to use CharField as primary key. You just have to mark the field as primary key.
field_name = models.CharField(primary_key=True, max_length=100)
But I wouldn't recommend it because:
Primary keys are used in urls (typically in Rest APIs) - but not all characters are allowed in urls
DRF (django-rest-framework) use urls patterns that don't catch some characters by default (for example ".")
Primary keys must be unique - it's harder to accomplish it if the field is a string, especially when you let users to define it

Retrieving data from referenced key table - Laravel-4

The structure of concerning tables is as follows (MySQL):
//Table Name : team
tid PK
team_name (varchar)
//Table Name : fixture
fid PK
home_team_id FK |_ both referenced to 'tid' from 'team' table
away_team_id FK |
My aim is to retrieve the team names. Considering this structure, I think I'll have to retrieve home_team_id and away_team_id and then do something like
Fixture::where('tid','=',$home_team_id)->get();
My question is, is this the correct way to accomplish what I aim to do?
and
should this be done from the controller? (if so, then I'll have to do two queries from same function)
First, rather than having your primary keys be tid and fid, just keep them both as id. This is not only best practice, but will allow you to more easily use Laravel's Eloquent ORM as it by default assumes your primary key column is named id.
Second thing, make sure your table names are in plural form. Although this is not necessary, the example I'm about to give is using Laravel defaults, and Laravel assumes they are in plural form.
Anyway, once you've 'Laravelized' your database, you can use an Eloquent model to setup awesome relationships with very minimal work. Here's what I think you'd want to do.
app/models/Team.php
class Team extends Eloquent {
// Yes, this can be empty. It just needs to be declared.
}
app/models/Fixture.php
class Fixture extends Eloquent {
public function homeTeam()
{
return $this->belongsTo('Team', 'home_team_id');
}
public function awayTeam()
{
return $this->belongsTo('Team', 'away_team_id');
}
}
Above, we created a simple model Team which Laravel will automatically look for in the teams database table.
Second, we created model Fixture which again, Laravel will use the fixtures table for. In this model, we specified two relationships. The belongsTo relationship takes two parameters, what model it is related to, in both cases here they are teams, and what the column name is.
Laravel will automatically take the value in away_team_id and search it against the id column in your teams table.
With just this minimal amount of code, you can then do things like this.
$fixture = Fixture::find(1); // Retrieves the fixture with and id of 1.
$awayTeam = $fixture->awayTeam()->first(); // var_dump this to see what you get.
$homeTeam = $fixutre->homeTeam()->first();
Then you can proceed as normal and access the column names for the tables. So say you have a 'name' column in the teams table. You can echo out the the home team name from the fixture like so.
$fixture = Fixture::find(1); // Get the fixture.
echo $fixture->homeTeam->name;
It's nearly 2AM, so there might be an error or two above, but it should work.
Make sure you check the docs for Eloquent, especially the bits relating to relationships. Remember to name your columns and tables in the way Laravel wants you to. If you don't, there are ways to specify your custom names.
If you want to get even more fancy, you can define the inverse relationship like this on your Team model.
app/models/Team.php
class Team extends Eloquent {
public function fixturesAtHome()
{
return $this->hasMany('Fixture', 'home_team_id');
}
public function fixturesAway()
{
return $this->hasMany('Fixture', 'away_team_id');
}
}
Then to get all of a particular team's home fixtures...
$team = Team::find(1); // Retreive team with id of 1;
$homeFixtures = $team->fixturesAtHome();

Django Model ValueError

I'm accessing emails in my email server, taking the body of each email and then applying regular expressions to find the data necessary to populate my Django model.
This all works fine except for one field, which is linked as a foreign key to another model field. Despite the value in my email being the same as the one in listed in my other model, it fails....
The error:
ValueError: Cannot assign "'Humanities'": "Subject.faculty" must be a "Faculty" instance.
For example, say each school subject has to be part of a faculty. When populating the database via a form, for the Subject's faculty field I drop down the menu to a list of faculty values/instances as there is a foreign key relationship defined in my model i.e. for the faculty field I can choose from Humanities, Art, Design Technology etc.
But when I find the value 'Humanities' in my email and try to add it to the database model, I get the error above.
Anyone shed any light on this? Am I being stupid or is it more than a ValueError as to me, the values are the same in both cases
Thank you
More code as requested:
class Faculty(models.Model):
name = models.CharField(primary_key=True, max_length=50)
leader = models.CharField(max_length=50)
email = models.EmailField()
mailing_list = models.ManyToManyField("Contact", null=True)
class Subject(models.Model):
name = models.CharField(max_length=50)
faculty = models.ForeignKey(Faculty, to_field="name")
faculty_head = models.CharField(max_length=50)
It sounds like you are trying to assign a string "Humantities" to a ForeignKey relationship. This doesn't make sense. You need to either find or create the actual Faculty object with the name "Humanities" and assign it to the Subject. Something like this in your view (depending on how your form is set up):
if form.is_valid():
faculty_str = form.cleaned_data['faculty']
(faculty, was_created) = Faculty.objects.get_or_create(name=faculty_str, ...)
# It's hard to tell if you are using a ModelForm or just a normal Form. Anyway, assume we already have access to the Subject object
subject.faculty = faculty
subject.save()
get_or_create()
Your value is 'Humanities' perhaps you mean to search for Humanities (without quotes).
You need to create a Faculty instance first.
faculty = Faculty(name='', leader='', email='')
faculty.save()
subject.faculty = faculty
subject.save()

Resources